2 * comedi/drivers/dt9812.c
3 * COMEDI driver for DataTranslation DT9812 USB module
5 * Copyright (C) 2005 Anders Blomdell <anders.blomdell@control.lth.se>
7 * COMEDI - Linux Control and Measurement Device Interface
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 Description: Data Translation DT9812 USB module
28 Author: anders.blomdell@control.lth.se (Anders Blomdell)
29 Status: in development
30 Devices: [Data Translation] DT9812 (dt9812)
31 Updated: Sun Nov 20 20:18:34 EST 2005
33 This driver works, but bulk transfers not implemented. Might be a starting point
34 for someone else. I found out too late that USB has too high latencies (>1 ms)
40 * 1. All writes to command pipe has to be 32 bytes (ISP1181B SHRTP=0 ?)
41 * 2. The DDK source (as of sep 2005) is in error regarding the
42 * input MUX bits (example code says P4, but firmware schematics
46 #include <linux/version.h>
47 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
49 #include <linux/config.h>
50 #include <linux/kernel.h>
51 #include <linux/errno.h>
52 #include <linux/init.h>
53 #include <linux/slab.h>
54 #include <linux/module.h>
55 #include <linux/kref.h>
56 #include <asm/uaccess.h>
57 #include <linux/usb.h>
58 #include <linux/comedidev.h>
62 #define DT9812_NUM_SLOTS 16
64 static DECLARE_MUTEX(dt9812_mutex);
66 static struct usb_device_id dt9812_table [] = {
67 { USB_DEVICE(0x0867, 0x9812) },
68 { } /* Terminating entry */
71 MODULE_DEVICE_TABLE (usb, dt9812_table);
73 typedef struct usb_dt9812 {
74 struct slot_dt9812 *slot;
75 struct usb_device *udev;
76 struct usb_interface *interface;
84 } message_pipe, command_write, command_read, write_stream, read_stream;
86 u16 analog_out_shadow[2];
87 u8 digital_out_shadow;
90 typedef struct comedi_dt9812 {
91 struct slot_dt9812 *slot;
95 typedef struct slot_dt9812 {
96 struct semaphore mutex;
99 comedi_dt9812_t *comedi;
102 static comedi_lrange dt9812_10_ain_range={ 1, {
107 static comedi_lrange dt9812_2pt5_ain_range={ 1, {
112 static comedi_lrange dt9812_10_aout_range={ 1, {
117 static comedi_lrange dt9812_2pt5_aout_range={ 1, {
122 static slot_dt9812_t dt9812[DT9812_NUM_SLOTS];
124 // Useful shorthand access to private data
125 #define devpriv ((comedi_dt9812_t *)dev->private)
128 static inline usb_dt9812_t *to_dt9812_dev(struct kref *d)
130 return container_of(d, usb_dt9812_t, kref);
133 static void dt9812_delete(struct kref *kref)
135 usb_dt9812_t *dev = to_dt9812_dev(kref);
137 usb_put_dev(dev->udev);
141 static int dt9812_read_info(usb_dt9812_t *dev,
142 int offset, void *buf, size_t buf_size)
144 dt9812_usb_cmd_t cmd;
147 cmd.cmd = cpu_to_le32(DT9812_R_FLASH_DATA);
148 cmd.u.flash_data_info.address =
149 cpu_to_le16(DT9812_DIAGS_BOARD_INFO_ADDR + offset);
150 cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size);
153 retval = usb_bulk_msg(dev->udev,
154 usb_sndbulkpipe(dev->udev, dev->command_write.addr),
156 32, // DT9812 only responds to 32 byte writes!!
159 retval = usb_bulk_msg(dev->udev,
160 usb_rcvbulkpipe(dev->udev, dev->command_read.addr),
168 static int dt9812_read_multiple_registers(usb_dt9812_t *dev,
173 dt9812_usb_cmd_t cmd;
174 int i, count, retval;
176 cmd.cmd = cpu_to_le32(DT9812_R_MULTI_BYTE_REG);
177 cmd.u.read_multi_info.count = reg_count;
178 for (i = 0 ; i < reg_count ; i++) {
179 cmd.u.read_multi_info.address[i] = address[i];
182 retval = usb_bulk_msg(dev->udev,
183 usb_sndbulkpipe(dev->udev, dev->command_write.addr),
185 32, // DT9812 only responds to 32 byte writes!!
188 retval = usb_bulk_msg(dev->udev,
189 usb_rcvbulkpipe(dev->udev, dev->command_read.addr),
197 static int dt9812_write_multiple_registers(usb_dt9812_t *dev,
203 dt9812_usb_cmd_t cmd;
204 int i, count, retval;
206 cmd.cmd = cpu_to_le32(DT9812_W_MULTI_BYTE_REG);
207 cmd.u.read_multi_info.count = reg_count;
208 for (i = 0 ; i < reg_count ; i++) {
209 cmd.u.write_multi_info.write[i].address = address[i];
210 cmd.u.write_multi_info.write[i].value = value[i];
212 retval = usb_bulk_msg(dev->udev,
213 usb_sndbulkpipe(dev->udev, dev->command_write.addr),
215 32, // DT9812 only responds to 32 byte writes!!
220 static int dt9812_rmw_multiple_registers(usb_dt9812_t *dev,
222 dt9812_rmw_byte_t rmw[])
224 dt9812_usb_cmd_t cmd;
225 int i, count, retval;
227 cmd.cmd = cpu_to_le32(DT9812_RMW_MULTI_BYTE_REG);
228 cmd.u.rmw_multi_info.count = reg_count;
229 for (i = 0 ; i < reg_count ; i++) {
230 cmd.u.rmw_multi_info.rmw[i] = rmw[i];
232 retval = usb_bulk_msg(dev->udev,
233 usb_sndbulkpipe(dev->udev, dev->command_write.addr),
235 32, // DT9812 only responds to 32 byte writes!!
240 static int dt9812_digital_in(slot_dt9812_t *slot, u8 *bits)
242 int result = -ENODEV;
246 u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 };
249 result = dt9812_read_multiple_registers(slot->usb, 2, reg, value);
251 // bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital input port
252 // bit 3 in F020_SFR_P1 is bit 7 in the digital input port
253 *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4);
254 // printk("%2.2x, %2.2x -> %2.2x\n", value[0], value[1], *bits);
262 static int dt9812_digital_out(slot_dt9812_t *slot, u8 bits)
264 int result = -ENODEV;
271 reg[0] = F020_SFR_P2;
273 result = dt9812_write_multiple_registers(slot->usb, 1, reg, value);
274 slot->usb->digital_out_shadow = bits;
280 static int dt9812_digital_out_shadow(slot_dt9812_t *slot, u8 *bits)
282 int result = -ENODEV;
286 *bits = slot->usb->digital_out_shadow;
293 static void dt9812_configure_mux(usb_dt9812_t *dev,
294 dt9812_rmw_byte_t *rmw,
297 if (dev->device == DT9812_DEVID_DT9812_10) {
298 // In the DT9812/10V MUX is selected by P1.5-7
299 rmw->address = F020_SFR_P1;
300 rmw->and_mask = 0xe0;
301 rmw->or_value = channel << 5;
303 // In the DT9812/2.5V, the internal mux is selected by bits 0:2
304 rmw->address = F020_SFR_AMX0SL;
305 rmw->and_mask = 0xff;
306 rmw->or_value = channel & 0x07;
310 static void dt9812_configure_gain(usb_dt9812_t *dev,
311 dt9812_rmw_byte_t *rmw,
314 if (dev->device == DT9812_DEVID_DT9812_10) {
315 // In the DT9812/10V, there is an external gain of 0.5
319 rmw->address = F020_SFR_ADC0CF;
321 F020_MASK_ADC0CF_AMP0GN2 |
322 F020_MASK_ADC0CF_AMP0GN1 |
323 F020_MASK_ADC0CF_AMP0GN0;
331 case DT9812_GAIN_0PT5: {
332 rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 || F020_MASK_ADC0CF_AMP0GN1;
334 case DT9812_GAIN_1: {
335 rmw->or_value = 0x00;
337 case DT9812_GAIN_2: {
338 rmw->or_value = F020_MASK_ADC0CF_AMP0GN0;
340 case DT9812_GAIN_4: {
341 rmw->or_value = F020_MASK_ADC0CF_AMP0GN1;
343 case DT9812_GAIN_8: {
344 rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 || F020_MASK_ADC0CF_AMP0GN0;
346 case DT9812_GAIN_16: {
347 rmw->or_value = F020_MASK_ADC0CF_AMP0GN2;
350 err("Illegal gain %d\n", gain);
355 static int dt9812_analog_in(slot_dt9812_t *slot,
360 int result = -ENODEV;
364 dt9812_rmw_byte_t rmw[3];
367 dt9812_configure_gain(slot->usb, &rmw[0], gain);
369 // 2 set the MUX to select the channel
370 dt9812_configure_mux(slot->usb, &rmw[1], channel);
372 // 3 start conversion
373 rmw[2].address = F020_SFR_ADC0CN;
374 rmw[2].and_mask = 0xff;
375 rmw[2].or_value = F020_MASK_ADC0CN_AD0EN | F020_MASK_ADC0CN_AD0BUSY;
378 result = dt9812_rmw_multiple_registers(slot->usb, 3, rmw);
380 // read the status and ADC
381 u8 reg[3] = { F020_SFR_ADC0CN, F020_SFR_ADC0H, F020_SFR_ADC0L };
383 result = dt9812_read_multiple_registers(slot->usb, 3, reg, val);
385 // An ADC conversion takes 16 SAR clocks cycles, i.e. about 9us.
386 // Therefore, between the instant that AD0BUSY was set via
387 // dt9812_rmw_multiple_registers and the read of AD0BUSY via
388 // dt9812_read_multiple_registers, the conversion
389 // should be complete since these two operations require two USB
390 // transactions each taking at least a millisecond to complete.
391 // However, lets make sure that conversion is finished.
392 if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) ==
393 F020_MASK_ADC0CN_AD0INT) {
394 switch (slot->usb->device) {
395 case DT9812_DEVID_DT9812_10: {
396 // For DT9812-10V the personality module set the encoding to 2's
397 // complement. Hence, convert it before returning it
398 *value = ((val[1] << 8) | val[2]) + 0x800;
400 case DT9812_DEVID_DT9812_2PT5: {
401 *value = (val[1] << 8) | val[2];
412 static int dt9812_analog_out_shadow(slot_dt9812_t *slot, int channel,
415 int result = -ENODEV;
419 *value = slot->usb->analog_out_shadow[channel];
427 static int dt9812_analog_out(slot_dt9812_t *slot, int channel, u16 value)
429 int result = -ENODEV;
433 dt9812_rmw_byte_t rmw[3];
438 rmw[0].address = F020_SFR_DAC0CN;
439 rmw[0].and_mask = 0xff;
440 rmw[0].or_value = F020_MASK_DACxCN_DACxEN;
442 // 2 load low byte of DAC value first
443 rmw[1].address = F020_SFR_DAC0L;
444 rmw[1].and_mask = 0xff;
445 rmw[1].or_value = value & 0xff;
447 // 3 load high byte of DAC value next to latch the 12-bit value
448 rmw[2].address = F020_SFR_DAC0H;
449 rmw[2].and_mask = 0xff;
450 rmw[2].or_value = (value >> 8) & 0xf;
454 rmw[0].address = F020_SFR_DAC1CN;
455 rmw[0].and_mask = 0xff;
456 rmw[0].or_value = F020_MASK_DACxCN_DACxEN;
458 // 2 load low byte of DAC value first
459 rmw[1].address = F020_SFR_DAC1L;
460 rmw[1].and_mask = 0xff;
461 rmw[1].or_value = value & 0xff;
463 // 3 load high byte of DAC value next to latch the 12-bit value
464 rmw[2].address = F020_SFR_DAC1H;
465 rmw[2].and_mask = 0xff;
466 rmw[2].or_value = (value >> 8) & 0xf;
469 result = dt9812_rmw_multiple_registers(slot->usb, 3, rmw);
470 slot->usb->analog_out_shadow[channel] = value;
478 * USB framework functions
481 static int dt9812_probe(struct usb_interface *interface,
482 const struct usb_device_id *id)
484 int retval = -ENOMEM;
485 usb_dt9812_t *dev = NULL;
486 struct usb_host_interface *iface_desc;
487 struct usb_endpoint_descriptor *endpoint;
491 // allocate memory for our device state and initialize it
492 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
494 err("Out of memory");
497 memset(dev, 0x00, sizeof(*dev));
498 KREF_INIT(&dev->kref, dt9812_delete);
500 dev->udev = usb_get_dev(interface_to_usbdev(interface));
501 dev->interface = interface;
504 iface_desc = interface->cur_altsetting;
506 if (iface_desc->desc.bNumEndpoints != 5) {
507 err("Wrong number of endpints.");
512 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
514 endpoint = &iface_desc->endpoint[i].desc;
517 direction = USB_DIR_IN;
518 dev->message_pipe.addr = endpoint->bEndpointAddress;
519 dev->message_pipe.size = le16_to_cpu(endpoint->wMaxPacketSize);
522 direction = USB_DIR_OUT;
523 dev->command_write.addr = endpoint->bEndpointAddress;
524 dev->command_write.size = le16_to_cpu(endpoint->wMaxPacketSize);
527 direction = USB_DIR_IN;
528 dev->command_read.addr = endpoint->bEndpointAddress;
529 dev->command_read.size = le16_to_cpu(endpoint->wMaxPacketSize);
532 direction = USB_DIR_OUT;
533 dev->write_stream.addr = endpoint->bEndpointAddress;
534 dev->write_stream.size = le16_to_cpu(endpoint->wMaxPacketSize);
537 direction = USB_DIR_IN;
538 dev->read_stream.addr = endpoint->bEndpointAddress;
539 dev->read_stream.size = le16_to_cpu(endpoint->wMaxPacketSize);
542 if ((endpoint->bEndpointAddress & USB_DIR_IN) != direction) {
543 err("Endpoint has wrong direction.");
548 if (dt9812_read_info(dev, 0, &fw, sizeof(fw)) != 0) {
549 // Seems like a configuration reset is necessary if driver
550 // is reloaded while device is attached
553 usb_reset_configuration(dev->udev);
554 for (i = 0 ; i < 10 ; i++) {
555 retval = dt9812_read_info(dev, 1, &fw, sizeof(fw));
557 printk("usb_reset_configuration succeded after %d iterations\n", i);
563 if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) {
564 err("Failed to read vendor.");
568 if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) {
569 err("Failed to read product.");
573 if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) {
574 err("Failed to read device.");
578 if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) {
579 err("Failed to read serial.");
584 dev->vendor = le16_to_cpu(dev->vendor);
585 dev->product = le16_to_cpu(dev->product);
586 dev->device = le16_to_cpu(dev->device);
587 dev->serial = le32_to_cpu(dev->serial);
588 switch (dev->device) {
589 case DT9812_DEVID_DT9812_10: {
590 dev->analog_out_shadow[0] = 0x0800;
591 dev->analog_out_shadow[1] = 0x800;
593 case DT9812_DEVID_DT9812_2PT5: {
594 dev->analog_out_shadow[0] = 0x0000;
595 dev->analog_out_shadow[1] = 0x0000;
598 dev->digital_out_shadow = 0;
600 // save our data pointer in this interface device a
601 usb_set_intfdata(interface, dev);
603 // let the user know what node this device is now attached to
604 info("USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x",
605 dev->vendor, dev->product, dev->device, dev->serial);
609 // Find a slot for the USB device
610 slot_dt9812_t *first = NULL;
611 slot_dt9812_t *best = NULL;
613 for (i = 0 ; i < DT9812_NUM_SLOTS ; i++) {
614 if (!first && !dt9812[i].usb && dt9812[i].serial == 0) {
617 if (!best && dt9812[i].serial == dev->serial) {
639 KREF_PUT(&dev->kref, dt9812_delete);
644 static void dt9812_disconnect(struct usb_interface *interface)
647 int minor = interface->minor;
650 dev = usb_get_intfdata(interface);
652 down(&dev->slot->mutex);
653 dev->slot->usb = NULL;
654 up(&dev->slot->mutex);
657 usb_set_intfdata(interface, NULL);
660 /* queue final destruction */
661 KREF_PUT(&dev->kref, dt9812_delete);
663 info("USB Dt9812 #%d now disconnected", minor);
666 static struct usb_driver dt9812_usb_driver = {
667 #ifdef COMEDI_HAVE_USB_DRIVER_OWNER
668 .owner = THIS_MODULE,
671 .probe = dt9812_probe,
672 .disconnect = dt9812_disconnect,
673 .id_table = dt9812_table,
680 static void dt9812_comedi_open(comedi_device *dev) {
681 down(&devpriv->slot->mutex);
682 if (devpriv->slot->usb) {
683 // We have an attached device, fill in current range info
686 s = &dev->subdevices[0];
690 s = &dev->subdevices[1];
694 s = &dev->subdevices[2];
696 switch (devpriv->slot->usb->device) {
699 s->range_table = &dt9812_10_ain_range;
703 s->range_table = &dt9812_2pt5_ain_range;
707 s = &dev->subdevices[3];
709 switch (devpriv->slot->usb->device) {
712 s->range_table = &dt9812_10_aout_range;
716 s->range_table = &dt9812_2pt5_aout_range;
720 up(&devpriv->slot->mutex);
723 static int dt9812_di_rinsn(comedi_device *dev, comedi_subdevice *s,
724 comedi_insn *insn, lsampl_t *data)
729 dt9812_digital_in(devpriv->slot, &bits);
730 for(n = 0 ; n < insn->n ; n++){
731 data[n] = ((1<<insn->chanspec) & bits) != 0;
736 static int dt9812_do_winsn(comedi_device *dev, comedi_subdevice *s,
737 comedi_insn *insn, lsampl_t *data)
742 dt9812_digital_out_shadow(devpriv->slot, &bits);
743 for(n = 0 ; n < insn->n ; n++){
744 u8 mask = 1<<insn->chanspec;
751 dt9812_digital_out(devpriv->slot, bits);
756 static int dt9812_ai_rinsn(comedi_device *dev, comedi_subdevice *s,
757 comedi_insn *insn, lsampl_t *data)
761 for(n = 0 ; n < insn->n ; n++){
764 dt9812_analog_in(devpriv->slot, insn->chanspec, &value, DT9812_GAIN_1);
771 static int dt9812_ao_rinsn(comedi_device *dev, comedi_subdevice *s,
772 comedi_insn *insn, lsampl_t *data)
776 for(n = 0 ; n < insn->n ; n++){
779 dt9812_analog_out_shadow(devpriv->slot, insn->chanspec, &value);
786 static int dt9812_ao_winsn(comedi_device *dev, comedi_subdevice *s,
787 comedi_insn *insn, lsampl_t *data)
791 for(n = 0 ; n < insn->n ; n++){
792 dt9812_analog_out(devpriv->slot, insn->chanspec, data[n]);
798 static int dt9812_attach(comedi_device *dev, comedi_devconfig *it)
803 dev->board_name = "dt9812";
805 if(alloc_private(dev,sizeof(comedi_dt9812_t)) < 0) {
809 // Special open routine, since USB unit may be unattached at
810 // comedi_config time, hence range can not be determined
811 dev->open = dt9812_comedi_open;
813 devpriv->serial = it->options[0];
815 // Allocate subdevices
816 if(alloc_subdevices(dev, 4) < 0) {
820 /* digital input subdevice */
821 s = dev->subdevices+0;
822 s->type = COMEDI_SUBD_DI;
823 s->subdev_flags = SDF_READABLE;
826 s->range_table = &range_digital;
827 s->insn_read = &dt9812_di_rinsn;
829 /* digital output subdevice */
830 s = dev->subdevices+1;
831 s->type = COMEDI_SUBD_DO;
832 s->subdev_flags = SDF_WRITEABLE;
835 s->range_table = &range_digital;
836 s->insn_write = &dt9812_do_winsn;
838 /* analog input subdevice */
840 s->type = COMEDI_SUBD_AI;
841 s->subdev_flags = SDF_READABLE|SDF_GROUND;
845 s->insn_read = &dt9812_ai_rinsn;
847 /* analog output subdevice */
849 s->type = COMEDI_SUBD_AO;
850 s->subdev_flags = SDF_WRITEABLE;
854 s->insn_write = &dt9812_ao_winsn;
855 s->insn_read = &dt9812_ao_rinsn;
857 printk("comedi%d: successfully attached to dt9812.\n",
861 // Find a slot for the comedi device
863 slot_dt9812_t *first = NULL;
864 slot_dt9812_t *best = NULL;
865 for (i = 0 ; i < DT9812_NUM_SLOTS ; i++) {
866 if (!first && !dt9812[i].comedi) {
867 // First free slot from comedi side
871 dt9812[i].usb && dt9812[i].usb->serial == devpriv->serial) {
872 // We have an attaced device with matching ID
881 best->comedi = devpriv;
882 best->serial = devpriv->serial;
883 devpriv->slot = best;
892 static int dt9812_detach(comedi_device *dev)
898 static comedi_driver dt9812_comedi_driver = {
899 .module = THIS_MODULE,
900 .driver_name = "dt9812",
901 .attach = dt9812_attach,
902 .detach= dt9812_detach,
905 static int __init usb_dt9812_init(void)
909 // Initialize all driver slots
910 for (i = 0 ; i < DT9812_NUM_SLOTS ; i++) {
911 init_MUTEX(&dt9812[i].mutex);
912 dt9812[i].serial = 0;
913 dt9812[i].usb = NULL;
914 dt9812[i].comedi = NULL;
916 dt9812[12].serial = 0x0;
918 // register with the USB subsystem
919 result = usb_register(&dt9812_usb_driver);
921 err("usb_register failed. Error number %d", result);
924 // register with comedi
925 result = comedi_driver_register(&dt9812_comedi_driver);
927 usb_deregister(&dt9812_usb_driver);
928 err("comedi_driver_register failed. Error number %d", result);
934 static void __exit usb_dt9812_exit(void)
936 // unregister with comedi
937 comedi_driver_unregister(&dt9812_comedi_driver);
939 /* deregister this driver with the USB subsystem */
940 usb_deregister(&dt9812_usb_driver);
943 module_init (usb_dt9812_init);
944 module_exit (usb_dt9812_exit);
946 MODULE_AUTHOR("Anders Blomdell <anders.blomdell@control.lth.se>");
947 MODULE_DESCRIPTION("Comedi DT9812 driver");
948 MODULE_LICENSE("GPL");
950 #endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)