1/* 2 * comedi/drivers/acl7225b.c 3 * Driver for Adlink NuDAQ ACL-7225b and clones 4 * José Luis Sánchez 5 */ 6/* 7Driver: acl7225b 8Description: Adlink NuDAQ ACL-7225b & compatibles 9Author: José Luis Sánchez (jsanchezv@teleline.es) 10Status: testing 11Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio) 12*/ 13 14#include "../comedidev.h" 15 16#include <linux/ioport.h> 17 18#define ACL7225_SIZE 8 /* Requires 8 ioports, but only 4 are used */ 19#define P16R16DIO_SIZE 4 20#define ACL7225_RIO_LO 0 /* Relays input/output low byte (R0-R7) */ 21#define ACL7225_RIO_HI 1 /* Relays input/output high byte (R8-R15) */ 22#define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */ 23#define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */ 24 25static int acl7225b_attach(struct comedi_device *dev, 26 struct comedi_devconfig *it); 27static int acl7225b_detach(struct comedi_device *dev); 28 29struct boardtype { 30 const char *name; /* driver name */ 31 int io_range; /* len of I/O space */ 32}; 33 34static const struct boardtype boardtypes[] = { 35 {"acl7225b", ACL7225_SIZE,}, 36 {"p16r16dio", P16R16DIO_SIZE,}, 37}; 38 39#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) 40#define this_board ((const struct boardtype *)dev->board_ptr) 41 42static struct comedi_driver driver_acl7225b = { 43 .driver_name = "acl7225b", 44 .module = THIS_MODULE, 45 .attach = acl7225b_attach, 46 .detach = acl7225b_detach, 47 .board_name = &boardtypes[0].name, 48 .num_names = n_boardtypes, 49 .offset = sizeof(struct boardtype), 50}; 51 52static int __init driver_acl7225b_init_module(void) 53{ 54 return comedi_driver_register(&driver_acl7225b); 55} 56 57static void __exit driver_acl7225b_cleanup_module(void) 58{ 59 comedi_driver_unregister(&driver_acl7225b); 60} 61 62module_init(driver_acl7225b_init_module); 63module_exit(driver_acl7225b_cleanup_module); 64 65static int acl7225b_do_insn(struct comedi_device *dev, 66 struct comedi_subdevice *s, 67 struct comedi_insn *insn, unsigned int *data) 68{ 69 if (insn->n != 2) 70 return -EINVAL; 71 72 if (data[0]) { 73 s->state &= ~data[0]; 74 s->state |= (data[0] & data[1]); 75 } 76 if (data[0] & 0x00ff) 77 outb(s->state & 0xff, dev->iobase + (unsigned long)s->private); 78 if (data[0] & 0xff00) 79 outb((s->state >> 8), 80 dev->iobase + (unsigned long)s->private + 1); 81 82 data[1] = s->state; 83 84 return 2; 85} 86 87static int acl7225b_di_insn(struct comedi_device *dev, 88 struct comedi_subdevice *s, 89 struct comedi_insn *insn, unsigned int *data) 90{ 91 if (insn->n != 2) 92 return -EINVAL; 93 94 data[1] = inb(dev->iobase + (unsigned long)s->private) | 95 (inb(dev->iobase + (unsigned long)s->private + 1) << 8); 96 97 return 2; 98} 99 100static int acl7225b_attach(struct comedi_device *dev, 101 struct comedi_devconfig *it) 102{ 103 struct comedi_subdevice *s; 104 int iobase, iorange; 105 106 iobase = it->options[0]; 107 iorange = this_board->io_range; 108 printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor, 109 this_board->name, iobase); 110 if (!request_region(iobase, iorange, "acl7225b")) { 111 printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n", 112 dev->minor); 113 return -EIO; 114 } 115 dev->board_name = this_board->name; 116 dev->iobase = iobase; 117 dev->irq = 0; 118 119 if (alloc_subdevices(dev, 3) < 0) 120 return -ENOMEM; 121 122 s = dev->subdevices + 0; 123 /* Relays outputs */ 124 s->type = COMEDI_SUBD_DO; 125 s->subdev_flags = SDF_WRITABLE; 126 s->maxdata = 1; 127 s->n_chan = 16; 128 s->insn_bits = acl7225b_do_insn; 129 s->range_table = &range_digital; 130 s->private = (void *)ACL7225_RIO_LO; 131 132 s = dev->subdevices + 1; 133 /* Relays status */ 134 s->type = COMEDI_SUBD_DI; 135 s->subdev_flags = SDF_READABLE; 136 s->maxdata = 1; 137 s->n_chan = 16; 138 s->insn_bits = acl7225b_di_insn; 139 s->range_table = &range_digital; 140 s->private = (void *)ACL7225_RIO_LO; 141 142 s = dev->subdevices + 2; 143 /* Isolated digital inputs */ 144 s->type = COMEDI_SUBD_DI; 145 s->subdev_flags = SDF_READABLE; 146 s->maxdata = 1; 147 s->n_chan = 16; 148 s->insn_bits = acl7225b_di_insn; 149 s->range_table = &range_digital; 150 s->private = (void *)ACL7225_DI_LO; 151 152 return 0; 153} 154 155static int acl7225b_detach(struct comedi_device *dev) 156{ 157 printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor); 158 159 if (dev->iobase) 160 release_region(dev->iobase, this_board->io_range); 161 162 return 0; 163} 164 165MODULE_AUTHOR("Comedi http://www.comedi.org"); 166MODULE_DESCRIPTION("Comedi low-level driver"); 167MODULE_LICENSE("GPL"); 168