in drivers/amplc_pci230.c [2368:2540]
static int pci230_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
const struct pci230_board *board;
struct pci230_private *devpriv;
struct comedi_subdevice *s;
int rc;
dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n",
pci_name(pci_dev));
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
spin_lock_init(&devpriv->isr_spinlock);
spin_lock_init(&devpriv->res_spinlock);
spin_lock_init(&devpriv->ai_stop_spinlock);
spin_lock_init(&devpriv->ao_stop_spinlock);
board = pci230_find_pci_board(pci_dev);
if (!board) {
dev_err(dev->class_dev,
"amplc_pci230: BUG! cannot determine board type!\n");
return -EINVAL;
}
dev->board_ptr = board;
dev->board_name = board->name;
rc = comedi_pci_enable(dev);
if (rc)
return rc;
/*
* Read base addresses of the PCI230's two I/O regions from PCI
* configuration register.
*/
dev->iobase = pci_resource_start(pci_dev, 2);
devpriv->daqio = pci_resource_start(pci_dev, 3);
dev_dbg(dev->class_dev,
"%s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
dev->board_name, dev->iobase, devpriv->daqio);
/* Read bits of DACCON register - only the output range. */
devpriv->daccon = inw(devpriv->daqio + PCI230_DACCON) &
PCI230_DAC_OR_MASK;
/*
* Read hardware version register and set extended function register
* if they exist.
*/
if (pci_resource_len(pci_dev, 3) >= 32) {
unsigned short extfunc = 0;
devpriv->hwver = inw(devpriv->daqio + PCI230P_HWVER);
if (devpriv->hwver < board->min_hwver) {
dev_err(dev->class_dev,
"%s - bad hardware version - got %u, need %u\n",
dev->board_name, devpriv->hwver,
board->min_hwver);
return -EIO;
}
if (devpriv->hwver > 0) {
if (!board->have_dio) {
/*
* No DIO ports. Route counters' external gates
* to the EXTTRIG signal (PCI260+ pin 17).
* (Otherwise, they would be routed to DIO
* inputs PC0, PC1 and PC2 which don't exist
* on PCI260[+].)
*/
extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
}
if (board->ao_bits && devpriv->hwver >= 2) {
/* Enable DAC FIFO functionality. */
extfunc |= PCI230P2_EXTFUNC_DACFIFO;
}
}
outw(extfunc, devpriv->daqio + PCI230P_EXTFUNC);
if (extfunc & PCI230P2_EXTFUNC_DACFIFO) {
/*
* Temporarily enable DAC FIFO, reset it and disable
* FIFO wraparound.
*/
outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN |
PCI230P2_DAC_FIFO_RESET,
devpriv->daqio + PCI230_DACCON);
/* Clear DAC FIFO channel enable register. */
outw(0, devpriv->daqio + PCI230P2_DACEN);
/* Disable DAC FIFO. */
outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON);
}
}
/* Disable board's interrupts. */
outb(0, dev->iobase + PCI230_INT_SCE);
/* Set ADC to a reasonable state. */
devpriv->adcg = 0;
devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE |
PCI230_ADC_IR_BIP;
outw(BIT(0), devpriv->daqio + PCI230_ADCEN);
outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG);
outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
devpriv->daqio + PCI230_ADCCON);
if (pci_dev->irq) {
rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED,
dev->board_name, dev);
if (rc == 0)
dev->irq = pci_dev->irq;
}
dev->pacer = comedi_8254_init(dev->iobase + PCI230_Z2_CT_BASE,
0, I8254_IO8, 0);
if (!dev->pacer)
return -ENOMEM;
rc = comedi_alloc_subdevices(dev, 3);
if (rc)
return rc;
s = &dev->subdevices[0];
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
s->n_chan = 16;
s->maxdata = (1 << board->ai_bits) - 1;
s->range_table = &pci230_ai_range;
s->insn_read = pci230_ai_insn_read;
s->len_chanlist = 256; /* but there are restrictions. */
if (dev->irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->do_cmd = pci230_ai_cmd;
s->do_cmdtest = pci230_ai_cmdtest;
s->cancel = pci230_ai_cancel;
}
s = &dev->subdevices[1];
/* analog output subdevice */
if (board->ao_bits) {
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
s->n_chan = 2;
s->maxdata = (1 << board->ao_bits) - 1;
s->range_table = &pci230_ao_range;
s->insn_write = pci230_ao_insn_write;
s->len_chanlist = 2;
if (dev->irq) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
s->do_cmd = pci230_ao_cmd;
s->do_cmdtest = pci230_ao_cmdtest;
s->cancel = pci230_ao_cancel;
}
rc = comedi_alloc_subdev_readback(s);
if (rc)
return rc;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
s = &dev->subdevices[2];
/* digital i/o subdevice */
if (board->have_dio) {
rc = subdev_8255_init(dev, s, NULL, PCI230_PPI_X_BASE);
if (rc)
return rc;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
return 0;
}