pcl730.c revision 71b5f4f11971dea972832ad63a994c7e5b45db6b
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, comedi_devconfig * it); 30static int pcl730_detach(struct comedi_device * dev); 31 32typedef struct { 33 const char *name; // board name 34 unsigned int io_range; // len of I/O space 35} boardtype; 36 37static const boardtype boardtypes[] = { 38 {"pcl730", PCL730_SIZE,}, 39 {"iso730", PCL730_SIZE,}, 40 {"acl7130", ACL7130_SIZE,}, 41}; 42 43#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype)) 44#define this_board ((const boardtype *)dev->board_ptr) 45 46static comedi_driver driver_pcl730 = { 47 driver_name:"pcl730", 48 module:THIS_MODULE, 49 attach:pcl730_attach, 50 detach:pcl730_detach, 51 board_name:&boardtypes[0].name, 52 num_names:n_boardtypes, 53 offset:sizeof(boardtype), 54}; 55 56COMEDI_INITCLEANUP(driver_pcl730); 57 58static int pcl730_do_insn(struct comedi_device * dev, comedi_subdevice * s, 59 comedi_insn * insn, unsigned int * data) 60{ 61 if (insn->n != 2) 62 return -EINVAL; 63 64 if (data[0]) { 65 s->state &= ~data[0]; 66 s->state |= (data[0] & data[1]); 67 } 68 if (data[0] & 0x00ff) 69 outb(s->state & 0xff, 70 dev->iobase + ((unsigned long)s->private)); 71 if (data[0] & 0xff00) 72 outb((s->state >> 8), 73 dev->iobase + ((unsigned long)s->private) + 1); 74 75 data[1] = s->state; 76 77 return 2; 78} 79 80static int pcl730_di_insn(struct comedi_device * dev, comedi_subdevice * s, 81 comedi_insn * insn, unsigned int * data) 82{ 83 if (insn->n != 2) 84 return -EINVAL; 85 86 data[1] = inb(dev->iobase + ((unsigned long)s->private)) | 87 (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8); 88 89 return 2; 90} 91 92static int pcl730_attach(struct comedi_device * dev, comedi_devconfig * it) 93{ 94 comedi_subdevice *s; 95 unsigned long iobase; 96 unsigned int iorange; 97 98 iobase = it->options[0]; 99 iorange = this_board->io_range; 100 printk("comedi%d: pcl730: board=%s 0x%04lx ", dev->minor, 101 this_board->name, iobase); 102 if (!request_region(iobase, iorange, "pcl730")) { 103 printk("I/O port conflict\n"); 104 return -EIO; 105 } 106 dev->board_name = this_board->name; 107 dev->iobase = iobase; 108 dev->irq = 0; 109 110 if (alloc_subdevices(dev, 4) < 0) 111 return -ENOMEM; 112 113 s = dev->subdevices + 0; 114 /* Isolated do */ 115 s->type = COMEDI_SUBD_DO; 116 s->subdev_flags = SDF_WRITABLE; 117 s->maxdata = 1; 118 s->n_chan = 16; 119 s->insn_bits = pcl730_do_insn; 120 s->range_table = &range_digital; 121 s->private = (void *)PCL730_IDIO_LO; 122 123 s = dev->subdevices + 1; 124 /* Isolated di */ 125 s->type = COMEDI_SUBD_DI; 126 s->subdev_flags = SDF_READABLE; 127 s->maxdata = 1; 128 s->n_chan = 16; 129 s->insn_bits = pcl730_di_insn; 130 s->range_table = &range_digital; 131 s->private = (void *)PCL730_IDIO_LO; 132 133 s = dev->subdevices + 2; 134 /* TTL do */ 135 s->type = COMEDI_SUBD_DO; 136 s->subdev_flags = SDF_WRITABLE; 137 s->maxdata = 1; 138 s->n_chan = 16; 139 s->insn_bits = pcl730_do_insn; 140 s->range_table = &range_digital; 141 s->private = (void *)PCL730_DIO_LO; 142 143 s = dev->subdevices + 3; 144 /* TTL di */ 145 s->type = COMEDI_SUBD_DI; 146 s->subdev_flags = SDF_READABLE; 147 s->maxdata = 1; 148 s->n_chan = 16; 149 s->insn_bits = pcl730_di_insn; 150 s->range_table = &range_digital; 151 s->private = (void *)PCL730_DIO_LO; 152 153 printk("\n"); 154 155 return 0; 156} 157 158static int pcl730_detach(struct comedi_device * dev) 159{ 160 printk("comedi%d: pcl730: remove\n", dev->minor); 161 162 if (dev->iobase) 163 release_region(dev->iobase, this_board->io_range); 164 165 return 0; 166} 167