static int apci1032_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct apci1032_private *devpriv; struct comedi_subdevice *s; int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; ret = comedi_pci_enable(dev); if (ret) return ret; devpriv->amcc_iobase = pci_resource_start(pcidev, 0); dev->iobase = pci_resource_start(pcidev, 1); apci1032_reset(dev); if (pcidev->irq > 0) { ret = request_irq(pcidev->irq, apci1032_interrupt, IRQF_SHARED, dev->board_name, dev); if (ret == 0) dev->irq = pcidev->irq; } ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; /* Allocate and Initialise DI Subdevice Structures */ s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 32; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = apci1032_di_insn_bits; /* Change-Of-State (COS) interrupt subdevice */ s = &dev->subdevices[1]; if (dev->irq) { dev->read_subdev = s; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; s->n_chan = 1; s->maxdata = 1; s->range_table = &range_digital; s->insn_config = apci1032_cos_insn_config; s->insn_bits = apci1032_cos_insn_bits; s->len_chanlist = 1; s->do_cmdtest = apci1032_cos_cmdtest; s->do_cmd = apci1032_cos_cmd; s->cancel = apci1032_cos_cancel; } else { s->type = COMEDI_SUBD_UNUSED; } return 0; }
static void apci1032_detach(struct comedi_device *dev) { if (dev->iobase) apci1032_reset(dev); if (dev->irq) free_irq(dev->irq, dev); comedi_pci_disable(dev); }
static void apci1032_detach(struct comedi_device *dev) { if (dev->iobase) apci1032_reset(dev); comedi_pci_detach(dev); }
static int apci1032_cos_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { return apci1032_reset(dev); }
static int apci1032_cos_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct apci1032_private *devpriv = dev->private; unsigned int shift, oldmask; switch (data[0]) { case INSN_CONFIG_DIGITAL_TRIG: if (data[1] != 0) return -EINVAL; shift = data[3]; oldmask = (1U << shift) - 1; switch (data[2]) { case COMEDI_DIGITAL_TRIG_DISABLE: devpriv->ctrl = 0; devpriv->mode1 = 0; devpriv->mode2 = 0; apci1032_reset(dev); break; case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | APCI1032_CTRL_INT_OR)) { /* switching to 'OR' mode */ devpriv->ctrl = APCI1032_CTRL_INT_ENA | APCI1032_CTRL_INT_OR; /* wipe old channels */ devpriv->mode1 = 0; devpriv->mode2 = 0; } else { /* preserve unspecified channels */ devpriv->mode1 &= oldmask; devpriv->mode2 &= oldmask; } /* configure specified channels */ devpriv->mode1 |= data[4] << shift; devpriv->mode2 |= data[5] << shift; break; case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | APCI1032_CTRL_INT_AND)) { /* switching to 'AND' mode */ devpriv->ctrl = APCI1032_CTRL_INT_ENA | APCI1032_CTRL_INT_AND; /* wipe old channels */ devpriv->mode1 = 0; devpriv->mode2 = 0; } else { /* preserve unspecified channels */ devpriv->mode1 &= oldmask; devpriv->mode2 &= oldmask; } /* configure specified channels */ devpriv->mode1 |= data[4] << shift; devpriv->mode2 |= data[5] << shift; break; default: return -EINVAL; } break; default: return -EINVAL; } return insn->n; }