From: H Hartley Sweeten Date: Fri, 22 Mar 2013 16:36:34 +0000 (-0700) Subject: staging: comedi: ni_labpc: remove forward declarations 1 X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=dd2aef646c9cfcc2647cae52a5097ce70f1e13c3;p=~shefty%2Frdma-dev.git staging: comedi: ni_labpc: remove forward declarations 1 Move the comedi_driver (*attach), (*auto_attach), and (*detach) functions as well as a couple of the attach helper functions to remove the need for a number of the forward declarations. Signed-off-by: H Hartley Sweeten Cc: Ian Abbott Cc: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 1a9024dd894..846a1e9a942 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -215,48 +215,17 @@ enum scan_mode { MODE_MULT_CHAN_DOWN, }; -static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t labpc_interrupt(int irq, void *d); static int labpc_drain_fifo(struct comedi_device *dev); #ifdef CONFIG_ISA_DMA_API static void labpc_drain_dma(struct comedi_device *dev); static void handle_isa_dma(struct comedi_device *dev); #endif static void labpc_drain_dregs(struct comedi_device *dev); -static int labpc_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_calib_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_calib_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_eeprom_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_eeprom_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, enum scan_mode scan_mode); #ifdef CONFIG_ISA_DMA_API static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd); #endif -static int labpc_dio_mem_callback(int dir, int port, int data, - unsigned long arg); -static void labpc_serial_out(struct comedi_device *dev, unsigned int value, - unsigned int num_bits); -static unsigned int labpc_serial_in(struct comedi_device *dev); -static unsigned int labpc_eeprom_read(struct comedi_device *dev, - unsigned int address); static unsigned int labpc_eeprom_read_status(struct comedi_device *dev); static int labpc_eeprom_write(struct comedi_device *dev, unsigned int address, @@ -498,388 +467,76 @@ static inline int labpc_counter_load(struct comedi_device *dev, return i8254_load(base_address, 0, counter_number, count, mode); } -int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, - unsigned int irq, unsigned int dma_chan) +static void labpc_clear_adc_fifo(const struct comedi_device *dev) { - const struct labpc_boardinfo *thisboard = comedi_board(dev); struct labpc_private *devpriv = dev->private; - struct comedi_subdevice *s; - int i; - unsigned long isr_flags; -#ifdef CONFIG_ISA_DMA_API - unsigned long dma_flags; -#endif - short lsb, msb; - int ret; - - dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name); - if (iobase == 0) { - dev_err(dev->class_dev, "io base address is zero!\n"); - return -EINVAL; - } - /* request io regions for isa boards */ - if (thisboard->bustype == isa_bustype) { - /* check if io addresses are available */ - if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) { - dev_err(dev->class_dev, "I/O port conflict\n"); - return -EIO; - } - } - dev->iobase = iobase; - - if (thisboard->memory_mapped_io) { - devpriv->read_byte = labpc_readb; - devpriv->write_byte = labpc_writeb; - } else { - devpriv->read_byte = labpc_inb; - devpriv->write_byte = labpc_outb; - } - /* initialize board's command registers */ - devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); - if (thisboard->register_layout == labpc_1200_layout) { - devpriv->write_byte(devpriv->command5_bits, - dev->iobase + COMMAND5_REG); - devpriv->write_byte(devpriv->command6_bits, - dev->iobase + COMMAND6_REG); - } - - /* grab our IRQ */ - if (irq) { - isr_flags = 0; - if (thisboard->bustype == pci_bustype - || thisboard->bustype == pcmcia_bustype) - isr_flags |= IRQF_SHARED; - if (request_irq(irq, labpc_interrupt, isr_flags, - DRV_NAME, dev)) { - dev_err(dev->class_dev, "unable to allocate irq %u\n", - irq); - return -EINVAL; - } - } - dev->irq = irq; - -#ifdef CONFIG_ISA_DMA_API - /* grab dma channel */ - if (dma_chan > 3) { - dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan); - return -EINVAL; - } else if (dma_chan) { - /* allocate dma buffer */ - devpriv->dma_buffer = kmalloc(dma_buffer_size, - GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer == NULL) - return -ENOMEM; - if (request_dma(dma_chan, DRV_NAME)) { - dev_err(dev->class_dev, - "failed to allocate dma channel %u\n", - dma_chan); - return -EINVAL; - } - devpriv->dma_chan = dma_chan; - dma_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); - release_dma_lock(dma_flags); - } -#endif + devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); + devpriv->read_byte(dev->iobase + ADC_FIFO_REG); + devpriv->read_byte(dev->iobase + ADC_FIFO_REG); +} - dev->board_name = thisboard->name; +static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct labpc_private *devpriv = dev->private; + unsigned long flags; - ret = comedi_alloc_subdevices(dev, 5); - if (ret) - return ret; + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; + devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); - /* analog input subdevice */ - s = &dev->subdevices[0]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ; - s->n_chan = 8; - s->len_chanlist = 8; - s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ - s->range_table = thisboard->ai_range_table; - s->do_cmd = labpc_ai_cmd; - s->do_cmdtest = labpc_ai_cmdtest; - s->insn_read = labpc_ai_rinsn; - s->cancel = labpc_cancel; + devpriv->command3_bits = 0; + devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - /* analog output */ - s = &dev->subdevices[1]; - if (thisboard->has_ao) { - /* - * Could provide command support, except it only has a - * one sample hardware buffer for analog output and no - * underrun flag. - */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; - s->n_chan = NUM_AO_CHAN; - s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ - s->range_table = &range_labpc_ao; - s->insn_read = labpc_ao_rinsn; - s->insn_write = labpc_ao_winsn; - /* initialize analog outputs to a known value */ - for (i = 0; i < s->n_chan; i++) { - devpriv->ao_value[i] = s->maxdata / 2; - lsb = devpriv->ao_value[i] & 0xff; - msb = (devpriv->ao_value[i] >> 8) & 0xff; - devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i)); - devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i)); - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } + return 0; +} - /* 8255 dio */ - s = &dev->subdevices[2]; - /* if board uses io memory we have to give a custom callback - * function to the 8255 driver */ - if (thisboard->memory_mapped_io) - subdev_8255_init(dev, s, labpc_dio_mem_callback, - (unsigned long)(dev->iobase + DIO_BASE_REG)); - else - subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG); +static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) +{ + if (cmd->chanlist_len == 1) + return MODE_SINGLE_CHAN; - /* calibration subdevices for boards that have one */ - s = &dev->subdevices[3]; - if (thisboard->register_layout == labpc_1200_layout) { - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 16; - s->maxdata = 0xff; - s->insn_read = labpc_calib_read_insn; - s->insn_write = labpc_calib_write_insn; + /* chanlist may be NULL during cmdtest. */ + if (cmd->chanlist == NULL) + return MODE_MULT_CHAN_UP; - for (i = 0; i < s->n_chan; i++) - write_caldac(dev, i, s->maxdata / 2); - } else - s->type = COMEDI_SUBD_UNUSED; + if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1])) + return MODE_SINGLE_CHAN_INTERVAL; - /* EEPROM */ - s = &dev->subdevices[4]; - if (thisboard->register_layout == labpc_1200_layout) { - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = EEPROM_SIZE; - s->maxdata = 0xff; - s->insn_read = labpc_eeprom_read_insn; - s->insn_write = labpc_eeprom_write_insn; + if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1])) + return MODE_MULT_CHAN_UP; - for (i = 0; i < EEPROM_SIZE; i++) - devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); - } else - s->type = COMEDI_SUBD_UNUSED; + if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1])) + return MODE_MULT_CHAN_DOWN; + pr_err("ni_labpc: bug! cannot determine AI scan mode\n"); return 0; } -EXPORT_SYMBOL_GPL(labpc_common_attach); -static const struct labpc_boardinfo * -labpc_pci_find_boardinfo(struct pci_dev *pcidev) +static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, + const struct comedi_cmd *cmd, + enum scan_mode mode) { - unsigned int device_id = pcidev->device; - unsigned int n; + int channel, range, aref, i; - for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) { - const struct labpc_boardinfo *board = &labpc_boards[n]; - if (board->bustype == pci_bustype && - board->device_id == device_id) - return board; - } - return NULL; -} + if (cmd->chanlist == NULL) + return 0; -static int labpc_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct labpc_private *devpriv; - unsigned long iobase; - unsigned int irq; - int ret; + if (mode == MODE_SINGLE_CHAN) + return 0; - if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS)) - return -ENODEV; + if (mode == MODE_SINGLE_CHAN_INTERVAL) { + if (cmd->chanlist_len > 0xff) { + comedi_error(dev, + "ni_labpc: chanlist too long for single channel interval mode\n"); + return 1; + } + } - ret = comedi_pci_enable(dev); - if (ret) - return ret; - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - dev->board_ptr = labpc_pci_find_boardinfo(pcidev); - if (!dev->board_ptr) - return -ENODEV; - devpriv->mite = mite_alloc(pcidev); - if (!devpriv->mite) - return -ENOMEM; - ret = mite_setup(devpriv->mite); - if (ret < 0) - return ret; - iobase = (unsigned long)devpriv->mite->daq_io_addr; - irq = mite_irq(devpriv->mite); - return labpc_common_attach(dev, iobase, irq, 0); -} - -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct labpc_boardinfo *thisboard = comedi_board(dev); - struct labpc_private *devpriv; - unsigned long iobase = 0; - unsigned int irq = 0; - unsigned int dma_chan = 0; - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case isa_bustype: -#ifdef CONFIG_ISA_DMA_API - iobase = it->options[0]; - irq = it->options[1]; - dma_chan = it->options[2]; -#else - dev_err(dev->class_dev, - "ni_labpc driver has not been built with ISA DMA support.\n"); - return -EINVAL; -#endif - break; - case pci_bustype: -#ifdef CONFIG_COMEDI_PCI_DRIVERS - dev_err(dev->class_dev, - "manual configuration of PCI board '%s' is not supported\n", - thisboard->name); - return -EINVAL; -#else - dev_err(dev->class_dev, - "ni_labpc driver has not been built with PCI support.\n"); - return -EINVAL; -#endif - break; - default: - dev_err(dev->class_dev, - "ni_labpc: bug! couldn't determine board type\n"); - return -EINVAL; - break; - } - - return labpc_common_attach(dev, iobase, irq, dma_chan); -} - -void labpc_common_detach(struct comedi_device *dev) -{ - const struct labpc_boardinfo *thisboard = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - struct comedi_subdevice *s; - - if (!thisboard) - return; - if (dev->subdevices) { - s = &dev->subdevices[2]; - subdev_8255_cleanup(dev, s); - } -#ifdef CONFIG_ISA_DMA_API - /* only free stuff if it has been allocated by _attach */ - kfree(devpriv->dma_buffer); - if (devpriv->dma_chan) - free_dma(devpriv->dma_chan); -#endif - if (dev->irq) - free_irq(dev->irq, dev); - if (thisboard->bustype == isa_bustype && dev->iobase) - release_region(dev->iobase, LABPC_SIZE); -#ifdef CONFIG_COMEDI_PCI_DRIVERS - if (devpriv->mite) { - mite_unsetup(devpriv->mite); - mite_free(devpriv->mite); - } - if (thisboard->bustype == pci_bustype) - comedi_pci_disable(dev); -#endif -}; -EXPORT_SYMBOL_GPL(labpc_common_detach); - -static void labpc_clear_adc_fifo(const struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - - devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); - devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - devpriv->read_byte(dev->iobase + ADC_FIFO_REG); -} - -static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct labpc_private *devpriv = dev->private; - unsigned long flags; - - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - devpriv->command3_bits = 0; - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - - return 0; -} - -static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) -{ - if (cmd->chanlist_len == 1) - return MODE_SINGLE_CHAN; - - /* chanlist may be NULL during cmdtest. */ - if (cmd->chanlist == NULL) - return MODE_MULT_CHAN_UP; - - if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1])) - return MODE_SINGLE_CHAN_INTERVAL; - - if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1])) - return MODE_MULT_CHAN_UP; - - if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1])) - return MODE_MULT_CHAN_DOWN; - - pr_err("ni_labpc: bug! cannot determine AI scan mode\n"); - return 0; -} - -static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, - const struct comedi_cmd *cmd, - enum scan_mode mode) -{ - int channel, range, aref, i; - - if (cmd->chanlist == NULL) - return 0; - - if (mode == MODE_SINGLE_CHAN) - return 0; - - if (mode == MODE_SINGLE_CHAN_INTERVAL) { - if (cmd->chanlist_len > 0xff) { - comedi_error(dev, - "ni_labpc: chanlist too long for single channel interval mode\n"); - return 1; - } - } - - channel = CR_CHAN(cmd->chanlist[0]); - range = CR_RANGE(cmd->chanlist[0]); - aref = CR_AREF(cmd->chanlist[0]); + channel = CR_CHAN(cmd->chanlist[0]); + range = CR_RANGE(cmd->chanlist[0]); + aref = CR_AREF(cmd->chanlist[0]); for (i = 0; i < cmd->chanlist_len; i++) { @@ -2105,6 +1762,318 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel, devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); } +int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, + unsigned int irq, unsigned int dma_chan) +{ + const struct labpc_boardinfo *thisboard = comedi_board(dev); + struct labpc_private *devpriv = dev->private; + struct comedi_subdevice *s; + int i; + unsigned long isr_flags; +#ifdef CONFIG_ISA_DMA_API + unsigned long dma_flags; +#endif + short lsb, msb; + int ret; + + dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name); + if (iobase == 0) { + dev_err(dev->class_dev, "io base address is zero!\n"); + return -EINVAL; + } + /* request io regions for isa boards */ + if (thisboard->bustype == isa_bustype) { + /* check if io addresses are available */ + if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) { + dev_err(dev->class_dev, "I/O port conflict\n"); + return -EIO; + } + } + dev->iobase = iobase; + + if (thisboard->memory_mapped_io) { + devpriv->read_byte = labpc_readb; + devpriv->write_byte = labpc_writeb; + } else { + devpriv->read_byte = labpc_inb; + devpriv->write_byte = labpc_outb; + } + /* initialize board's command registers */ + devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); + devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); + devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); + devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); + if (thisboard->register_layout == labpc_1200_layout) { + devpriv->write_byte(devpriv->command5_bits, + dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->command6_bits, + dev->iobase + COMMAND6_REG); + } + + /* grab our IRQ */ + if (irq) { + isr_flags = 0; + if (thisboard->bustype == pci_bustype + || thisboard->bustype == pcmcia_bustype) + isr_flags |= IRQF_SHARED; + if (request_irq(irq, labpc_interrupt, isr_flags, + DRV_NAME, dev)) { + dev_err(dev->class_dev, "unable to allocate irq %u\n", + irq); + return -EINVAL; + } + } + dev->irq = irq; + +#ifdef CONFIG_ISA_DMA_API + /* grab dma channel */ + if (dma_chan > 3) { + dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan); + return -EINVAL; + } else if (dma_chan) { + /* allocate dma buffer */ + devpriv->dma_buffer = kmalloc(dma_buffer_size, + GFP_KERNEL | GFP_DMA); + if (devpriv->dma_buffer == NULL) + return -ENOMEM; + + if (request_dma(dma_chan, DRV_NAME)) { + dev_err(dev->class_dev, + "failed to allocate dma channel %u\n", + dma_chan); + return -EINVAL; + } + devpriv->dma_chan = dma_chan; + dma_flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); + release_dma_lock(dma_flags); + } +#endif + + dev->board_name = thisboard->name; + + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; + + /* analog input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = + SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ; + s->n_chan = 8; + s->len_chanlist = 8; + s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ + s->range_table = thisboard->ai_range_table; + s->do_cmd = labpc_ai_cmd; + s->do_cmdtest = labpc_ai_cmdtest; + s->insn_read = labpc_ai_rinsn; + s->cancel = labpc_cancel; + + /* analog output */ + s = &dev->subdevices[1]; + if (thisboard->has_ao) { + /* + * Could provide command support, except it only has a + * one sample hardware buffer for analog output and no + * underrun flag. + */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; + s->n_chan = NUM_AO_CHAN; + s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ + s->range_table = &range_labpc_ao; + s->insn_read = labpc_ao_rinsn; + s->insn_write = labpc_ao_winsn; + /* initialize analog outputs to a known value */ + for (i = 0; i < s->n_chan; i++) { + devpriv->ao_value[i] = s->maxdata / 2; + lsb = devpriv->ao_value[i] & 0xff; + msb = (devpriv->ao_value[i] >> 8) & 0xff; + devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i)); + devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i)); + } + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* 8255 dio */ + s = &dev->subdevices[2]; + /* if board uses io memory we have to give a custom callback + * function to the 8255 driver */ + if (thisboard->memory_mapped_io) + subdev_8255_init(dev, s, labpc_dio_mem_callback, + (unsigned long)(dev->iobase + DIO_BASE_REG)); + else + subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG); + + /* calibration subdevices for boards that have one */ + s = &dev->subdevices[3]; + if (thisboard->register_layout == labpc_1200_layout) { + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 16; + s->maxdata = 0xff; + s->insn_read = labpc_calib_read_insn; + s->insn_write = labpc_calib_write_insn; + + for (i = 0; i < s->n_chan; i++) + write_caldac(dev, i, s->maxdata / 2); + } else + s->type = COMEDI_SUBD_UNUSED; + + /* EEPROM */ + s = &dev->subdevices[4]; + if (thisboard->register_layout == labpc_1200_layout) { + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = EEPROM_SIZE; + s->maxdata = 0xff; + s->insn_read = labpc_eeprom_read_insn; + s->insn_write = labpc_eeprom_write_insn; + + for (i = 0; i < EEPROM_SIZE; i++) + devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); + } else + s->type = COMEDI_SUBD_UNUSED; + + return 0; +} +EXPORT_SYMBOL_GPL(labpc_common_attach); + +static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + const struct labpc_boardinfo *thisboard = comedi_board(dev); + struct labpc_private *devpriv; + unsigned long iobase = 0; + unsigned int irq = 0; + unsigned int dma_chan = 0; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + /* get base address, irq etc. based on bustype */ + switch (thisboard->bustype) { + case isa_bustype: +#ifdef CONFIG_ISA_DMA_API + iobase = it->options[0]; + irq = it->options[1]; + dma_chan = it->options[2]; +#else + dev_err(dev->class_dev, + "ni_labpc driver has not been built with ISA DMA support.\n"); + return -EINVAL; +#endif + break; + case pci_bustype: +#ifdef CONFIG_COMEDI_PCI_DRIVERS + dev_err(dev->class_dev, + "manual configuration of PCI board '%s' is not supported\n", + thisboard->name); + return -EINVAL; +#else + dev_err(dev->class_dev, + "ni_labpc driver has not been built with PCI support.\n"); + return -EINVAL; +#endif + break; + default: + dev_err(dev->class_dev, + "ni_labpc: bug! couldn't determine board type\n"); + return -EINVAL; + break; + } + + return labpc_common_attach(dev, iobase, irq, dma_chan); +} + +static const struct labpc_boardinfo * +labpc_pci_find_boardinfo(struct pci_dev *pcidev) +{ + unsigned int device_id = pcidev->device; + unsigned int n; + + for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) { + const struct labpc_boardinfo *board = &labpc_boards[n]; + if (board->bustype == pci_bustype && + board->device_id == device_id) + return board; + } + return NULL; +} + +static int labpc_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct labpc_private *devpriv; + unsigned long iobase; + unsigned int irq; + int ret; + + if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS)) + return -ENODEV; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + dev->board_ptr = labpc_pci_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; + ret = mite_setup(devpriv->mite); + if (ret < 0) + return ret; + iobase = (unsigned long)devpriv->mite->daq_io_addr; + irq = mite_irq(devpriv->mite); + return labpc_common_attach(dev, iobase, irq, 0); +} + +void labpc_common_detach(struct comedi_device *dev) +{ + const struct labpc_boardinfo *thisboard = comedi_board(dev); + struct labpc_private *devpriv = dev->private; + struct comedi_subdevice *s; + + if (!thisboard) + return; + if (dev->subdevices) { + s = &dev->subdevices[2]; + subdev_8255_cleanup(dev, s); + } +#ifdef CONFIG_ISA_DMA_API + /* only free stuff if it has been allocated by _attach */ + kfree(devpriv->dma_buffer); + if (devpriv->dma_chan) + free_dma(devpriv->dma_chan); +#endif + if (dev->irq) + free_irq(dev->irq, dev); + if (thisboard->bustype == isa_bustype && dev->iobase) + release_region(dev->iobase, LABPC_SIZE); +#ifdef CONFIG_COMEDI_PCI_DRIVERS + if (devpriv->mite) { + mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } + if (thisboard->bustype == pci_bustype) + comedi_pci_disable(dev); +#endif +} +EXPORT_SYMBOL_GPL(labpc_common_detach); + static struct comedi_driver labpc_driver = { .driver_name = DRV_NAME, .module = THIS_MODULE,