pcl730.c revision 2696fb57e6af653dd8b4df41b16754579f42fc78
1/* 2 * comedi/drivers/pcl730.c 3 * Driver for Advantech PCL-730 and clones 4 * José Luis Sánchez 5 */ 6/* 7Driver: pcl730 8Description: Advantech PCL-730 (& compatibles) 9Author: José Luis Sánchez (jsanchezv@teleline.es) 10Status: untested 11Devices: [Advantech] PCL-730 (pcl730), [ICP] ISO-730 (iso730), 12 [Adlink] ACL-7130 (acl7130) 13 14Interrupts are not supported. 15The ACL-7130 card have an 8254 timer/counter not supported by this driver. 16*/ 17 18#include "../comedidev.h" 19 20#include <linux/ioport.h> 21 22#define PCL730_SIZE 4 23#define ACL7130_SIZE 8 24#define PCL730_IDIO_LO 0 /* Isolated Digital I/O low byte (ID0-ID7) */ 25#define PCL730_IDIO_HI 1 /* Isolated Digital I/O high byte (ID8-ID15) */ 26#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */ 27#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */ 28 29static int pcl730_attach(struct comedi_device * dev, struct comedi_devconfig * it); 30static int pcl730_detach(struct comedi_device * dev); 31 32struct pcl730_board { 33 34 const char *name; /* board name */ 35 unsigned int io_range; /* len of I/O space */ 36}; 37 38 39static const struct pcl730_board boardtypes[] = { 40 {"pcl730", PCL730_SIZE,}, 41 {"iso730", PCL730_SIZE,}, 42 {"acl7130", ACL7130_SIZE,}, 43}; 44 45#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board)) 46#define this_board ((const struct pcl730_board *)dev->board_ptr) 47 48static struct comedi_driver driver_pcl730 = { 49 driver_name:"pcl730", 50 module:THIS_MODULE, 51 attach:pcl730_attach, 52 detach:pcl730_detach, 53 board_name:&boardtypes[0].name, 54 num_names:n_boardtypes, 55 offset:sizeof(struct pcl730_board), 56}; 57 58COMEDI_INITCLEANUP(driver_pcl730); 59 60static int pcl730_do_insn(struct comedi_device * dev, struct comedi_subdevice * s, 61 struct comedi_insn * insn, unsigned int * data) 62{ 63 if (insn->n != 2) 64 return -EINVAL; 65 66 if (data[0]) { 67 s->state &= ~data[0]; 68 s->state |= (data[0] & data[1]); 69 } 70 if (data[0] & 0x00ff) 71 outb(s->state & 0xff, 72 dev->iobase + ((unsigned long)s->private)); 73 if (data[0] & 0xff00) 74 outb((s->state >> 8), 75 dev->iobase + ((unsigned long)s->private) + 1); 76 77 data[1] = s->state; 78 79 return 2; 80} 81 82static int pcl730_di_insn(struct comedi_device * dev, struct comedi_subdevice * s, 83 struct comedi_insn * insn, unsigned int * data) 84{ 85 if (insn->n != 2) 86 return -EINVAL; 87 88 data[1] = inb(dev->iobase + ((unsigned long)s->private)) | 89 (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8); 90 91 return 2; 92} 93 94static int pcl730_attach(struct comedi_device * dev, struct comedi_devconfig * it) 95{ 96 struct comedi_subdevice *s; 97 unsigned long iobase; 98 unsigned int iorange; 99 100 iobase = it->options[0]; 101 iorange = this_board->io_range; 102 printk("comedi%d: pcl730: board=%s 0x%04lx ", dev->minor, 103 this_board->name, iobase); 104 if (!request_region(iobase, iorange, "pcl730")) { 105 printk("I/O port conflict\n"); 106 return -EIO; 107 } 108 dev->board_name = this_board->name; 109 dev->iobase = iobase; 110 dev->irq = 0; 111 112 if (alloc_subdevices(dev, 4) < 0) 113 return -ENOMEM; 114 115 s = dev->subdevices + 0; 116 /* Isolated do */ 117 s->type = COMEDI_SUBD_DO; 118 s->subdev_flags = SDF_WRITABLE; 119 s->maxdata = 1; 120 s->n_chan = 16; 121 s->insn_bits = pcl730_do_insn; 122 s->range_table = &range_digital; 123 s->private = (void *)PCL730_IDIO_LO; 124 125 s = dev->subdevices + 1; 126 /* Isolated di */ 127 s->type = COMEDI_SUBD_DI; 128 s->subdev_flags = SDF_READABLE; 129 s->maxdata = 1; 130 s->n_chan = 16; 131 s->insn_bits = pcl730_di_insn; 132 s->range_table = &range_digital; 133 s->private = (void *)PCL730_IDIO_LO; 134 135 s = dev->subdevices + 2; 136 /* TTL do */ 137 s->type = COMEDI_SUBD_DO; 138 s->subdev_flags = SDF_WRITABLE; 139 s->maxdata = 1; 140 s->n_chan = 16; 141 s->insn_bits = pcl730_do_insn; 142 s->range_table = &range_digital; 143 s->private = (void *)PCL730_DIO_LO; 144 145 s = dev->subdevices + 3; 146 /* TTL di */ 147 s->type = COMEDI_SUBD_DI; 148 s->subdev_flags = SDF_READABLE; 149 s->maxdata = 1; 150 s->n_chan = 16; 151 s->insn_bits = pcl730_di_insn; 152 s->range_table = &range_digital; 153 s->private = (void *)PCL730_DIO_LO; 154 155 printk("\n"); 156 157 return 0; 158} 159 160static int pcl730_detach(struct comedi_device * dev) 161{ 162 printk("comedi%d: pcl730: remove\n", dev->minor); 163 164 if (dev->iobase) 165 release_region(dev->iobase, this_board->io_range); 166 167 return 0; 168} 169