diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/me4000.c')
-rw-r--r-- | drivers/staging/comedi/drivers/me4000.c | 1636 |
1 files changed, 618 insertions, 1018 deletions
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 9a8258e6fa45..22db35d091f8 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -35,13 +35,7 @@ Supports: - Digital I/O - Counter -Configuration Options: - - [0] - PCI bus number (optional) - [1] - PCI slot number (optional) - - If bus/slot is not specified, the first available PCI - device will be used. +Configuration Options: not applicable, uses PCI auto config The firmware required by these boards is available in the comedi_nonfree_firmware tarball available from @@ -58,51 +52,306 @@ broken. #include <linux/list.h> #include <linux/spinlock.h> -#include "me4000.h" +#include "comedi_fc.h" +#include "8253.h" + #if 0 /* file removed due to GPL incompatibility */ #include "me4000_fw.h" #endif -static const struct me4000_board me4000_boards[] = { - {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} }, - - {"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3} }, - {"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3} }, - {"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3} }, - {"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3} }, - - {"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3} }, - {"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3} }, +#define PCI_VENDOR_ID_MEILHAUS 0x1402 + +#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 +#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 +#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 +#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 +#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 +#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 +#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 +#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 +#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 +#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 +#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 +#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 +#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 - {"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3} }, - {"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3} }, +/* + * ME4000 Register map and bit defines + */ +#define ME4000_AO_CHAN(x) ((x) * 0x18) + +#define ME4000_AO_CTRL_REG(x) (0x00 + ME4000_AO_CHAN(x)) +#define ME4000_AO_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_AO_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_AO_CTRL_MASK_MODE (3 << 0) +#define ME4000_AO_CTRL_BIT_STOP (1 << 2) +#define ME4000_AO_CTRL_BIT_ENABLE_FIFO (1 << 3) +#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG (1 << 4) +#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE (1 << 5) +#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP (1 << 7) +#define ME4000_AO_CTRL_BIT_ENABLE_DO (1 << 8) +#define ME4000_AO_CTRL_BIT_ENABLE_IRQ (1 << 9) +#define ME4000_AO_CTRL_BIT_RESET_IRQ (1 << 10) +#define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x)) +#define ME4000_AO_STATUS_BIT_FSM (1 << 0) +#define ME4000_AO_STATUS_BIT_FF (1 << 1) +#define ME4000_AO_STATUS_BIT_HF (1 << 2) +#define ME4000_AO_STATUS_BIT_EF (1 << 3) +#define ME4000_AO_FIFO_REG(x) (0x08 + ME4000_AO_CHAN(x)) +#define ME4000_AO_SINGLE_REG(x) (0x0c + ME4000_AO_CHAN(x)) +#define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x)) +#define ME4000_AI_CTRL_REG 0x74 +#define ME4000_AI_STATUS_REG 0x74 +#define ME4000_AI_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_AI_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_AI_CTRL_BIT_MODE_2 (1 << 2) +#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD (1 << 3) +#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP (1 << 4) +#define ME4000_AI_CTRL_BIT_STOP (1 << 5) +#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO (1 << 6) +#define ME4000_AI_CTRL_BIT_DATA_FIFO (1 << 7) +#define ME4000_AI_CTRL_BIT_FULLSCALE (1 << 8) +#define ME4000_AI_CTRL_BIT_OFFSET (1 << 9) +#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG (1 << 10) +#define ME4000_AI_CTRL_BIT_EX_TRIG (1 << 11) +#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING (1 << 12) +#define ME4000_AI_CTRL_BIT_EX_IRQ (1 << 13) +#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET (1 << 14) +#define ME4000_AI_CTRL_BIT_LE_IRQ (1 << 15) +#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET (1 << 16) +#define ME4000_AI_CTRL_BIT_HF_IRQ (1 << 17) +#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET (1 << 18) +#define ME4000_AI_CTRL_BIT_SC_IRQ (1 << 19) +#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET (1 << 20) +#define ME4000_AI_CTRL_BIT_SC_RELOAD (1 << 21) +#define ME4000_AI_STATUS_BIT_EF_CHANNEL (1 << 22) +#define ME4000_AI_STATUS_BIT_HF_CHANNEL (1 << 23) +#define ME4000_AI_STATUS_BIT_FF_CHANNEL (1 << 24) +#define ME4000_AI_STATUS_BIT_EF_DATA (1 << 25) +#define ME4000_AI_STATUS_BIT_HF_DATA (1 << 26) +#define ME4000_AI_STATUS_BIT_FF_DATA (1 << 27) +#define ME4000_AI_STATUS_BIT_LE (1 << 28) +#define ME4000_AI_STATUS_BIT_FSM (1 << 29) +#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) +#define ME4000_AI_CHANNEL_LIST_REG 0x78 +#define ME4000_AI_LIST_INPUT_SINGLE_ENDED (0 << 5) +#define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5) +#define ME4000_AI_LIST_RANGE_BIPOLAR_10 (0 << 6) +#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 (1 << 6) +#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 (2 << 6) +#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 (3 << 6) +#define ME4000_AI_LIST_LAST_ENTRY (1 << 8) +#define ME4000_AI_DATA_REG 0x7c +#define ME4000_AI_CHAN_TIMER_REG 0x80 +#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 +#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 +#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8c +#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 +#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 +#define ME4000_AI_START_REG 0x98 +#define ME4000_IRQ_STATUS_REG 0x9c +#define ME4000_IRQ_STATUS_BIT_EX (1 << 0) +#define ME4000_IRQ_STATUS_BIT_LE (1 << 1) +#define ME4000_IRQ_STATUS_BIT_AI_HF (1 << 2) +#define ME4000_IRQ_STATUS_BIT_AO_0_HF (1 << 3) +#define ME4000_IRQ_STATUS_BIT_AO_1_HF (1 << 4) +#define ME4000_IRQ_STATUS_BIT_AO_2_HF (1 << 5) +#define ME4000_IRQ_STATUS_BIT_AO_3_HF (1 << 6) +#define ME4000_IRQ_STATUS_BIT_SC (1 << 7) +#define ME4000_DIO_PORT_0_REG 0xa0 +#define ME4000_DIO_PORT_1_REG 0xa4 +#define ME4000_DIO_PORT_2_REG 0xa8 +#define ME4000_DIO_PORT_3_REG 0xac +#define ME4000_DIO_DIR_REG 0xb0 +#define ME4000_AO_LOADSETREG_XX 0xb4 +#define ME4000_DIO_CTRL_REG 0xb8 +#define ME4000_DIO_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_DIO_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_DIO_CTRL_BIT_MODE_2 (1 << 2) +#define ME4000_DIO_CTRL_BIT_MODE_3 (1 << 3) +#define ME4000_DIO_CTRL_BIT_MODE_4 (1 << 4) +#define ME4000_DIO_CTRL_BIT_MODE_5 (1 << 5) +#define ME4000_DIO_CTRL_BIT_MODE_6 (1 << 6) +#define ME4000_DIO_CTRL_BIT_MODE_7 (1 << 7) +#define ME4000_DIO_CTRL_BIT_FUNCTION_0 (1 << 8) +#define ME4000_DIO_CTRL_BIT_FUNCTION_1 (1 << 9) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 (1 << 10) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 (1 << 11) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 (1 << 12) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 (1 << 13) +#define ME4000_AO_DEMUX_ADJUST_REG 0xbc +#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c +#define ME4000_AI_SAMPLE_COUNTER_REG 0xc0 - {0}, +/* + * PLX Register map and bit defines + */ +#define PLX_INTCSR 0x4c +#define PLX_INTCSR_LOCAL_INT1_EN (1 << 0) +#define PLX_INTCSR_LOCAL_INT1_POL (1 << 1) +#define PLX_INTCSR_LOCAL_INT1_STATE (1 << 2) +#define PLX_INTCSR_LOCAL_INT2_EN (1 << 3) +#define PLX_INTCSR_LOCAL_INT2_POL (1 << 4) +#define PLX_INTCSR_LOCAL_INT2_STATE (1 << 5) +#define PLX_INTCSR_PCI_INT_EN (1 << 6) +#define PLX_INTCSR_SOFT_INT (1 << 7) +#define PLX_ICR 0x50 +#define PLX_ICR_BIT_EEPROM_CLOCK_SET (1 << 24) +#define PLX_ICR_BIT_EEPROM_CHIP_SELECT (1 << 25) +#define PLX_ICR_BIT_EEPROM_WRITE (1 << 26) +#define PLX_ICR_BIT_EEPROM_READ (1 << 27) +#define PLX_ICR_BIT_EEPROM_VALID (1 << 28) +#define PLX_ICR_MASK_EEPROM (0x1f << 24) + +#define EEPROM_DELAY 1 + +#define ME4000_AI_FIFO_COUNT 2048 + +#define ME4000_AI_MIN_TICKS 66 +#define ME4000_AI_MIN_SAMPLE_TIME 2000 +#define ME4000_AI_BASE_FREQUENCY (unsigned int) 33E6 + +#define ME4000_AI_CHANNEL_LIST_COUNT 1024 + +struct me4000_info { + unsigned long plx_regbase; + unsigned long timer_regbase; + + unsigned int ao_readback[4]; }; -#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1) - -/*----------------------------------------------------------------------------- - Meilhaus function prototypes - ---------------------------------------------------------------------------*/ -static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p); -static int init_board_info(struct comedi_device *dev, - struct pci_dev *pci_dev_p); -static int init_ao_context(struct comedi_device *dev); -static int init_ai_context(struct comedi_device *dev); -static int init_dio_context(struct comedi_device *dev); -static int init_cnt_context(struct comedi_device *dev); -static int xilinx_download(struct comedi_device *dev); -static int reset_board(struct comedi_device *dev); +struct me4000_board { + const char *name; + unsigned short device_id; + int ao_nchan; + int ao_fifo; + int ai_nchan; + int ai_diff_nchan; + int ai_sh_nchan; + int ex_trig_analog; + int dio_nchan; + int has_counter; +}; -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); +static const struct me4000_board me4000_boards[] = { + { + .name = "ME-4650", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4650, + .ai_nchan = 16, + .dio_nchan = 32, + }, { + .name = "ME-4660", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4660i", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660I, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4660s", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660S, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4660is", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660IS, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670i", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670I, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670s", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670S, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670is", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670IS, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680i", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680I, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680s", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680S, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680is", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680IS, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, +}; static const struct comedi_lrange me4000_ai_range = { 4, @@ -114,380 +363,6 @@ static const struct comedi_lrange me4000_ai_range = { } }; -static const struct comedi_lrange me4000_ao_range = { - 1, - { - BIP_RANGE(10), - } -}; - -static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pci_device = NULL; - int result, i; - struct me4000_board *board; - - /* Allocate private memory */ - if (alloc_private(dev, sizeof(struct me4000_info)) < 0) - return -ENOMEM; - - /* - * Probe the device to determine what device in the series it is. - */ - for_each_pci_dev(pci_device) { - if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) { - for (i = 0; i < ME4000_BOARD_VERSIONS; i++) { - if (me4000_boards[i].device_id == - pci_device->device) { - /* - * Was a particular - * bus/slot requested? - */ - if ((it->options[0] != 0) - || (it->options[1] != 0)) { - /* - * Are we on the wrong - * bus/slot? - */ - if (pci_device->bus->number != - it->options[0] - || - PCI_SLOT(pci_device->devfn) - != it->options[1]) { - continue; - } - } - dev->board_ptr = me4000_boards + i; - board = - (struct me4000_board *) - dev->board_ptr; - info->pci_dev_p = pci_device; - goto found; - } - } - } - } - - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "No supported board found (req. bus/slot : %d/%d)\n", - dev->minor, it->options[0], it->options[1]); - return -ENODEV; - -found: - - printk(KERN_INFO - "comedi%d: me4000: me4000_probe(): " - "Found %s at PCI bus %d, slot %d\n", - dev->minor, me4000_boards[i].name, pci_device->bus->number, - PCI_SLOT(pci_device->devfn)); - - /* Set data in device structure */ - dev->board_name = board->name; - - /* Enable PCI device and request regions */ - result = comedi_pci_enable(pci_device, dev->board_name); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): Cannot enable PCI " - "device and request I/O regions\n", dev->minor); - return result; - } - - /* Get the PCI base registers */ - result = get_registers(dev, pci_device); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot get registers\n", dev->minor); - return result; - } - /* Initialize board info */ - result = init_board_info(dev, pci_device); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init baord info\n", dev->minor); - return result; - } - - /* Init analog output context */ - result = init_ao_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init ao context\n", dev->minor); - return result; - } - - /* Init analog input context */ - result = init_ai_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init ai context\n", dev->minor); - return result; - } - - /* Init digital I/O context */ - result = init_dio_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init dio context\n", dev->minor); - return result; - } - - /* Init counter context */ - result = init_cnt_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init cnt context\n", dev->minor); - return result; - } - - /* Download the xilinx firmware */ - result = xilinx_download(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Can't download firmware\n", dev->minor); - return result; - } - - /* Make a hardware reset */ - result = reset_board(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): Can't reset board\n", - dev->minor); - return result; - } - - return 0; -} - -static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p) -{ - /*--------------------------- plx regbase -------------------------------*/ - - info->plx_regbase = pci_resource_start(pci_dev_p, 1); - if (info->plx_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 1 is not available\n", dev->minor); - return -ENODEV; - } - info->plx_regbase_size = pci_resource_len(pci_dev_p, 1); - - /*--------------------------- me4000 regbase ----------------------------*/ - - info->me4000_regbase = pci_resource_start(pci_dev_p, 2); - if (info->me4000_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 2 is not available\n", dev->minor); - return -ENODEV; - } - info->me4000_regbase_size = pci_resource_len(pci_dev_p, 2); - - /*--------------------------- timer regbase ------------------------------*/ - - info->timer_regbase = pci_resource_start(pci_dev_p, 3); - if (info->timer_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 3 is not available\n", dev->minor); - return -ENODEV; - } - info->timer_regbase_size = pci_resource_len(pci_dev_p, 3); - - /*--------------------------- program regbase ----------------------------*/ - - info->program_regbase = pci_resource_start(pci_dev_p, 5); - if (info->program_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 5 is not available\n", dev->minor); - return -ENODEV; - } - info->program_regbase_size = pci_resource_len(pci_dev_p, 5); - - return 0; -} - -static int init_board_info(struct comedi_device *dev, struct pci_dev *pci_dev_p) -{ - int result; - - /* Init spin locks */ - /* spin_lock_init(&info->preload_lock); */ - /* spin_lock_init(&info->ai_ctrl_lock); */ - - /* Get the serial number */ - result = pci_read_config_dword(pci_dev_p, 0x2C, &info->serial_no); - if (result != PCIBIOS_SUCCESSFUL) - return result; - - /* Get the hardware revision */ - result = pci_read_config_byte(pci_dev_p, 0x08, &info->hw_revision); - if (result != PCIBIOS_SUCCESSFUL) - return result; - - /* Get the vendor id */ - info->vendor_id = pci_dev_p->vendor; - - /* Get the device id */ - info->device_id = pci_dev_p->device; - - /* Get the irq assigned to the board */ - info->irq = pci_dev_p->irq; - - return 0; -} - -static int init_ao_context(struct comedi_device *dev) -{ - int i; - - for (i = 0; i < thisboard->ao.count; i++) { - /* spin_lock_init(&info->ao_context[i].use_lock); */ - info->ao_context[i].irq = info->irq; - - switch (i) { - case 0: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_00_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_00_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_00_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_00_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_00_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 1: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_01_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_01_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_01_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_01_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_01_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 2: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_02_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_02_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_02_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_02_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_02_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 3: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_03_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_03_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_03_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_03_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_03_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - default: - break; - } - } - - return 0; -} - -static int init_ai_context(struct comedi_device *dev) -{ - info->ai_context.irq = info->irq; - - info->ai_context.ctrl_reg = info->me4000_regbase + ME4000_AI_CTRL_REG; - info->ai_context.status_reg = - info->me4000_regbase + ME4000_AI_STATUS_REG; - info->ai_context.channel_list_reg = - info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG; - info->ai_context.data_reg = info->me4000_regbase + ME4000_AI_DATA_REG; - info->ai_context.chan_timer_reg = - info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG; - info->ai_context.chan_pre_timer_reg = - info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG; - info->ai_context.scan_timer_low_reg = - info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG; - info->ai_context.scan_timer_high_reg = - info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG; - info->ai_context.scan_pre_timer_low_reg = - info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG; - info->ai_context.scan_pre_timer_high_reg = - info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG; - info->ai_context.start_reg = info->me4000_regbase + ME4000_AI_START_REG; - info->ai_context.irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ai_context.sample_counter_reg = - info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG; - - return 0; -} - -static int init_dio_context(struct comedi_device *dev) -{ - info->dio_context.dir_reg = info->me4000_regbase + ME4000_DIO_DIR_REG; - info->dio_context.ctrl_reg = info->me4000_regbase + ME4000_DIO_CTRL_REG; - info->dio_context.port_0_reg = - info->me4000_regbase + ME4000_DIO_PORT_0_REG; - info->dio_context.port_1_reg = - info->me4000_regbase + ME4000_DIO_PORT_1_REG; - info->dio_context.port_2_reg = - info->me4000_regbase + ME4000_DIO_PORT_2_REG; - info->dio_context.port_3_reg = - info->me4000_regbase + ME4000_DIO_PORT_3_REG; - - return 0; -} - -static int init_cnt_context(struct comedi_device *dev) -{ - info->cnt_context.ctrl_reg = info->timer_regbase + ME4000_CNT_CTRL_REG; - info->cnt_context.counter_0_reg = - info->timer_regbase + ME4000_CNT_COUNTER_0_REG; - info->cnt_context.counter_1_reg = - info->timer_regbase + ME4000_CNT_COUNTER_1_REG; - info->cnt_context.counter_2_reg = - info->timer_regbase + ME4000_CNT_COUNTER_2_REG; - - return 0; -} - #define FIRMWARE_NOT_AVAILABLE 1 #if FIRMWARE_NOT_AVAILABLE extern unsigned char *xilinx_firm; @@ -495,11 +370,17 @@ extern unsigned char *xilinx_firm; static int xilinx_download(struct comedi_device *dev) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct me4000_info *info = dev->private; + unsigned long xilinx_iobase = pci_resource_start(pcidev, 5); u32 value = 0; wait_queue_head_t queue; int idx = 0; int size = 0; + if (!xilinx_iobase) + return -ENODEV; + init_waitqueue_head(&queue); /* @@ -514,14 +395,12 @@ static int xilinx_download(struct comedi_device *dev) outl(value, info->plx_regbase + PLX_ICR); /* Init Xilinx with CS1 */ - inb(info->program_regbase + 0xC8); + inb(xilinx_iobase + 0xC8); /* Wait until /INIT pin is set */ udelay(20); if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Can't init Xilinx\n", dev->minor); + dev_err(dev->class_dev, "Can't init Xilinx\n"); return -EIO; } @@ -530,8 +409,8 @@ static int xilinx_download(struct comedi_device *dev) value &= ~0x100; outl(value, info->plx_regbase + PLX_ICR); if (FIRMWARE_NOT_AVAILABLE) { - comedi_error(dev, "xilinx firmware unavailable " - "due to licensing, aborting"); + dev_err(dev->class_dev, + "xilinx firmware unavailable due to licensing, aborting"); return -EIO; } else { /* Download Xilinx firmware */ @@ -540,15 +419,14 @@ static int xilinx_download(struct comedi_device *dev) udelay(10); for (idx = 0; idx < size; idx++) { - outb(xilinx_firm[16 + idx], info->program_regbase); + outb(xilinx_firm[16 + idx], xilinx_iobase); udelay(10); /* Check if BUSY flag is low */ if (inl(info->plx_regbase + PLX_ICR) & 0x20) { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Xilinx is still busy (idx = %d)\n", - dev->minor, idx); + dev_err(dev->class_dev, + "Xilinx is still busy (idx = %d)\n", + idx); return -EIO; } } @@ -557,12 +435,8 @@ static int xilinx_download(struct comedi_device *dev) /* If done flag is high download was successful */ if (inl(info->plx_regbase + PLX_ICR) & 0x4) { } else { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "DONE flag is not set\n", dev->minor); - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Download not successful\n", dev->minor); + dev_err(dev->class_dev, "DONE flag is not set\n"); + dev_err(dev->class_dev, "Download not successful\n"); return -EIO; } @@ -574,52 +448,45 @@ static int xilinx_download(struct comedi_device *dev) return 0; } -static int reset_board(struct comedi_device *dev) +static void me4000_reset(struct comedi_device *dev) { - unsigned long icr; + struct me4000_info *info = dev->private; + unsigned long val; + int chan; /* Make a hardware reset */ - icr = inl(info->plx_regbase + PLX_ICR); - icr |= 0x40000000; - outl(icr, info->plx_regbase + PLX_ICR); - icr &= ~0x40000000; - outl(icr, info->plx_regbase + PLX_ICR); + val = inl(info->plx_regbase + PLX_ICR); + val |= 0x40000000; + outl(val, info->plx_regbase + PLX_ICR); + val &= ~0x40000000; + outl(val , info->plx_regbase + PLX_ICR); /* 0x8000 to the DACs means an output voltage of 0V */ - outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG); - outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG); - outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG); - outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG); + for (chan = 0; chan < 4; chan++) + outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Set both stop bits in the analog input control register */ outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AI_CTRL_REG); + dev->iobase + ME4000_AI_CTRL_REG); /* Set both stop bits in the analog output control register */ - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_00_CTRL_REG); - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_01_CTRL_REG); - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_02_CTRL_REG); - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_03_CTRL_REG); + val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP; + for (chan = 0; chan < 4; chan++) + outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Enable interrupts on the PLX */ outl(0x43, info->plx_regbase + PLX_INTCSR); /* Set the adustment register for AO demux */ outl(ME4000_AO_DEMUX_ADJUST_VALUE, - info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG); + dev->iobase + ME4000_AO_DEMUX_ADJUST_REG); /* * Set digital I/O direction for port 0 * to output on isolated versions */ - if (!(inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) - outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG); - - return 0; + if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1)) + outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG); } /*============================================================================= @@ -630,7 +497,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *subdevice, struct comedi_insn *insn, unsigned int *data) { - + const struct me4000_board *thisboard = comedi_board(dev); int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); @@ -642,9 +509,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev, if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid instruction length %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } @@ -662,19 +528,16 @@ static int me4000_ai_insn_read(struct comedi_device *dev, entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid range specified\n", dev->minor); + dev_err(dev->class_dev, "Invalid range specified\n"); return -EINVAL; } switch (aref) { case AREF_GROUND: case AREF_COMMON: - if (chan >= thisboard->ai.count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Analog input is not available\n", dev->minor); + if (chan >= thisboard->ai_nchan) { + dev_err(dev->class_dev, + "Analog input is not available\n"); return -EINVAL; } entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan; @@ -682,68 +545,61 @@ static int me4000_ai_insn_read(struct comedi_device *dev, case AREF_DIFF: if (rang == 0 || rang == 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Range must be bipolar when aref = diff\n", - dev->minor); + dev_err(dev->class_dev, + "Range must be bipolar when aref = diff\n"); return -EINVAL; } - if (chan >= thisboard->ai.diff_count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Analog input is not available\n", dev->minor); + if (chan >= thisboard->ai_diff_nchan) { + dev_err(dev->class_dev, + "Analog input is not available\n"); return -EINVAL; } entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid aref specified\n", dev->minor); + dev_err(dev->class_dev, "Invalid aref specified\n"); return -EINVAL; } entry |= ME4000_AI_LIST_LAST_ENTRY; /* Clear channel list, data fifo and both stop bits */ - tmp = inl(info->ai_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Set the acquisition mode to single */ tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 | ME4000_AI_CTRL_BIT_MODE_2); - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Enable channel list and data fifo */ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Generate channel list entry */ - outl(entry, info->ai_context.channel_list_reg); + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); /* Set the timer to maximum sample rate */ - outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg); - outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_pre_timer_reg); + outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG); + outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); /* Start conversion by dummy read */ - inl(info->ai_context.start_reg); + inl(dev->iobase + ME4000_AI_START_REG); /* Wait until ready */ udelay(10); - if (!(inl(info->ai_context.status_reg) & + if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) & ME4000_AI_STATUS_BIT_EF_DATA)) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Value not available after wait\n", dev->minor); + dev_err(dev->class_dev, "Value not available after wait\n"); return -EIO; } /* Read value from data fifo */ - lval = inl(info->ai_context.data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; data[0] = lval ^ 0x8000; return 1; @@ -755,12 +611,12 @@ static int me4000_ai_cancel(struct comedi_device *dev, unsigned long tmp; /* Stop any running conversion */ - tmp = inl(info->ai_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Clear the control register */ - outl(0x0, info->ai_context.ctrl_reg); + outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); return 0; } @@ -768,30 +624,25 @@ static int me4000_ai_cancel(struct comedi_device *dev, static int ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct me4000_board *thisboard = comedi_board(dev); int aref; int i; /* Check whether a channel list is available */ if (!cmd->chanlist_len) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "No channel list available\n", dev->minor); + dev_err(dev->class_dev, "No channel list available\n"); return -EINVAL; } /* Check the channel list size */ if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Channel list is to large\n", dev->minor); + dev_err(dev->class_dev, "Channel list is to large\n"); return -EINVAL; } /* Check the pointer */ if (!cmd->chanlist) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "NULL pointer to channel list\n", dev->minor); + dev_err(dev->class_dev, "NULL pointer to channel list\n"); return -EFAULT; } @@ -799,10 +650,8 @@ static int ai_check_chanlist(struct comedi_device *dev, aref = CR_AREF(cmd->chanlist[0]); for (i = 0; i < cmd->chanlist_len; i++) { if (CR_AREF(cmd->chanlist[i]) != aref) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Mode is not equal for all entries\n", - dev->minor); + dev_err(dev->class_dev, + "Mode is not equal for all entries\n"); return -EINVAL; } } @@ -811,19 +660,17 @@ static int ai_check_chanlist(struct comedi_device *dev, if (aref == SDF_DIFF) { for (i = 0; i < cmd->chanlist_len; i++) { if (CR_CHAN(cmd->chanlist[i]) >= - thisboard->ai.diff_count) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist():" - " Channel number to high\n", dev->minor); + thisboard->ai_diff_nchan) { + dev_err(dev->class_dev, + "Channel number to high\n"); return -EINVAL; } } } else { for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai.count) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Channel number to high\n", dev->minor); + if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) { + dev_err(dev->class_dev, + "Channel number to high\n"); return -EINVAL; } } @@ -834,11 +681,8 @@ static int ai_check_chanlist(struct comedi_device *dev, for (i = 0; i < cmd->chanlist_len; i++) { if (CR_RANGE(cmd->chanlist[i]) != 1 && CR_RANGE(cmd->chanlist[i]) != 2) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Bipolar is not selected in " - "differential mode\n", - dev->minor); + dev_err(dev->class_dev, + "Bipolar is not selected in differential mode\n"); return -EINVAL; } } @@ -906,16 +750,52 @@ static void ai_write_timer(struct comedi_device *dev, unsigned int init_ticks, unsigned int scan_ticks, unsigned int chan_ticks) { - outl(init_ticks - 1, info->ai_context.scan_pre_timer_low_reg); - outl(0x0, info->ai_context.scan_pre_timer_high_reg); + outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG); if (scan_ticks) { - outl(scan_ticks - 1, info->ai_context.scan_timer_low_reg); - outl(0x0, info->ai_context.scan_timer_high_reg); + outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG); } - outl(chan_ticks - 1, info->ai_context.chan_pre_timer_reg); - outl(chan_ticks - 1, info->ai_context.chan_timer_reg); + outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); + outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG); +} + +static int ai_write_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) +{ + unsigned int entry; + unsigned int chan; + unsigned int rang; + unsigned int aref; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + chan = CR_CHAN(cmd->chanlist[i]); + rang = CR_RANGE(cmd->chanlist[i]); + aref = CR_AREF(cmd->chanlist[i]); + + entry = chan; + + if (rang == 0) + entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; + else if (rang == 1) + entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; + else if (rang == 2) + entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; + else + entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; + + if (aref == SDF_DIFF) + entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; + else + entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; + + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); + } + + return 0; } static int ai_prepare(struct comedi_device *dev, @@ -931,7 +811,7 @@ static int ai_prepare(struct comedi_device *dev, ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); /* Reset control register */ - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Start sources */ if ((cmd->start_src == TRIG_EXT && @@ -965,19 +845,19 @@ static int ai_prepare(struct comedi_device *dev, /* Stop triggers */ if (cmd->stop_src == TRIG_COUNT) { outl(cmd->chanlist_len * cmd->stop_arg, - info->ai_context.sample_counter_reg); + dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; } else if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_COUNT) { outl(cmd->scan_end_arg, - info->ai_context.sample_counter_reg); + dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; } else { tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; } /* Write the setup to the control register */ - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Write the channel list */ ai_write_chanlist(dev, s, cmd); @@ -985,42 +865,6 @@ static int ai_prepare(struct comedi_device *dev, return 0; } -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - unsigned int entry; - unsigned int chan; - unsigned int rang; - unsigned int aref; - int i; - - for (i = 0; i < cmd->chanlist_len; i++) { - chan = CR_CHAN(cmd->chanlist[i]); - rang = CR_RANGE(cmd->chanlist[i]); - aref = CR_AREF(cmd->chanlist[i]); - - entry = chan; - - if (rang == 0) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; - else if (rang == 1) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; - else if (rang == 2) - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; - else - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; - - if (aref == SDF_DIFF) - entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; - else - entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; - - outl(entry, info->ai_context.channel_list_reg); - } - - return 0; -} - static int me4000_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1047,23 +891,11 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, return err; /* Start acquistion by dummy read */ - inl(info->ai_context.start_reg); + inl(dev->iobase + ME4000_AI_START_REG); return 0; } -/* - * me4000_ai_do_cmd_test(): - * - * The demo cmd.c in ./comedilib/demo specifies 6 return values: - * - success - * - invalid source - * - source conflict - * - invalid argument - * - argument conflict - * - invalid chanlist - * So I tried to adopt this scheme. - */ static int me4000_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -1080,91 +912,29 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Round the timer arguments */ ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); - /* - * Stage 1. Check if the trigger sources are generally valid. - */ - switch (cmd->start_src) { - case TRIG_NOW: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->start_src &= TRIG_NOW | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start source\n", dev->minor); - cmd->start_src = TRIG_NOW; - err++; - } - switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: - case TRIG_TIMER: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan begin source\n", dev->minor); - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } - switch (cmd->convert_src) { - case TRIG_TIMER: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert source\n", dev->minor); - cmd->convert_src = TRIG_TIMER; - err++; - } - switch (cmd->scan_end_src) { - case TRIG_NONE: - case TRIG_COUNT: - break; - case TRIG_ANY: - cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end source\n", dev->minor); - cmd->scan_end_src = TRIG_NONE; - err++; - } - switch (cmd->stop_src) { - case TRIG_NONE: - case TRIG_COUNT: - break; - case TRIG_ANY: - cmd->stop_src &= TRIG_NONE | TRIG_COUNT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop source\n", dev->minor); - cmd->stop_src = TRIG_NONE; - err++; - } + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, + TRIG_NONE | TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE | TRIG_COUNT); + if (err) return 1; - /* - * Stage 2. Check for trigger source conflicts. - */ + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->scan_end_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + if (cmd->start_src == TRIG_NOW && cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { @@ -1184,13 +954,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_EXT) { } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start trigger combination\n", dev->minor); - cmd->start_src = TRIG_NOW; - cmd->scan_begin_src = TRIG_FOLLOW; - cmd->convert_src = TRIG_TIMER; - err++; + err |= -EINVAL; } if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) { @@ -1201,13 +965,9 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, } else if (cmd->stop_src == TRIG_COUNT && cmd->scan_end_src == TRIG_COUNT) { } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop trigger combination\n", dev->minor); - cmd->stop_src = TRIG_NONE; - cmd->scan_end_src = TRIG_NONE; - err++; + err |= -EINVAL; } + if (err) return 2; @@ -1215,30 +975,22 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, * Stage 3. Check if arguments are generally valid. */ if (cmd->chanlist_len < 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "No channel list\n", dev->minor); + dev_err(dev->class_dev, "No channel list\n"); cmd->chanlist_len = 1; err++; } if (init_ticks < 66) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Start arg to low\n", dev->minor); + dev_err(dev->class_dev, "Start arg to low\n"); cmd->start_arg = 2000; err++; } if (scan_ticks && scan_ticks < 67) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Scan begin arg to low\n", dev->minor); + dev_err(dev->class_dev, "Scan begin arg to low\n"); cmd->scan_begin_arg = 2031; err++; } if (chan_ticks < 66) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Convert arg to low\n", dev->minor); + dev_err(dev->class_dev, "Convert arg to low\n"); cmd->convert_arg = 2000; err++; } @@ -1255,23 +1007,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } if (scan_ticks <= cmd->chanlist_len * chan_ticks) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; @@ -1283,16 +1029,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1302,23 +1044,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } if (scan_ticks <= cmd->chanlist_len * chan_ticks) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; @@ -1330,16 +1066,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1349,16 +1081,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1368,27 +1096,21 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } } if (cmd->stop_src == TRIG_COUNT) { if (cmd->stop_arg == 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid stop arg\n"); cmd->stop_arg = 1; err++; } } if (cmd->scan_end_src == TRIG_COUNT) { if (cmd->scan_end_arg == 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); cmd->scan_end_arg = 1; err++; } @@ -1410,8 +1132,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) { unsigned int tmp; struct comedi_device *dev = dev_id; - struct comedi_subdevice *s = dev->subdevices; - struct me4000_ai_context *ai_context = &info->ai_context; + struct comedi_subdevice *s = &dev->subdevices[0]; int i; int c = 0; long lval; @@ -1423,17 +1144,15 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) s->async->events = 0; /* Check if irq number is right */ - if (irq != ai_context->irq) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Incorrect interrupt num: %d\n", dev->minor, irq); + if (irq != dev->irq) { + dev_err(dev->class_dev, "Incorrect interrupt num: %d\n", irq); return IRQ_HANDLED; } - if (inl(ai_context->irq_status_reg) & + if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ - tmp = inl(ai_context->ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && @@ -1447,13 +1166,11 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "FIFO overflow\n", dev->minor); + dev_err(dev->class_dev, "FIFO overflow\n"); } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { @@ -1461,9 +1178,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) c = ME4000_AI_FIFO_COUNT / 2; } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Can't determine state of fifo\n", dev->minor); + dev_err(dev->class_dev, + "Can't determine state of fifo\n"); c = 0; /* @@ -1473,18 +1189,16 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Undefined FIFO state\n", dev->minor); + dev_err(dev->class_dev, "Undefined FIFO state\n"); } for (i = 0; i < c; i++) { /* Read value from data fifo */ - lval = inl(ai_context->data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; if (!comedi_buf_put(s->async, lval)) { @@ -1495,13 +1209,11 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_OVERFLOW; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Buffer overflow\n", dev->minor); + dev_err(dev->class_dev, "Buffer overflow\n"); break; } @@ -1509,33 +1221,33 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) /* Work is done, so reset the interrupt */ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } - if (inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { + if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & + ME4000_IRQ_STATUS_BIT_SC) { s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA; /* * Acquisition is complete, so stop * conversion and disable all interrupts */ - tmp = inl(ai_context->ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Poll data until fifo empty */ - while (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_EF_DATA) { + while (inl(dev->iobase + ME4000_AI_CTRL_REG) & + ME4000_AI_STATUS_BIT_EF_DATA) { /* Read value from data fifo */ - lval = inl(ai_context->data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; if (!comedi_buf_put(s->async, lval)) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Buffer overflow\n", dev->minor); + dev_err(dev->class_dev, "Buffer overflow\n"); s->async->events |= COMEDI_CB_OVERFLOW; break; } @@ -1543,9 +1255,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) /* Work is done, so reset the interrupt */ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } if (s->async->events) @@ -1562,7 +1274,8 @@ static int me4000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - + const struct me4000_board *thisboard = comedi_board(dev); + struct me4000_info *info = dev->private; int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); @@ -1571,46 +1284,39 @@ static int me4000_ao_insn_write(struct comedi_device *dev, if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid instruction length %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - if (chan >= thisboard->ao.count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid channel %d\n", dev->minor, insn->n); + if (chan >= thisboard->ao_nchan) { + dev_err(dev->class_dev, "Invalid channel %d\n", insn->n); return -EINVAL; } if (rang != 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid range %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid range %d\n", insn->n); return -EINVAL; } if (aref != AREF_GROUND && aref != AREF_COMMON) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid aref %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid aref %d\n", insn->n); return -EINVAL; } /* Stop any running conversion */ - tmp = inl(info->ao_context[chan].ctrl_reg); + tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan)); tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; - outl(tmp, info->ao_context[chan].ctrl_reg); + outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Clear control register and set to single mode */ - outl(0x0, info->ao_context[chan].ctrl_reg); + outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Write data value */ - outl(data[0], info->ao_context[chan].single_reg); + outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Store in the mirror */ - info->ao_context[chan].mirror = data[0]; + info->ao_readback[chan] = data[0]; return 1; } @@ -1619,18 +1325,17 @@ static int me4000_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct me4000_info *info = dev->private; int chan = CR_CHAN(insn->chanspec); if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk - ("comedi%d: me4000: me4000_ao_insn_read(): " - "Invalid instruction length\n", dev->minor); + dev_err(dev->class_dev, "Invalid instruction length\n"); return -EINVAL; } - data[0] = info->ao_context[chan].mirror; + data[0] = info->ao_readback[chan]; return 1; } @@ -1659,21 +1364,21 @@ static int me4000_dio_insn_bits(struct comedi_device *dev, /* Write out the new digital output lines */ outl((s->state >> 0) & 0xFF, - info->dio_context.port_0_reg); + dev->iobase + ME4000_DIO_PORT_0_REG); outl((s->state >> 8) & 0xFF, - info->dio_context.port_1_reg); + dev->iobase + ME4000_DIO_PORT_1_REG); outl((s->state >> 16) & 0xFF, - info->dio_context.port_2_reg); + dev->iobase + ME4000_DIO_PORT_2_REG); outl((s->state >> 24) & 0xFF, - info->dio_context.port_3_reg); + dev->iobase + ME4000_DIO_PORT_3_REG); } /* On return, data[1] contains the value of the digital input and output lines. */ - data[1] = ((inl(info->dio_context.port_0_reg) & 0xFF) << 0) | - ((inl(info->dio_context.port_1_reg) & 0xFF) << 8) | - ((inl(info->dio_context.port_2_reg) & 0xFF) << 16) | - ((inl(info->dio_context.port_3_reg) & 0xFF) << 24); + data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) | + ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) | + ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) | + ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24); return insn->n; } @@ -1705,7 +1410,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, * On the ME-4000 it is only possible to switch port wise (8 bit) */ - tmp = inl(info->dio_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG); if (data[0] == INSN_CONFIG_DIO_OUTPUT) { if (chan < 8) { @@ -1719,7 +1424,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, * If one the first port is a fixed output * port and the second is a fixed input port. */ - if (!inl(info->dio_context.dir_reg)) + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) return -ENODEV; s->io_bits |= 0xFF00; @@ -1746,7 +1451,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, * If one the first port is a fixed output * port and the second is a fixed input port. */ - if (!inl(info->dio_context.dir_reg)) + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) return -ENODEV; s->io_bits &= ~0xFF; @@ -1769,7 +1474,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, } } - outl(tmp, info->dio_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG); return 1; } @@ -1778,177 +1483,56 @@ static int me4000_dio_insn_config(struct comedi_device *dev, Counter section ===========================================================================*/ -static int cnt_reset(struct comedi_device *dev, unsigned int channel) -{ - switch (channel) { - case 0: - outb(0x30, info->cnt_context.ctrl_reg); - outb(0x00, info->cnt_context.counter_0_reg); - outb(0x00, info->cnt_context.counter_0_reg); - break; - case 1: - outb(0x70, info->cnt_context.ctrl_reg); - outb(0x00, info->cnt_context.counter_1_reg); - outb(0x00, info->cnt_context.counter_1_reg); - break; - case 2: - outb(0xB0, info->cnt_context.ctrl_reg); - outb(0x00, info->cnt_context.counter_2_reg); - outb(0x00, info->cnt_context.counter_2_reg); - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_reset(): Invalid channel\n", - dev->minor); - return -EINVAL; - } - - return 0; -} - -static int cnt_config(struct comedi_device *dev, unsigned int channel, - unsigned int mode) -{ - int tmp = 0; - - switch (channel) { - case 0: - tmp |= ME4000_CNT_COUNTER_0; - break; - case 1: - tmp |= ME4000_CNT_COUNTER_1; - break; - case 2: - tmp |= ME4000_CNT_COUNTER_2; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_config(): Invalid channel\n", - dev->minor); - return -EINVAL; - } - - switch (mode) { - case 0: - tmp |= ME4000_CNT_MODE_0; - break; - case 1: - tmp |= ME4000_CNT_MODE_1; - break; - case 2: - tmp |= ME4000_CNT_MODE_2; - break; - case 3: - tmp |= ME4000_CNT_MODE_3; - break; - case 4: - tmp |= ME4000_CNT_MODE_4; - break; - case 5: - tmp |= ME4000_CNT_MODE_5; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_config(): Invalid counter mode\n", - dev->minor); - return -EINVAL; - } - - /* Write the control word */ - tmp |= 0x30; - outb(tmp, info->cnt_context.ctrl_reg); - - return 0; -} - static int me4000_cnt_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - + struct me4000_info *info = dev->private; int err; switch (data[0]) { case GPCT_RESET: - if (insn->n != 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction length%d\n", - dev->minor, insn->n); + if (insn->n != 1) return -EINVAL; - } - err = cnt_reset(dev, insn->chanspec); + err = i8254_load(info->timer_regbase, 0, insn->chanspec, 0, + I8254_MODE0 | I8254_BINARY); if (err) return err; break; case GPCT_SET_OPERATION: - if (insn->n != 2) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction length%d\n", - dev->minor, insn->n); + if (insn->n != 2) return -EINVAL; - } - err = cnt_config(dev, insn->chanspec, data[1]); + err = i8254_set_mode(info->timer_regbase, 0, insn->chanspec, + (data[1] << 1) | I8254_BINARY); if (err) return err; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction\n", dev->minor); return -EINVAL; } - return 2; + return insn->n; } static int me4000_cnt_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - unsigned short tmp; + struct me4000_info *info = dev->private; if (insn->n == 0) return 0; if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_read(): " - "Invalid instruction length %d\n", - dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - switch (insn->chanspec) { - case 0: - tmp = inb(info->cnt_context.counter_0_reg); - data[0] = tmp; - tmp = inb(info->cnt_context.counter_0_reg); - data[0] |= tmp << 8; - break; - case 1: - tmp = inb(info->cnt_context.counter_1_reg); - data[0] = tmp; - tmp = inb(info->cnt_context.counter_1_reg); - data[0] |= tmp << 8; - break; - case 2: - tmp = inb(info->cnt_context.counter_2_reg); - data[0] = tmp; - tmp = inb(info->cnt_context.counter_2_reg); - data[0] |= tmp << 8; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_read(): " - "Invalid channel %d\n", - dev->minor, insn->chanspec); - return -EINVAL; - } + data[0] = i8254_read(info->timer_regbase, 0, insn->chanspec); return 1; } @@ -1957,58 +1541,72 @@ static int me4000_cnt_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - unsigned short tmp; + struct me4000_info *info = dev->private; if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_write(): " - "Invalid instruction length %d\n", - dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - switch (insn->chanspec) { - case 0: - tmp = data[0] & 0xFF; - outb(tmp, info->cnt_context.counter_0_reg); - tmp = (data[0] >> 8) & 0xFF; - outb(tmp, info->cnt_context.counter_0_reg); - break; - case 1: - tmp = data[0] & 0xFF; - outb(tmp, info->cnt_context.counter_1_reg); - tmp = (data[0] >> 8) & 0xFF; - outb(tmp, info->cnt_context.counter_1_reg); - break; - case 2: - tmp = data[0] & 0xFF; - outb(tmp, info->cnt_context.counter_2_reg); - tmp = (data[0] >> 8) & 0xFF; - outb(tmp, info->cnt_context.counter_2_reg); - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_write(): " - "Invalid channel %d\n", - dev->minor, insn->chanspec); - return -EINVAL; - } + i8254_write(info->timer_regbase, 0, insn->chanspec, data[0]); return 1; } -static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static const void *me4000_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { + const struct me4000_board *thisboard; + int i; + + for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) { + thisboard = &me4000_boards[i]; + if (thisboard->device_id == pcidev->device) + return thisboard; + } + return NULL; +} + +static int me4000_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct me4000_board *thisboard; + struct me4000_info *info; struct comedi_subdevice *s; int result; - result = me4000_probe(dev, it); + comedi_set_hw_dev(dev, &pcidev->dev); + + thisboard = me4000_find_boardinfo(dev, pcidev); + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + result = alloc_private(dev, sizeof(*info)); + if (result) + return result; + info = dev->private; + + result = comedi_pci_enable(pcidev, dev->board_name); + if (result) + return result; + + info->plx_regbase = pci_resource_start(pcidev, 1); + dev->iobase = pci_resource_start(pcidev, 2); + info->timer_regbase = pci_resource_start(pcidev, 3); + if (!info->plx_regbase || !dev->iobase || !info->timer_regbase) + return -ENODEV; + + result = xilinx_download(dev); if (result) return result; + me4000_reset(dev); + result = comedi_alloc_subdevices(dev, 4); if (result) return result; @@ -2017,35 +1615,34 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) Analog input subdevice ========================================================================*/ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; - if (thisboard->ai.count) { + if (thisboard->ai_nchan) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai.count; + s->n_chan = thisboard->ai_nchan; s->maxdata = 0xFFFF; /* 16 bit ADC */ s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; s->range_table = &me4000_ai_range; s->insn_read = me4000_ai_insn_read; - if (info->irq > 0) { - if (request_irq(info->irq, me4000_ai_isr, - IRQF_SHARED, "ME-4000", dev)) { - printk - ("comedi%d: me4000: me4000_attach(): " - "Unable to allocate irq\n", dev->minor); + if (pcidev->irq > 0) { + if (request_irq(pcidev->irq, me4000_ai_isr, + IRQF_SHARED, dev->board_name, dev)) { + dev_warn(dev->class_dev, + "request_irq failed\n"); } else { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->cancel = me4000_ai_cancel; s->do_cmdtest = me4000_ai_do_cmd_test; s->do_cmd = me4000_ai_do_cmd; + + dev->irq = pcidev->irq; } } else { - printk(KERN_WARNING - "comedi%d: me4000: me4000_attach(): " - "No interrupt available\n", dev->minor); + dev_warn(dev->class_dev, "No interrupt available\n"); } } else { s->type = COMEDI_SUBD_UNUSED; @@ -2055,14 +1652,14 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) Analog output subdevice ========================================================================*/ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; - if (thisboard->ao.count) { + if (thisboard->ao_nchan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; - s->n_chan = thisboard->ao.count; + s->n_chan = thisboard->ao_nchan; s->maxdata = 0xFFFF; /* 16 bit DAC */ - s->range_table = &me4000_ao_range; + s->range_table = &range_bipolar10; s->insn_write = me4000_ao_insn_write; s->insn_read = me4000_ao_insn_read; } else { @@ -2073,12 +1670,12 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) Digital I/O subdevice ========================================================================*/ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; - if (thisboard->dio.count) { + if (thisboard->dio_nchan) { s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->dio.count * 8; + s->n_chan = thisboard->dio_nchan; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = me4000_dio_insn_bits; @@ -2091,21 +1688,22 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) * Check for optoisolated ME-4000 version. If one the first * port is a fixed output port and the second is a fixed input port. */ - if (!inl(info->dio_context.dir_reg)) { + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) { s->io_bits |= 0xFF; - outl(ME4000_DIO_CTRL_BIT_MODE_0, info->dio_context.dir_reg); + outl(ME4000_DIO_CTRL_BIT_MODE_0, + dev->iobase + ME4000_DIO_DIR_REG); } /*========================================================================= Counter subdevice ========================================================================*/ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; - if (thisboard->cnt.count) { + if (thisboard->has_counter) { s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->cnt.count; + s->n_chan = 3; s->maxdata = 0xFFFF; /* 16 bit counters */ s->insn_read = me4000_cnt_insn_read; s->insn_write = me4000_cnt_insn_write; @@ -2119,12 +1717,14 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void me4000_detach(struct comedi_device *dev) { - if (info) { - if (info->pci_dev_p) { - reset_board(dev); - if (info->plx_regbase) - comedi_pci_disable(info->pci_dev_p); - pci_dev_put(info->pci_dev_p); + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (dev->irq) + free_irq(dev->irq, dev); + if (pcidev) { + if (dev->iobase) { + me4000_reset(dev); + comedi_pci_disable(pcidev); } } } @@ -2132,7 +1732,7 @@ static void me4000_detach(struct comedi_device *dev) static struct comedi_driver me4000_driver = { .driver_name = "me4000", .module = THIS_MODULE, - .attach = me4000_attach, + .attach_pci = me4000_attach_pci, .detach = me4000_detach, }; @@ -2148,20 +1748,20 @@ static void __devexit me4000_pci_remove(struct pci_dev *dev) } static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) }, - { 0 } + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660S)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660IS)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS)}, + {0} }; MODULE_DEVICE_TABLE(pci, me4000_pci_table); |