acl7225b.c revision 0dfd69bfdbf9de7021e81443c0c195f7da208a7d
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 52COMEDI_INITCLEANUP(driver_acl7225b); 53 54static int acl7225b_do_insn(struct comedi_device *dev, 55 struct comedi_subdevice *s, 56 struct comedi_insn *insn, unsigned int *data) 57{ 58 if (insn->n != 2) 59 return -EINVAL; 60 61 if (data[0]) { 62 s->state &= ~data[0]; 63 s->state |= (data[0] & data[1]); 64 } 65 if (data[0] & 0x00ff) 66 outb(s->state & 0xff, dev->iobase + (unsigned long)s->private); 67 if (data[0] & 0xff00) 68 outb((s->state >> 8), 69 dev->iobase + (unsigned long)s->private + 1); 70 71 data[1] = s->state; 72 73 return 2; 74} 75 76static int acl7225b_di_insn(struct comedi_device *dev, 77 struct comedi_subdevice *s, 78 struct comedi_insn *insn, unsigned int *data) 79{ 80 if (insn->n != 2) 81 return -EINVAL; 82 83 data[1] = inb(dev->iobase + (unsigned long)s->private) | 84 (inb(dev->iobase + (unsigned long)s->private + 1) << 8); 85 86 return 2; 87} 88 89static int acl7225b_attach(struct comedi_device *dev, 90 struct comedi_devconfig *it) 91{ 92 struct comedi_subdevice *s; 93 int iobase, iorange; 94 95 iobase = it->options[0]; 96 iorange = this_board->io_range; 97 printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor, 98 this_board->name, iobase); 99 if (!request_region(iobase, iorange, "acl7225b")) { 100 printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n", 101 dev->minor); 102 return -EIO; 103 } 104 dev->board_name = this_board->name; 105 dev->iobase = iobase; 106 dev->irq = 0; 107 108 if (alloc_subdevices(dev, 3) < 0) 109 return -ENOMEM; 110 111 s = dev->subdevices + 0; 112 /* Relays outputs */ 113 s->type = COMEDI_SUBD_DO; 114 s->subdev_flags = SDF_WRITABLE; 115 s->maxdata = 1; 116 s->n_chan = 16; 117 s->insn_bits = acl7225b_do_insn; 118 s->range_table = &range_digital; 119 s->private = (void *)ACL7225_RIO_LO; 120 121 s = dev->subdevices + 1; 122 /* Relays status */ 123 s->type = COMEDI_SUBD_DI; 124 s->subdev_flags = SDF_READABLE; 125 s->maxdata = 1; 126 s->n_chan = 16; 127 s->insn_bits = acl7225b_di_insn; 128 s->range_table = &range_digital; 129 s->private = (void *)ACL7225_RIO_LO; 130 131 s = dev->subdevices + 2; 132 /* Isolated digital inputs */ 133 s->type = COMEDI_SUBD_DI; 134 s->subdev_flags = SDF_READABLE; 135 s->maxdata = 1; 136 s->n_chan = 16; 137 s->insn_bits = acl7225b_di_insn; 138 s->range_table = &range_digital; 139 s->private = (void *)ACL7225_DI_LO; 140 141 return 0; 142} 143 144static int acl7225b_detach(struct comedi_device *dev) 145{ 146 printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor); 147 148 if (dev->iobase) 149 release_region(dev->iobase, this_board->io_range); 150 151 return 0; 152} 153