219
206
#define devpriv ((struct pcmuio_private *)dev->private)
220
207
#define subpriv ((struct pcmuio_subdev_private *)s->private)
222
* The struct comedi_driver structure tells the Comedi core module
223
* which functions to call to configure/deconfigure (attach/detach)
224
* the board, and also about the kernel module that contains
227
static int pcmuio_attach(struct comedi_device *dev,
228
struct comedi_devconfig *it);
229
static int pcmuio_detach(struct comedi_device *dev);
231
static struct comedi_driver driver = {
232
.driver_name = "pcmuio",
233
.module = THIS_MODULE,
234
.attach = pcmuio_attach,
235
.detach = pcmuio_detach,
236
/* It is not necessary to implement the following members if you are
237
* writing a driver for a ISA PnP or PCI card */
238
/* Most drivers will support multiple types of boards by
239
* having an array of board structures. These were defined
240
* in pcmuio_boards[] above. Note that the element 'name'
241
* was first in the structure -- Comedi uses this fact to
242
* extract the name of the board without knowing any details
243
* about the structure except for its length.
244
* When a device is attached (by comedi_config), the name
245
* of the device is given to Comedi, and Comedi tries to
246
* match it by going through the list of board names. If
247
* there is a match, the address of the pointer is put
248
* into dev->board_ptr and driver->attach() is called.
250
* Note that these are not necessary if you can determine
251
* the type of board in software. ISA PnP, PCI, and PCMCIA
252
* devices are such boards.
254
.board_name = &pcmuio_boards[0].name,
255
.offset = sizeof(struct pcmuio_board),
256
.num_names = ARRAY_SIZE(pcmuio_boards),
259
static int pcmuio_dio_insn_bits(struct comedi_device *dev,
260
struct comedi_subdevice *s,
261
struct comedi_insn *insn, unsigned int *data);
262
static int pcmuio_dio_insn_config(struct comedi_device *dev,
263
struct comedi_subdevice *s,
264
struct comedi_insn *insn, unsigned int *data);
266
static irqreturn_t interrupt_pcmuio(int irq, void *d);
267
static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
268
static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
269
static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
270
static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
271
struct comedi_cmd *cmd);
273
/* some helper functions to deal with specifics of this device's registers */
274
static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */
275
static void switch_page(struct comedi_device *dev, int asic, int page);
277
static void lock_port(struct comedi_device *dev, int asic, int port);
278
static void unlock_port(struct comedi_device *dev, int asic, int port);
282
* Attach is called by the Comedi core to configure the driver
283
* for a particular board. If you specified a board_name array
284
* in the driver structure, dev->board_ptr contains that
287
static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
289
struct comedi_subdevice *s;
290
int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
291
unsigned long iobase;
292
unsigned int irq[MAX_ASICS];
294
iobase = it->options[0];
295
irq[0] = it->options[1];
296
irq[1] = it->options[2];
298
dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
299
driver.driver_name, iobase);
301
dev->iobase = iobase;
303
if (!iobase || !request_region(iobase,
304
thisboard->num_asics * ASIC_IOSIZE,
305
driver.driver_name)) {
306
dev_err(dev->hw_dev, "I/O port conflict\n");
311
* Initialize dev->board_name. Note that we can use the "thisboard"
312
* macro now, since we just initialized it in the last line.
314
dev->board_name = thisboard->name;
317
* Allocate the private structure area. alloc_private() is a
318
* convenient macro defined in comedidev.h.
320
if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
321
dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
325
for (asic = 0; asic < MAX_ASICS; ++asic) {
326
devpriv->asics[asic].num = asic;
327
devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
328
devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
329
this function when we
331
spin_lock_init(&devpriv->asics[asic].spinlock);
334
chans_left = CHANS_PER_ASIC * thisboard->num_asics;
335
n_subdevs = CALC_N_SUBDEVS(chans_left);
337
kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
339
if (!devpriv->sprivs) {
340
dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
344
* Allocate the subdevice structures. alloc_subdevice() is a
345
* convenient macro defined in comedidev.h.
347
* Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
348
* 96-channel version of the board.
350
if (alloc_subdevices(dev, n_subdevs) < 0) {
351
dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
357
for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
360
s = dev->subdevices + sdev_no;
361
s->private = devpriv->sprivs + sdev_no;
363
s->range_table = &range_digital;
364
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
365
s->type = COMEDI_SUBD_DIO;
366
s->insn_bits = pcmuio_dio_insn_bits;
367
s->insn_config = pcmuio_dio_insn_config;
368
s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
369
subpriv->intr.asic = -1;
370
subpriv->intr.first_chan = -1;
371
subpriv->intr.asic_chan = -1;
372
subpriv->intr.num_asic_chans = -1;
373
subpriv->intr.active = 0;
376
/* save the ioport address for each 'port' of 8 channels in the
378
for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
379
if (port >= PORTS_PER_ASIC) {
384
subpriv->iobases[byte_no] =
385
devpriv->asics[asic].iobase + port;
387
if (thisasic_chanct <
388
CHANS_PER_PORT * INTR_PORTS_PER_ASIC
389
&& subpriv->intr.asic < 0) {
390
/* this is an interrupt subdevice, so setup the struct */
391
subpriv->intr.asic = asic;
392
subpriv->intr.active = 0;
393
subpriv->intr.stop_count = 0;
394
subpriv->intr.first_chan = byte_no * 8;
395
subpriv->intr.asic_chan = thisasic_chanct;
396
subpriv->intr.num_asic_chans =
397
s->n_chan - subpriv->intr.first_chan;
398
dev->read_subdev = s;
399
s->subdev_flags |= SDF_CMD_READ;
400
s->cancel = pcmuio_cancel;
401
s->do_cmd = pcmuio_cmd;
402
s->do_cmdtest = pcmuio_cmdtest;
403
s->len_chanlist = subpriv->intr.num_asic_chans;
405
thisasic_chanct += CHANS_PER_PORT;
407
spin_lock_init(&subpriv->intr.spinlock);
409
chans_left -= s->n_chan;
412
asic = 0; /* reset the asic to our first asic, to do intr subdevs */
418
init_asics(dev); /* clear out all the registers, basically */
420
for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
422
&& request_irq(irq[asic], interrupt_pcmuio,
423
IRQF_SHARED, thisboard->name, dev)) {
425
/* unroll the allocated irqs.. */
426
for (i = asic - 1; i >= 0; --i) {
427
free_irq(irq[i], dev);
428
devpriv->asics[i].irq = irq[i] = 0;
432
devpriv->asics[asic].irq = irq[asic];
435
dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
439
dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
440
if (irq[1] && thisboard->num_asics == 2)
441
dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
443
dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
451
* _detach is called to deconfigure a device. It should deallocate
453
* This function is also called when _attach() fails, so it should be
454
* careful not to release resources that were not necessarily
455
* allocated by _attach(). dev->private and dev->subdevices are
456
* deallocated automatically by the core.
458
static int pcmuio_detach(struct comedi_device *dev)
462
dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
465
release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
467
for (i = 0; i < MAX_ASICS; ++i) {
468
if (devpriv->asics[i].irq)
469
free_irq(devpriv->asics[i].irq, dev);
472
if (devpriv && devpriv->sprivs)
473
kfree(devpriv->sprivs);
478
209
/* DIO devices are slightly special. Although it is possible to
479
210
* implement the insn_read/insn_write interface, it is much more
1014
745
return comedi_pcm_cmdtest(dev, s, cmd);
1018
* A convenient macro that defines init_module() and cleanup_module(),
1021
static int __init driver_init_module(void)
1023
return comedi_driver_register(&driver);
1026
static void __exit driver_cleanup_module(void)
1028
comedi_driver_unregister(&driver);
1031
module_init(driver_init_module);
1032
module_exit(driver_cleanup_module);
748
static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
750
struct comedi_subdevice *s;
751
int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
752
unsigned long iobase;
753
unsigned int irq[MAX_ASICS];
755
iobase = it->options[0];
756
irq[0] = it->options[1];
757
irq[1] = it->options[2];
759
dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
760
dev->driver->driver_name, iobase);
762
dev->iobase = iobase;
764
if (!iobase || !request_region(iobase,
765
thisboard->num_asics * ASIC_IOSIZE,
766
dev->driver->driver_name)) {
767
dev_err(dev->hw_dev, "I/O port conflict\n");
772
* Initialize dev->board_name. Note that we can use the "thisboard"
773
* macro now, since we just initialized it in the last line.
775
dev->board_name = thisboard->name;
778
* Allocate the private structure area. alloc_private() is a
779
* convenient macro defined in comedidev.h.
781
if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
782
dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
786
for (asic = 0; asic < MAX_ASICS; ++asic) {
787
devpriv->asics[asic].num = asic;
788
devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
789
devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
790
this function when we
792
spin_lock_init(&devpriv->asics[asic].spinlock);
795
chans_left = CHANS_PER_ASIC * thisboard->num_asics;
796
n_subdevs = CALC_N_SUBDEVS(chans_left);
798
kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
800
if (!devpriv->sprivs) {
801
dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
805
* Allocate the subdevice structures. alloc_subdevice() is a
806
* convenient macro defined in comedidev.h.
808
* Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
809
* 96-channel version of the board.
811
if (alloc_subdevices(dev, n_subdevs) < 0) {
812
dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
818
for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
821
s = dev->subdevices + sdev_no;
822
s->private = devpriv->sprivs + sdev_no;
824
s->range_table = &range_digital;
825
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
826
s->type = COMEDI_SUBD_DIO;
827
s->insn_bits = pcmuio_dio_insn_bits;
828
s->insn_config = pcmuio_dio_insn_config;
829
s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
830
subpriv->intr.asic = -1;
831
subpriv->intr.first_chan = -1;
832
subpriv->intr.asic_chan = -1;
833
subpriv->intr.num_asic_chans = -1;
834
subpriv->intr.active = 0;
837
/* save the ioport address for each 'port' of 8 channels in the
839
for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
840
if (port >= PORTS_PER_ASIC) {
845
subpriv->iobases[byte_no] =
846
devpriv->asics[asic].iobase + port;
848
if (thisasic_chanct <
849
CHANS_PER_PORT * INTR_PORTS_PER_ASIC
850
&& subpriv->intr.asic < 0) {
851
/* this is an interrupt subdevice, so setup the struct */
852
subpriv->intr.asic = asic;
853
subpriv->intr.active = 0;
854
subpriv->intr.stop_count = 0;
855
subpriv->intr.first_chan = byte_no * 8;
856
subpriv->intr.asic_chan = thisasic_chanct;
857
subpriv->intr.num_asic_chans =
858
s->n_chan - subpriv->intr.first_chan;
859
dev->read_subdev = s;
860
s->subdev_flags |= SDF_CMD_READ;
861
s->cancel = pcmuio_cancel;
862
s->do_cmd = pcmuio_cmd;
863
s->do_cmdtest = pcmuio_cmdtest;
864
s->len_chanlist = subpriv->intr.num_asic_chans;
866
thisasic_chanct += CHANS_PER_PORT;
868
spin_lock_init(&subpriv->intr.spinlock);
870
chans_left -= s->n_chan;
873
asic = 0; /* reset the asic to our first asic, to do intr subdevs */
879
init_asics(dev); /* clear out all the registers, basically */
881
for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
883
&& request_irq(irq[asic], interrupt_pcmuio,
884
IRQF_SHARED, thisboard->name, dev)) {
886
/* unroll the allocated irqs.. */
887
for (i = asic - 1; i >= 0; --i) {
888
free_irq(irq[i], dev);
889
devpriv->asics[i].irq = irq[i] = 0;
893
devpriv->asics[asic].irq = irq[asic];
896
dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
900
dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
901
if (irq[1] && thisboard->num_asics == 2)
902
dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
904
dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
911
static void pcmuio_detach(struct comedi_device *dev)
916
release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
917
for (i = 0; i < MAX_ASICS; ++i) {
918
if (devpriv->asics[i].irq)
919
free_irq(devpriv->asics[i].irq, dev);
921
if (devpriv && devpriv->sprivs)
922
kfree(devpriv->sprivs);
925
static const struct pcmuio_board pcmuio_boards[] = {
937
static struct comedi_driver pcmuio_driver = {
938
.driver_name = "pcmuio",
939
.module = THIS_MODULE,
940
.attach = pcmuio_attach,
941
.detach = pcmuio_detach,
942
.board_name = &pcmuio_boards[0].name,
943
.offset = sizeof(struct pcmuio_board),
944
.num_names = ARRAY_SIZE(pcmuio_boards),
946
module_comedi_driver(pcmuio_driver);
1034
948
MODULE_AUTHOR("Comedi http://www.comedi.org");
1035
949
MODULE_DESCRIPTION("Comedi low-level driver");