3 comedi/drivers/me_daq.c
5 Hardware driver for Meilhaus data acquisition cards:
7 ME-2000i, ME-2600i, ME-3000vm1
9 Copyright (C) 2002 Michael Hillmann <hillmann@syscongroup.de>
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 Description: Meilhaus PCI data acquisition cards
29 Author: Michael Hillmann <hillmann@syscongroup.de>
30 Devices: [Meilhaus] ME-2600i (me_daq), ME-2000i
37 Configuration options:
39 [0] - PCI bus number (optional)
40 [1] - PCI slot number (optional)
42 If bus/slot is not specified, the first available PCI
45 The 2600 requires a firmware upload, which can be accomplished
46 using the -i or --init-data option of comedi_config.
48 found in the comedi_nonfree_firmware tarball available
49 from http://www.comedi.org
53 #include <linux/comedidev.h>
55 #include <linux/pci.h>
57 //#include "me2600_fw.h"
59 #define ME_DRIVER_NAME "me_daq"
61 #define ME2000_DEVICE_ID 0x2000
62 #define ME2600_DEVICE_ID 0x2600
64 #define PLX_INTCSR 0x4C // PLX interrupt status register
65 #define XILINX_DOWNLOAD_RESET 0x42 // Xilinx registers
67 #define ME_CONTROL_1 0x0000 // - | W
68 #define INTERRUPT_ENABLE (1<<15)
69 #define COUNTER_B_IRQ (1<<12)
70 #define COUNTER_A_IRQ (1<<11)
71 #define CHANLIST_READY_IRQ (1<<10)
72 #define EXT_IRQ (1<<9)
73 #define ADFIFO_HALFFULL_IRQ (1<<8)
74 #define SCAN_COUNT_ENABLE (1<<5)
75 #define SIMULTANEOUS_ENABLE (1<<4)
76 #define TRIGGER_FALLING_EDGE (1<<3)
77 #define CONTINUOUS_MODE (1<<2)
78 #define DISABLE_ADC (0<<0)
79 #define SOFTWARE_TRIGGERED_ADC (1<<0)
80 #define SCAN_TRIGGERED_ADC (2<<0)
81 #define EXT_TRIGGERED_ADC (3<<0)
82 #define ME_ADC_START 0x0000 // R | -
83 #define ME_CONTROL_2 0x0002 // - | W
84 #define ENABLE_ADFIFO (1<<10)
85 #define ENABLE_CHANLIST (1<<9)
86 #define ENABLE_PORT_B (1<<7)
87 #define ENABLE_PORT_A (1<<6)
88 #define ENABLE_COUNTER_B (1<<4)
89 #define ENABLE_COUNTER_A (1<<3)
90 #define ENABLE_DAC (1<<1)
91 #define BUFFERED_DAC (1<<0)
92 #define ME_DAC_UPDATE 0x0002 // R | -
93 #define ME_STATUS 0x0004 // R | -
94 #define COUNTER_B_IRQ_PENDING (1<<12)
95 #define COUNTER_A_IRQ_PENDING (1<<11)
96 #define CHANLIST_READY_IRQ_PENDING (1<<10)
97 #define EXT_IRQ_PENDING (1<<9)
98 #define ADFIFO_HALFFULL_IRQ_PENDING (1<<8)
99 #define ADFIFO_FULL (1<<4)
100 #define ADFIFO_HALFFULL (1<<3)
101 #define ADFIFO_EMPTY (1<<2)
102 #define CHANLIST_FULL (1<<1)
103 #define FST_ACTIVE (1<<0)
104 #define ME_RESET_INTERRUPT 0x0004 // - | W
105 #define ME_DIO_PORT_A 0x0006 // R | W
106 #define ME_DIO_PORT_B 0x0008 // R | W
107 #define ME_TIMER_DATA_0 0x000A // - | W
108 #define ME_TIMER_DATA_1 0x000C // - | W
109 #define ME_TIMER_DATA_2 0x000E // - | W
110 #define ME_CHANNEL_LIST 0x0010 // - | W
111 #define ADC_UNIPOLAR (1<<6)
112 #define ADC_GAIN_0 (0<<4)
113 #define ADC_GAIN_1 (1<<4)
114 #define ADC_GAIN_2 (2<<4)
115 #define ADC_GAIN_3 (3<<4)
116 #define ME_READ_AD_FIFO 0x0010 // R | -
117 #define ME_DAC_CONTROL 0x0012 // - | W
118 #define DAC_UNIPOLAR_D (0<<4)
119 #define DAC_BIPOLAR_D (1<<4)
120 #define DAC_UNIPOLAR_C (0<<5)
121 #define DAC_BIPOLAR_C (1<<5)
122 #define DAC_UNIPOLAR_B (0<<6)
123 #define DAC_BIPOLAR_B (1<<6)
124 #define DAC_UNIPOLAR_A (0<<7)
125 #define DAC_BIPOLAR_A (1<<7)
126 #define DAC_GAIN_0_D (0<<8)
127 #define DAC_GAIN_1_D (1<<8)
128 #define DAC_GAIN_0_C (0<<9)
129 #define DAC_GAIN_1_C (1<<9)
130 #define DAC_GAIN_0_B (0<<10)
131 #define DAC_GAIN_1_B (1<<10)
132 #define DAC_GAIN_0_A (0<<11)
133 #define DAC_GAIN_1_A (1<<11)
134 #define ME_DAC_CONTROL_UPDATE 0x0012 // R | -
135 #define ME_DAC_DATA_A 0x0014 // - | W
136 #define ME_DAC_DATA_B 0x0016 // - | W
137 #define ME_DAC_DATA_C 0x0018 // - | W
138 #define ME_DAC_DATA_D 0x001A // - | W
139 #define ME_COUNTER_ENDDATA_A 0x001C // - | W
140 #define ME_COUNTER_ENDDATA_B 0x001E // - | W
141 #define ME_COUNTER_STARTDATA_A 0x0020 // - | W
142 #define ME_COUNTER_VALUE_A 0x0020 // R | -
143 #define ME_COUNTER_STARTDATA_B 0x0022 // - | W
144 #define ME_COUNTER_VALUE_B 0x0022 // R | -
147 // Function prototypes
150 static int me_attach(comedi_device *dev, comedi_devconfig *it);
151 static int me_detach(comedi_device *dev);
153 static comedi_lrange me2000_ai_range=
168 static comedi_lrange me2600_ai_range=
183 static comedi_lrange me2600_ao_range=
193 static struct pci_device_id me_pci_table[] __devinitdata =
195 { PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
196 { PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
199 MODULE_DEVICE_TABLE(pci, me_pci_table);
202 // Board specification structure
207 const char *name; // driver name
209 int ao_channel_nbr; // DA config
211 int ao_resolution_mask;
212 comedi_lrange *ao_range_list;
213 int ai_channel_nbr; // AD config
215 int ai_resolution_mask;
216 comedi_lrange *ai_range_list;
217 int dio_channel_nbr; // DIO config
220 static me_board_struct me_boards[] =
223 name: ME_DRIVER_NAME,
224 device_id: ME2600_DEVICE_ID,
225 ao_channel_nbr: 4, // Analog Output
227 ao_resolution_mask: 0x0fff,
228 ao_range_list: &me2600_ao_range,
229 ai_channel_nbr: 16, // Analog Input
231 ai_resolution_mask: 0x0fff,
232 ai_range_list: &me2600_ai_range,
236 name: ME_DRIVER_NAME,
237 device_id: ME2000_DEVICE_ID,
238 ao_channel_nbr: 0, // Analog Output
240 ao_resolution_mask: 0,
242 ai_channel_nbr: 16, // Analog Input
244 ai_resolution_mask: 0x0fff,
245 ai_range_list: &me2000_ai_range,
250 #define me_board_nbr (sizeof(me_boards)/sizeof(me_board_struct))
252 static comedi_driver me_driver=
254 driver_name: ME_DRIVER_NAME,
258 num_names: me_board_nbr,
259 board_name: &me_boards[0].name,
260 offset: sizeof(me_board_struct),
262 COMEDI_INITCLEANUP(me_driver);
265 // Private data structure
270 struct pci_dev* pci_device;
271 void *plx_regbase; // PLX configuration base address
272 void *me_regbase; // Base address of the Meilhaus card
273 unsigned long plx_regbase_size; // Size of PLX configuration space
274 unsigned long me_regbase_size; // Size of Meilhaus space
276 unsigned short control_1; // Mirror of CONTROL_1 register
277 unsigned short control_2; // Mirror of CONTROL_2 register
278 unsigned short dac_control; // Mirror of the DAC_CONTROL register
279 int ao_readback[4]; // Mirror of analog output data
281 } me_private_data_struct;
283 #define dev_private ((me_private_data_struct *)dev->private)
285 // ------------------------------------------------------------------
289 // ------------------------------------------------------------------
291 static __inline__ void sleep(unsigned sec)
293 current->state = TASK_INTERRUPTIBLE;
294 schedule_timeout(sec*HZ);
297 // ------------------------------------------------------------------
299 // DIGITAL INPUT/OUTPUT SECTION
301 // ------------------------------------------------------------------
303 static int me_dio_insn_config(comedi_device *dev,
309 int mask = 1 << CR_CHAN(insn->chanspec);
312 if(mask & 0x0000ffff) /* Port A in use */
317 dev_private->control_2 |= ENABLE_PORT_A;
318 writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
320 else /* Port B in use */
325 dev_private->control_2 |= ENABLE_PORT_B;
326 writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
330 if(data[0]) /* Config port as output */
334 else /* Config port as input */
343 // Digital instant input/outputs
346 static int me_dio_insn_bits(comedi_device *dev,
351 unsigned int mask = data[0];
353 s->state |= (mask & data[1]);
356 if(mask & 0x0000ffff) /* Port A */
358 writew((s->state & 0xffff), dev_private->me_regbase + ME_DIO_PORT_A);
362 data[1] &= ~0x0000ffff;
363 data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_A);
366 if(mask & 0xffff0000) /* Port B */
368 writew(((s->state >> 16) & 0xffff), dev_private->me_regbase + ME_DIO_PORT_B);
372 data[1] &= ~0xffff0000;
373 data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_B) << 16;
379 // ------------------------------------------------------------------
381 // ANALOG INPUT SECTION
383 // ------------------------------------------------------------------
386 // Analog instant input
388 static int me_ai_insn_read(comedi_device *dev,
389 comedi_subdevice *subdevice,
393 unsigned short value;
394 int chan = CR_CHAN((&insn->chanspec)[0]);
395 int rang = CR_RANGE((&insn->chanspec)[0]);
396 int aref = CR_AREF((&insn->chanspec)[0]);
399 /* stop any running conversion */
400 dev_private->control_1 &= 0xFFFC;
401 writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
403 /* clear chanlist and ad fifo */
404 dev_private->control_2 &= ~(ENABLE_ADFIFO | ENABLE_CHANLIST);
405 writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
407 /* reset any pending interrupt */
408 writew(0x00, dev_private->me_regbase + ME_RESET_INTERRUPT);
410 /* enable the chanlist and ADC fifo */
411 dev_private->control_2 |= (ENABLE_ADFIFO | ENABLE_CHANLIST);
412 writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
414 /* write to channel list fifo */
415 value = chan & 0x0f; // b3:b0 are the channel number
416 value |= (rang & 0x03) << 4; // b5:b4 are the channel gain
417 value |= (rang & 0x04) << 4; // b6 channel polarity
418 value |= ((aref & AREF_DIFF) ? 0x80 : 0); // b7 single or differential
419 writew(value & 0xff, dev_private->me_regbase + ME_CHANNEL_LIST);
421 /* set ADC mode to software trigger */
422 dev_private->control_1 |= SOFTWARE_TRIGGERED_ADC;
423 writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
425 /* start conversion by reading from ADC_START */
426 readw(dev_private->me_regbase + ME_ADC_START);
428 /* wait for ADC fifo not empty flag */
429 for(i = 100000; i > 0; i--)
431 if(!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004))
437 /* get value from ADC fifo*/
440 data[0] = (readw(dev_private->me_regbase + ME_READ_AD_FIFO) ^ 0x800) & 0x0FFF;
444 printk("comedi%d: Cannot get single value\n", dev->minor);
448 /* stop any running conversion */
449 dev_private->control_1 &= 0xFFFC;
450 writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
456 // ------------------------------------------------------------------
458 // HARDWARE TRIGGERED ANALOG INPUT SECTION
460 // ------------------------------------------------------------------
463 // Cancel analog input autoscan
465 static int me_ai_cancel(comedi_device *dev,
468 /* disable interrupts */
470 /* stop any running conversion */
471 dev_private->control_1 &= 0xFFFC;
472 writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
478 // Test analog input command
480 static int me_ai_do_cmd_test(comedi_device *dev,
488 // Analog input command
490 static int me_ai_do_cmd(comedi_device *dev,
491 comedi_subdevice *subdevice)
496 // ------------------------------------------------------------------
498 // ANALOG OUTPUT SECTION
500 // ------------------------------------------------------------------
503 // Analog instant output
505 static int me_ao_insn_write(comedi_device *dev,
515 dev_private->control_2 |= ENABLE_DAC;
516 writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
518 /* and set DAC to "buffered" mode */
519 dev_private->control_2 |= BUFFERED_DAC;
520 writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
522 /* Set dac-control register */
523 for (i=0; i < insn->n; i++)
525 chan = CR_CHAN((&insn->chanspec)[i]);
526 rang = CR_RANGE((&insn->chanspec)[i]);
528 dev_private->dac_control &= ~(0x0880 >> chan); /* clear bits for this channel */
530 dev_private->dac_control |= ((DAC_BIPOLAR_A | DAC_GAIN_1_A) >> chan);
532 dev_private->dac_control |= ((DAC_BIPOLAR_A | DAC_GAIN_0_A) >> chan);
534 writew(dev_private->dac_control, dev_private->me_regbase + ME_DAC_CONTROL);
536 /* Update dac-control register */
537 readw(dev_private->me_regbase + ME_DAC_CONTROL_UPDATE);
539 /* Set data register */
540 for (i=0; i < insn->n; i++)
542 chan = CR_CHAN((&insn->chanspec)[i]);
543 writew((data[0] & s->maxdata), dev_private->me_regbase + ME_DAC_DATA_A + (chan<<1));
544 dev_private->ao_readback[chan] = (data[0] & s->maxdata);
547 /* Update dac with data registers */
548 readw(dev_private->me_regbase + ME_DAC_UPDATE);
554 // Analog output readback
556 static int me_ao_insn_read(comedi_device * dev,
563 for (i=0; i < insn->n; i++)
565 data[i] = dev_private->ao_readback[CR_CHAN((&insn->chanspec)[i])];
571 // ------------------------------------------------------------------
573 // INITIALISATION SECTION
575 // ------------------------------------------------------------------
578 // Xilinx firmware download for card: ME-2600i
581 static int me2600_xilinx_download(comedi_device *dev, unsigned char
582 *me2600_firmware, unsigned int length)
585 unsigned int file_length;
588 /* disable irq's on PLX */
589 writel(0x00, dev_private->plx_regbase + PLX_INTCSR);
591 /* First, make a dummy read to reset xilinx */
592 value = readw(dev_private->me_regbase + XILINX_DOWNLOAD_RESET);
594 /* Wait until reset is over */
597 /* Write a dummy value to Xilinx */
598 writeb(0x00, dev_private->me_regbase + 0x0);
602 * Format of the firmware
603 * Build longs from the byte-wise coded header
604 * Byte 1-3: length of the array
607 * Byte 12-15: reserved
609 if(length<16)return -EINVAL;
611 (((unsigned int)me2600_firmware[0] & 0xff)<<24) +
612 (((unsigned int)me2600_firmware[1] & 0xff)<<16) +
613 (((unsigned int)me2600_firmware[2] & 0xff)<< 8) +
614 ((unsigned int)me2600_firmware[3] & 0xff);
617 * Loop for writing firmware byte by byte to xilinx
618 * Firmware data start at offfset 16
620 for(i = 0; i < file_length; i++)
622 writeb((me2600_firmware[16+i] & 0xff), dev_private->me_regbase + 0x0);
625 /* Write 5 dummy values to xilinx */
626 for(i = 0; i < 5; i++)
628 writeb(0x00, dev_private->me_regbase + 0x0);
631 /* Test if there was an error during download -> INTB was thrown */
632 value = readl(dev_private->plx_regbase + PLX_INTCSR);
635 /* Disable interrupt */
636 writel(0x00, dev_private->plx_regbase + PLX_INTCSR);
637 printk("comedi%d: Xilinx download failed\n", dev->minor);
641 /* Wait until the Xilinx is ready for real work */
644 /* Enable PLX-Interrupts */
645 writel(0x43, dev_private->plx_regbase + PLX_INTCSR);
654 static int me_reset(comedi_device *dev)
657 writew(0x00, dev_private->me_regbase + ME_CONTROL_1);
658 writew(0x00, dev_private->me_regbase + ME_CONTROL_2);
659 writew(0x00, dev_private->me_regbase + ME_RESET_INTERRUPT);
660 writew(0x00, dev_private->me_regbase + ME_DAC_CONTROL);
662 /* Save values in the board context */
663 dev_private->dac_control = 0;
664 dev_private->control_1 = 0;
665 dev_private->control_2 = 0;
673 // - Register PCI device
674 // - Declare device driver capability
677 static int me_attach(comedi_device *dev,comedi_devconfig *it)
679 struct pci_dev* pci_device;
680 comedi_subdevice *subdevice;
681 me_board_struct* board;
682 resource_size_t plx_regbase_tmp;
683 unsigned long plx_regbase_size_tmp;
684 resource_size_t me_regbase_tmp;
685 unsigned long me_regbase_size_tmp;
686 resource_size_t swap_regbase_tmp;
687 unsigned long swap_regbase_size_tmp;
688 resource_size_t regbase_tmp;
689 int result, error, i;
691 // Allocate private memory
692 if(alloc_private(dev,sizeof(me_private_data_struct)) < 0)
698 // Probe the device to determine what device in the series it is.
700 for(pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pci_device != NULL ;
701 pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device))
703 if(pci_device->vendor == PCI_VENDOR_ID_MEILHAUS)
705 for(i = 0; i < me_board_nbr; i++)
707 if(me_boards[i].device_id == pci_device->device)
709 // was a particular bus/slot requested?
710 if((it->options[0] != 0) || (it->options[1] != 0))
712 // are we on the wrong bus/slot?
713 if(pci_device->bus->number != it->options[0] ||
714 PCI_SLOT(pci_device->devfn) != it->options[1])
720 dev->board_ptr = me_boards + i;
721 board = (me_board_struct *) dev->board_ptr;
722 dev_private->pci_device = pci_device;
729 printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
730 dev->minor,it->options[0], it->options[1]);
735 printk("comedi%d: found %s at PCI bus %d, slot %d\n",
736 dev->minor, me_boards[i].name,
737 pci_device->bus->number, PCI_SLOT(pci_device->devfn));
740 if(pci_enable_device(pci_device) < 0)
742 printk("comedi%d: Failed to enable PCI device\n", dev->minor);
746 // Request PCI regions
747 if(pci_request_regions(pci_device, ME_DRIVER_NAME) < 0)
749 printk("comedi%d: I/O memory conflict\n", dev->minor);
753 // Set data in device structure
755 dev->board_name = board->name;
757 // Read PLX register base address [PCI_BASE_ADDRESS #0].
759 plx_regbase_tmp = pci_resource_start(pci_device, 0);
760 plx_regbase_size_tmp = pci_resource_len(pci_device, 0);
761 dev_private->plx_regbase = ioremap(plx_regbase_tmp, plx_regbase_size_tmp);
762 dev_private->plx_regbase_size = plx_regbase_size_tmp;
763 if(!dev_private->plx_regbase)
765 printk("comedi%d: Failed to remap I/O memory\n", dev->minor);
769 // Read Swap base address [PCI_BASE_ADDRESS #5].
771 swap_regbase_tmp = pci_resource_start(pci_device, 5);
772 swap_regbase_size_tmp = pci_resource_len(pci_device, 5);
774 if(!swap_regbase_tmp)
776 printk("comedi%d: Swap not present\n", dev->minor);
779 /*----------------------------------------------------- Workaround start ---*/
780 if(plx_regbase_tmp & 0x0080)
782 printk("comedi%d: PLX-Bug detected\n", dev->minor);
786 regbase_tmp = plx_regbase_tmp;
787 plx_regbase_tmp = swap_regbase_tmp;
788 swap_regbase_tmp = regbase_tmp;
790 result = pci_write_config_dword(pci_device, PCI_BASE_ADDRESS_0, plx_regbase_tmp);
791 if(result != PCIBIOS_SUCCESSFUL)
794 result = pci_write_config_dword(pci_device, PCI_BASE_ADDRESS_5, swap_regbase_tmp);
795 if(result != PCIBIOS_SUCCESSFUL)
800 plx_regbase_tmp -= 0x80;
801 result = pci_write_config_dword(pci_device, PCI_BASE_ADDRESS_0, plx_regbase_tmp);
802 if(result != PCIBIOS_SUCCESSFUL)
806 /*----------------------------------------------------- Workaround end -----*/
809 // Read Meilhaus register base address [PCI_BASE_ADDRESS #2].
811 me_regbase_tmp = pci_resource_start(pci_device, 2);
812 me_regbase_size_tmp = pci_resource_len(pci_device, 2);
813 dev_private->me_regbase_size = me_regbase_size_tmp;
814 dev_private->me_regbase = ioremap(me_regbase_tmp, me_regbase_size_tmp);
815 if(!dev_private->me_regbase)
817 printk("comedi%d: Failed to remap I/O memory\n", dev->minor);
821 // Download firmware and reset card
822 if(board->device_id == ME2600_DEVICE_ID)
824 unsigned char *aux_data;
827 aux_data = comedi_aux_data(it->options, 0);
828 aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
830 if(!aux_data || aux_len < 1)
832 comedi_error(dev, "You must provide me2600 firmware using the --init-data option of comedi_config");
835 me2600_xilinx_download(dev, aux_data, aux_len);
840 // device driver capabilities
842 if((error = alloc_subdevices(dev, 3)) < 0)
845 subdevice = dev->subdevices + 0;
846 subdevice->type = COMEDI_SUBD_AI;
847 subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
848 subdevice->n_chan = board->ai_channel_nbr;
849 subdevice->maxdata = board->ai_resolution_mask;
850 subdevice->len_chanlist = board->ai_channel_nbr;
851 subdevice->range_table = board->ai_range_list;
852 subdevice->cancel = me_ai_cancel;
853 subdevice->insn_read = me_ai_insn_read;
854 subdevice->do_cmdtest = me_ai_do_cmd_test;
855 subdevice->do_cmd = me_ai_do_cmd;
857 subdevice = dev->subdevices + 1;
858 subdevice->type = COMEDI_SUBD_AO;
859 subdevice->subdev_flags = SDF_WRITEABLE | SDF_COMMON;
860 subdevice->n_chan = board->ao_channel_nbr;
861 subdevice->maxdata = board->ao_resolution_mask;
862 subdevice->len_chanlist = board->ao_channel_nbr;
863 subdevice->range_table = board->ao_range_list;
864 subdevice->insn_read = me_ao_insn_read;
865 subdevice->insn_write = me_ao_insn_write;
867 subdevice = dev->subdevices + 2;
868 subdevice->type = COMEDI_SUBD_DIO;
869 subdevice->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
870 subdevice->n_chan = board->dio_channel_nbr;
871 subdevice->maxdata = 1;
872 subdevice->len_chanlist = board->dio_channel_nbr;
873 subdevice->range_table = &range_digital;
874 subdevice->insn_bits = me_dio_insn_bits;
875 subdevice->insn_config = me_dio_insn_config;
876 subdevice->io_bits = 0;
878 printk("comedi%d: " ME_DRIVER_NAME " attached.\n", dev->minor);
887 static int me_detach(comedi_device *dev)
891 if (dev_private->me_regbase)
894 iounmap(dev_private->me_regbase);
896 if (dev_private->plx_regbase)
897 iounmap(dev_private->plx_regbase);
898 if(dev_private->pci_device)
900 if(dev_private->plx_regbase_size)
902 pci_release_regions(dev_private->pci_device);
903 pci_disable_device(dev_private->pci_device);
905 pci_dev_put(dev_private->pci_device);