diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/amplc_pci230.c')
-rw-r--r-- | drivers/staging/comedi/drivers/amplc_pci230.c | 1224 |
1 files changed, 481 insertions, 743 deletions
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 684275d76e8c..01796cd28e5b 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -24,24 +24,19 @@ * Author: Allan Willcox <allanwillcox@ozemail.com.au>, * Steve D Sharples <steve.sharples@nottingham.ac.uk>, * Ian Abbott <abbotti@mev.co.uk> - * Updated: Wed, 22 Oct 2008 12:34:49 +0100 - * Devices: [Amplicon] PCI230 (pci230 or amplc_pci230), - * PCI230+ (pci230+ or amplc_pci230), - * PCI260 (pci260 or amplc_pci230), PCI260+ (pci260+ or amplc_pci230) + * Updated: Mon, 01 Sep 2014 10:09:16 +0000 + * Devices: [Amplicon] PCI230 (amplc_pci230), PCI230+, PCI260, PCI260+ * Status: works * * Configuration options: - * [0] - PCI bus of device (optional). - * [1] - PCI slot of device (optional). - * If bus/slot is not specified, the first available PCI device - * will be used. + * none * - * Configuring a "amplc_pci230" will match any supported card and it will - * choose the best match, picking the "+" models if possible. Configuring - * a "pci230" will match a PCI230 or PCI230+ card and it will be treated as - * a PCI230. Configuring a "pci260" will match a PCI260 or PCI260+ card - * and it will be treated as a PCI260. Configuring a "pci230+" will match - * a PCI230+ card. Configuring a "pci260+" will match a PCI260+ card. + * Manual configuration of PCI cards is not supported; they are configured + * automatically. + * + * The PCI230+ and PCI260+ have the same PCI device IDs as the PCI230 and + * PCI260, but can be distinguished by the the size of the PCI regions. A + * card will be configured as a "+" model if detected as such. * * Subdevices: * @@ -201,7 +196,6 @@ */ #define PCI_DEVICE_ID_PCI230 0x0000 #define PCI_DEVICE_ID_PCI260 0x0006 -#define PCI_DEVICE_ID_INVALID 0xffff /* * PCI230 i/o space 1 registers. @@ -427,16 +421,15 @@ * (Potentially) shared resources and their owners */ enum { - RES_Z2CT0, /* Z2-CT0 */ - RES_Z2CT1, /* Z2-CT1 */ - RES_Z2CT2, /* Z2-CT2 */ - NUM_RESOURCES /* Number of (potentially) shared resources. */ + RES_Z2CT0 = (1U << 0), /* Z2-CT0 */ + RES_Z2CT1 = (1U << 1), /* Z2-CT1 */ + RES_Z2CT2 = (1U << 2) /* Z2-CT2 */ }; enum { - OWNER_NONE, /* Not owned */ OWNER_AICMD, /* Owned by AI command */ - OWNER_AOCMD /* Owned by AO command */ + OWNER_AOCMD, /* Owned by AO command */ + NUM_OWNERS /* Number of owners */ }; /* @@ -449,10 +442,6 @@ enum { /* Current CPU. XXX should this be hard_smp_processor_id()? */ #define THISCPU smp_processor_id() -/* State flags for atomic bit operations */ -#define AI_CMD_STARTED 0 -#define AO_CMD_STARTED 1 - /* * Board descriptions for the two boards supported. */ @@ -460,52 +449,39 @@ enum { struct pci230_board { const char *name; unsigned short id; - int ai_chans; - int ai_bits; - int ao_chans; - int ao_bits; - int have_dio; - unsigned int min_hwver; /* Minimum hardware version supported. */ + unsigned char ai_bits; + unsigned char ao_bits; + unsigned char min_hwver; /* Minimum hardware version supported. */ + bool have_dio:1; }; static const struct pci230_board pci230_boards[] = { { .name = "pci230+", .id = PCI_DEVICE_ID_PCI230, - .ai_chans = 16, .ai_bits = 16, - .ao_chans = 2, .ao_bits = 12, - .have_dio = 1, + .have_dio = true, .min_hwver = 1, }, { .name = "pci260+", .id = PCI_DEVICE_ID_PCI260, - .ai_chans = 16, .ai_bits = 16, .min_hwver = 1, }, { .name = "pci230", .id = PCI_DEVICE_ID_PCI230, - .ai_chans = 16, .ai_bits = 12, - .ao_chans = 2, .ao_bits = 12, - .have_dio = 1, + .have_dio = true, }, { .name = "pci260", .id = PCI_DEVICE_ID_PCI260, - .ai_chans = 16, .ai_bits = 12, }, - { - /* Wildcard matches any above */ - .name = "amplc_pci230", - .id = PCI_DEVICE_ID_INVALID, - }, }; struct pci230_private { @@ -513,9 +489,7 @@ struct pci230_private { spinlock_t res_spinlock; /* Shared resources spin lock */ spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */ spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */ - unsigned long state; /* State flags */ - unsigned long iobase1; /* PCI230's I/O space 1 */ - unsigned int ao_readback[2]; /* Used for AO readback */ + unsigned long daqio; /* PCI230's DAQ I/O space */ unsigned int ai_scan_count; /* Number of AI scans remaining */ unsigned int ai_scan_pos; /* Current position within AI scan */ unsigned int ao_scan_count; /* Number of AO scans remaining. */ @@ -525,12 +499,13 @@ struct pci230_private { unsigned short daccon; /* DACCON register value */ unsigned short adcfifothresh; /* ADC FIFO threshold (PCI230+/260+) */ unsigned short adcg; /* ADCG register value */ - unsigned char int_en; /* Interrupt enable bits */ - unsigned char ai_bipolar; /* Flag AI range is bipolar */ - unsigned char ao_bipolar; /* Flag AO range is bipolar */ - unsigned char ier; /* Copy of interrupt enable register */ - unsigned char intr_running; /* Flag set in interrupt routine */ - unsigned char res_owner[NUM_RESOURCES]; /* Shared resource owners */ + unsigned char ier; /* Interrupt enable bits */ + unsigned char res_owned[NUM_OWNERS]; /* Owned resources */ + bool intr_running:1; /* Flag set in interrupt routine */ + bool ai_bipolar:1; /* Flag AI range is bipolar */ + bool ao_bipolar:1; /* Flag AO range is bipolar */ + bool ai_cmd_started:1; /* Flag AI command started */ + bool ao_cmd_started:1; /* Flag AO command started */ }; /* PCI230 clock source periods in ns */ @@ -558,9 +533,6 @@ static const struct comedi_lrange pci230_ai_range = { /* PCI230 analogue gain bits for each input range. */ static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 }; -/* PCI230 adccon bipolar flag for each analogue input range. */ -static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 }; - /* PCI230 analogue output range table */ static const struct comedi_lrange pci230_ao_range = { 2, { @@ -569,170 +541,122 @@ static const struct comedi_lrange pci230_ao_range = { } }; -/* PCI230 daccon bipolar flag for each analogue output range. */ -static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; - static unsigned short pci230_ai_read(struct comedi_device *dev) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; unsigned short data; /* Read sample. */ - data = inw(dev->iobase + PCI230_ADCDATA); + data = inw(devpriv->daqio + PCI230_ADCDATA); /* * PCI230 is 12 bit - stored in upper bits of 16 bit register * (lower four bits reserved for expansion). PCI230+ is 16 bit AI. - */ - data = data >> (16 - thisboard->ai_bits); - - /* + * * If a bipolar range was specified, mangle it * (twos complement->straight binary). */ if (devpriv->ai_bipolar) - data ^= 1 << (thisboard->ai_bits - 1); - + data ^= 0x8000; + data >>= (16 - thisboard->ai_bits); return data; } -static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, - unsigned short datum) +static unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, + unsigned short datum) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; /* - * If a bipolar range was specified, mangle it - * (straight binary->twos complement). - */ - if (devpriv->ao_bipolar) - datum ^= 1 << (thisboard->ao_bits - 1); - - /* * PCI230 is 12 bit - stored in upper bits of 16 bit register (lower * four bits reserved for expansion). PCI230+ is also 12 bit AO. */ datum <<= (16 - thisboard->ao_bits); + /* + * If a bipolar range was specified, mangle it + * (straight binary->twos complement). + */ + if (devpriv->ao_bipolar) + datum ^= 0x8000; return datum; } -static inline void pci230_ao_write_nofifo(struct comedi_device *dev, - unsigned short datum, - unsigned int chan) +static void pci230_ao_write_nofifo(struct comedi_device *dev, + unsigned short datum, unsigned int chan) { struct pci230_private *devpriv = dev->private; - /* Store unmangled datum to be read back later. */ - devpriv->ao_readback[chan] = datum; - /* Write mangled datum to appropriate DACOUT register. */ outw(pci230_ao_mangle_datum(dev, datum), - dev->iobase + (((chan) == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2)); + devpriv->daqio + ((chan == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2)); } -static inline void pci230_ao_write_fifo(struct comedi_device *dev, - unsigned short datum, unsigned int chan) +static void pci230_ao_write_fifo(struct comedi_device *dev, + unsigned short datum, unsigned int chan) { struct pci230_private *devpriv = dev->private; - /* Store unmangled datum to be read back later. */ - devpriv->ao_readback[chan] = datum; - /* Write mangled datum to appropriate DACDATA register. */ outw(pci230_ao_mangle_datum(dev, datum), - dev->iobase + PCI230P2_DACDATA); + devpriv->daqio + PCI230P2_DACDATA); } -static int get_resources(struct comedi_device *dev, unsigned int res_mask, - unsigned char owner) +static bool pci230_claim_shared(struct comedi_device *dev, + unsigned char res_mask, unsigned int owner) { struct pci230_private *devpriv = dev->private; - int ok; - unsigned int i; - unsigned int b; - unsigned int claimed; + unsigned int o; unsigned long irqflags; - ok = 1; - claimed = 0; spin_lock_irqsave(&devpriv->res_spinlock, irqflags); - for (b = 1, i = 0; (i < NUM_RESOURCES) && res_mask; b <<= 1, i++) { - if (res_mask & b) { - res_mask &= ~b; - if (devpriv->res_owner[i] == OWNER_NONE) { - devpriv->res_owner[i] = owner; - claimed |= b; - } else if (devpriv->res_owner[i] != owner) { - for (b = 1, i = 0; claimed; b <<= 1, i++) { - if (claimed & b) { - devpriv->res_owner[i] = - OWNER_NONE; - claimed &= ~b; - } - } - ok = 0; - break; - } + for (o = 0; o < NUM_OWNERS; o++) { + if (o == owner) + continue; + if (devpriv->res_owned[o] & res_mask) { + spin_unlock_irqrestore(&devpriv->res_spinlock, + irqflags); + return false; } } + devpriv->res_owned[owner] |= res_mask; spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); - return ok; -} - -static inline int get_one_resource(struct comedi_device *dev, - unsigned int resource, unsigned char owner) -{ - return get_resources(dev, (1U << resource), owner); + return true; } -static void put_resources(struct comedi_device *dev, unsigned int res_mask, - unsigned char owner) +static void pci230_release_shared(struct comedi_device *dev, + unsigned char res_mask, unsigned int owner) { struct pci230_private *devpriv = dev->private; - unsigned int i; - unsigned int b; unsigned long irqflags; spin_lock_irqsave(&devpriv->res_spinlock, irqflags); - for (b = 1, i = 0; (i < NUM_RESOURCES) && res_mask; b <<= 1, i++) { - if (res_mask & b) { - res_mask &= ~b; - if (devpriv->res_owner[i] == owner) - devpriv->res_owner[i] = OWNER_NONE; - } - } + devpriv->res_owned[owner] &= ~res_mask; spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); } -static inline void put_one_resource(struct comedi_device *dev, - unsigned int resource, unsigned char owner) +static void pci230_release_all_resources(struct comedi_device *dev, + unsigned int owner) { - put_resources(dev, (1U << resource), owner); + pci230_release_shared(dev, (unsigned char)~0, owner); } -static inline void put_all_resources(struct comedi_device *dev, - unsigned char owner) -{ - put_resources(dev, (1U << NUM_RESOURCES) - 1, owner); -} - -static unsigned int divide_ns(uint64_t ns, unsigned int timebase, - unsigned int flags) +static unsigned int pci230_divide_ns(uint64_t ns, unsigned int timebase, + unsigned int flags) { uint64_t div; unsigned int rem; div = ns; rem = do_div(div, timebase); - switch (flags & TRIG_ROUND_MASK) { + switch (flags & CMDF_ROUND_MASK) { default: - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: div += (rem + (timebase / 2)) / timebase; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: div += (rem + timebase - 1) / timebase; break; } @@ -749,8 +673,8 @@ static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count, unsigned int clk_src, cnt; for (clk_src = CLK_10MHZ;; clk_src++) { - cnt = divide_ns(ns, pci230_timebase[clk_src], flags); - if ((cnt <= 65536) || (clk_src == CLK_1KHZ)) + cnt = pci230_divide_ns(ns, pci230_timebase[clk_src], flags); + if (cnt <= 65536 || clk_src == CLK_1KHZ) break; } *count = cnt; @@ -770,29 +694,25 @@ static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, unsigned int mode, uint64_t ns, unsigned int flags) { - struct pci230_private *devpriv = dev->private; unsigned int clk_src; unsigned int count; /* Set mode. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, mode); /* Determine clock source and count. */ clk_src = pci230_choose_clk_count(ns, &count, flags); /* Program clock source. */ - outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE); + outb(CLK_CONFIG(ct, clk_src), dev->iobase + PCI230_ZCLK_SCE); /* Set initial count. */ if (count >= 65536) count = 0; - i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count); + i8254_write(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, count); } static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) { - struct pci230_private *devpriv = dev->private; - - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, - I8254_MODE1); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, I8254_MODE1); /* Counter ct, 8254 mode 1, initial count not written. */ } @@ -801,17 +721,18 @@ static int pci230_ai_eoc(struct comedi_device *dev, struct comedi_insn *insn, unsigned long context) { + struct pci230_private *devpriv = dev->private; unsigned int status; - status = inw(dev->iobase + PCI230_ADCCON); + status = inw(devpriv->daqio + PCI230_ADCCON); if ((status & PCI230_ADC_FIFO_EMPTY) == 0) return 0; return -EBUSY; } -static int pci230_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int pci230_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct pci230_private *devpriv = dev->private; unsigned int n; @@ -842,8 +763,8 @@ static int pci230_ai_rinsn(struct comedi_device *dev, */ adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN; /* Set Z2-CT2 output low to avoid any false triggers. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0); - devpriv->ai_bipolar = pci230_ai_bipolar[range]; + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0); + devpriv->ai_bipolar = comedi_range_is_bipolar(s, range); if (aref == AREF_DIFF) { /* Differential. */ gainshift = chan * 2; @@ -874,19 +795,18 @@ static int pci230_ai_rinsn(struct comedi_device *dev, else adccon |= PCI230_ADC_IR_UNI; - /* * Enable only this channel in the scan list - otherwise by default * we'll get one sample from each channel. */ - outw(adcen, dev->iobase + PCI230_ADCEN); + outw(adcen, devpriv->daqio + PCI230_ADCEN); /* Set gain for channel. */ - outw(devpriv->adcg, dev->iobase + PCI230_ADCG); + outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); /* Specify uni/bip, se/diff, conversion source, and reset FIFO. */ devpriv->adccon = adccon; - outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); + outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON); /* Convert n samples */ for (n = 0; n < insn->n; n++) { @@ -894,10 +814,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev, * Trigger conversion by toggling Z2-CT2 output * (finish with output high). */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE0); - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE1); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, + 2, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, + 2, I8254_MODE1); /* wait for conversion to end */ ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0); @@ -912,57 +832,31 @@ static int pci230_ai_rinsn(struct comedi_device *dev, return n; } -/* - * COMEDI_SUBD_AO instructions; - */ -static int pci230_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int pci230_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pci230_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - int chan, range; - - /* Unpack channel and range. */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); /* * Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ - devpriv->ao_bipolar = pci230_ao_bipolar[range]; - outw(range, dev->iobase + PCI230_DACCON); + devpriv->ao_bipolar = comedi_range_is_bipolar(s, range); + outw(range, devpriv->daqio + PCI230_DACCON); - /* - * Writing a list of values to an AO channel is probably not - * very useful, but that's how the interface is defined. - */ for (i = 0; i < insn->n; i++) { - /* Write value to DAC and store it. */ - pci230_ao_write_nofifo(dev, data[i], chan); + val = data[i]; + pci230_ao_write_nofifo(dev, val, chan); } + s->readback[chan] = val; - /* return the number of samples read/written */ - return i; -} - -/* - * AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. - */ -static int pci230_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct pci230_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int pci230_ao_check_chanlist(struct comedi_device *dev, @@ -1000,7 +894,7 @@ static int pci230_ao_check_chanlist(struct comedi_device *dev, static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; int err = 0; unsigned int tmp; @@ -1010,7 +904,7 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); tmp = TRIG_TIMER | TRIG_INT; - if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) { + if (thisboard->min_hwver > 0 && devpriv->hwver >= 2) { /* * For PCI230+ hardware version 2 onwards, allow external * trigger from EXTTRIG/EXTCONVCLK input (PCI230+ pin 25). @@ -1078,11 +972,11 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, * The only flags allowed are CR_EDGE and CR_INVERT. * The CR_EDGE flag is ignored. */ - if (cmd->scan_begin_arg & - (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) { - cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, - CR_FLAGS_MASK & - ~(CR_EDGE | CR_INVERT)); + if (cmd->scan_begin_arg & CR_FLAGS_MASK & + ~(CR_EDGE | CR_INVERT)) { + cmd->scan_begin_arg = + COMBINE(cmd->scan_begin_arg, 0, + CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT)); err |= -EINVAL; } break; @@ -1093,7 +987,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -1127,11 +1023,12 @@ static void pci230_ao_stop(struct comedi_device *dev, struct pci230_private *devpriv = dev->private; unsigned long irqflags; unsigned char intsrc; - int started; + bool started; struct comedi_cmd *cmd; spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); - started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state); + started = devpriv->ao_cmd_started; + devpriv->ao_cmd_started = false; spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); if (!started) return; @@ -1153,15 +1050,12 @@ static void pci230_ao_stop(struct comedi_device *dev, * unless we are called from the interrupt routine. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en &= ~intsrc; + devpriv->ier &= ~intsrc; while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); } - if (devpriv->ier != devpriv->int_en) { - devpriv->ier = devpriv->int_en; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - } + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); if (devpriv->hwver >= 2) { /* @@ -1171,10 +1065,10 @@ static void pci230_ao_stop(struct comedi_device *dev, devpriv->daccon &= PCI230_DAC_OR_MASK; outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR, - dev->iobase + PCI230_DACCON); + devpriv->daqio + PCI230_DACCON); } /* Release resources. */ - put_all_resources(dev, OWNER_AOCMD); + pci230_release_all_resources(dev, OWNER_AOCMD); } static void pci230_handle_ao_nofifo(struct comedi_device *dev, @@ -1189,6 +1083,8 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) return; for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + /* Read sample from Comedi's circular buffer. */ ret = comedi_buf_get(s, &data); if (ret == 0) { @@ -1197,8 +1093,8 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, dev_err(dev->class_dev, "AO buffer underrun\n"); return; } - /* Write value to DAC. */ - pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i])); + pci230_ao_write_nofifo(dev, data, chan); + s->readback[chan] = data; } async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; if (cmd->stop_src == TRIG_COUNT) { @@ -1211,10 +1107,12 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, } } -/* Loads DAC FIFO (if using it) from buffer. */ -/* Returns 0 if AO finished due to completion or error, 1 if still going. */ -static int pci230_handle_ao_fifo(struct comedi_device *dev, - struct comedi_subdevice *s) +/* + * Loads DAC FIFO (if using it) from buffer. + * Returns false if AO finished due to completion or error, true if still going. + */ +static bool pci230_handle_ao_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pci230_private *devpriv = dev->private; struct comedi_async *async = s->async; @@ -1224,10 +1122,10 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, unsigned short dacstat; unsigned int i, n; unsigned int events = 0; - int running; + bool running; /* Get DAC FIFO status. */ - dacstat = inw(dev->iobase + PCI230_DACCON); + dacstat = inw(devpriv->daqio + PCI230_DACCON); /* Determine number of scans available in buffer. */ num_scans = comedi_buf_read_n_available(s) / cfc_bytes_per_scan(s); if (cmd->stop_src == TRIG_COUNT) { @@ -1250,8 +1148,8 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, * (otherwise there will be loads of "DAC FIFO not half full" * interrupts). */ - if ((num_scans == 0) && - ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) { + if (num_scans == 0 && + (dacstat & PCI230P2_DAC_FIFO_HALF) == 0) { dev_err(dev->class_dev, "AO buffer underrun\n"); events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; } @@ -1274,11 +1172,12 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, /* Process scans. */ for (n = 0; n < num_scans; n++) { for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned short datum; comedi_buf_get(s, &datum); - pci230_ao_write_fifo(dev, datum, - CR_CHAN(cmd->chanlist[i])); + pci230_ao_write_fifo(dev, datum, chan); + s->readback[chan] = datum; } } events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; @@ -1295,11 +1194,11 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, ~PCI230P2_DAC_INT_FIFO_MASK) | PCI230P2_DAC_INT_FIFO_EMPTY; outw(devpriv->daccon, - dev->iobase + PCI230_DACCON); + devpriv->daqio + PCI230_DACCON); } } /* Check if FIFO underrun occurred while writing to FIFO. */ - dacstat = inw(dev->iobase + PCI230_DACCON); + dacstat = inw(devpriv->daqio + PCI230_DACCON); if (dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) { dev_err(dev->class_dev, "AO FIFO underrun\n"); events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; @@ -1308,9 +1207,9 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { /* Stopping AO due to completion or error. */ pci230_ao_stop(dev, s); - running = 0; + running = false; } else { - running = 1; + running = true; } async->events |= events; return running; @@ -1327,28 +1226,25 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, return -EINVAL; spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); - if (test_bit(AO_CMD_STARTED, &devpriv->state)) { - /* Perform scan. */ - if (devpriv->hwver < 2) { - /* Not using DAC FIFO. */ - spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, - irqflags); - pci230_handle_ao_nofifo(dev, s); - comedi_event(dev, s); - } else { - /* Using DAC FIFO. */ - /* Read DACSWTRIG register to trigger conversion. */ - inw(dev->iobase + PCI230P2_DACSWTRIG); - spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, - irqflags); - } - /* Delay. Should driver be responsible for this? */ - /* XXX TODO: See if DAC busy bit can be used. */ - udelay(8); + if (!devpriv->ao_cmd_started) { + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); + return 1; + } + /* Perform scan. */ + if (devpriv->hwver < 2) { + /* Not using DAC FIFO. */ + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); + pci230_handle_ao_nofifo(dev, s); + comedi_event(dev, s); } else { + /* Using DAC FIFO. */ + /* Read DACSWTRIG register to trigger conversion. */ + inw(devpriv->daqio + PCI230P2_DACSWTRIG); spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); } - + /* Delay. Should driver be responsible for this? */ + /* XXX TODO: See if DAC busy bit can be used. */ + udelay(8); return 1; } @@ -1360,84 +1256,71 @@ static void pci230_ao_start(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; unsigned long irqflags; - set_bit(AO_CMD_STARTED, &devpriv->state); - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) { - /* An empty acquisition! */ - async->events |= COMEDI_CB_EOA; - pci230_ao_stop(dev, s); + devpriv->ao_cmd_started = true; + + if (devpriv->hwver >= 2) { + /* Using DAC FIFO. */ + unsigned short scantrig; + bool run; + + /* Preload FIFO data. */ + run = pci230_handle_ao_fifo(dev, s); comedi_event(dev, s); - } else { - if (devpriv->hwver >= 2) { - /* Using DAC FIFO. */ - unsigned short scantrig; - int run; - - /* Preload FIFO data. */ - run = pci230_handle_ao_fifo(dev, s); - comedi_event(dev, s); - if (!run) { - /* Stopped. */ - return; - } - /* Set scan trigger source. */ - switch (cmd->scan_begin_src) { - case TRIG_TIMER: - scantrig = PCI230P2_DAC_TRIG_Z2CT1; - break; - case TRIG_EXT: - /* Trigger on EXTTRIG/EXTCONVCLK pin. */ - if ((cmd->scan_begin_arg & CR_INVERT) == 0) { - /* +ve edge */ - scantrig = PCI230P2_DAC_TRIG_EXTP; - } else { - /* -ve edge */ - scantrig = PCI230P2_DAC_TRIG_EXTN; - } - break; - case TRIG_INT: - scantrig = PCI230P2_DAC_TRIG_SW; - break; - default: - /* Shouldn't get here. */ - scantrig = PCI230P2_DAC_TRIG_NONE; - break; - } - devpriv->daccon = - (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) | - scantrig; - outw(devpriv->daccon, dev->iobase + PCI230_DACCON); + if (!run) { + /* Stopped. */ + return; } + /* Set scan trigger source. */ switch (cmd->scan_begin_src) { case TRIG_TIMER: - if (devpriv->hwver < 2) { - /* Not using DAC FIFO. */ - /* Enable CT1 timer interrupt. */ - spin_lock_irqsave(&devpriv->isr_spinlock, - irqflags); - devpriv->int_en |= PCI230_INT_ZCLK_CT1; - devpriv->ier |= PCI230_INT_ZCLK_CT1; - outb(devpriv->ier, - devpriv->iobase1 + PCI230_INT_SCE); - spin_unlock_irqrestore(&devpriv->isr_spinlock, - irqflags); + scantrig = PCI230P2_DAC_TRIG_Z2CT1; + break; + case TRIG_EXT: + /* Trigger on EXTTRIG/EXTCONVCLK pin. */ + if ((cmd->scan_begin_arg & CR_INVERT) == 0) { + /* +ve edge */ + scantrig = PCI230P2_DAC_TRIG_EXTP; + } else { + /* -ve edge */ + scantrig = PCI230P2_DAC_TRIG_EXTN; } - /* Set CT1 gate high to start counting. */ - outb(GAT_CONFIG(1, GAT_VCC), - devpriv->iobase1 + PCI230_ZGAT_SCE); break; case TRIG_INT: - async->inttrig = pci230_ao_inttrig_scan_begin; + scantrig = PCI230P2_DAC_TRIG_SW; + break; + default: + /* Shouldn't get here. */ + scantrig = PCI230P2_DAC_TRIG_NONE; break; } - if (devpriv->hwver >= 2) { - /* Using DAC FIFO. Enable DAC FIFO interrupt. */ + devpriv->daccon = + (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) | scantrig; + outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON); + } + switch (cmd->scan_begin_src) { + case TRIG_TIMER: + if (devpriv->hwver < 2) { + /* Not using DAC FIFO. */ + /* Enable CT1 timer interrupt. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en |= PCI230P2_INT_DAC; - devpriv->ier |= PCI230P2_INT_DAC; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); + devpriv->ier |= PCI230_INT_ZCLK_CT1; + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); } + /* Set CT1 gate high to start counting. */ + outb(GAT_CONFIG(1, GAT_VCC), dev->iobase + PCI230_ZGAT_SCE); + break; + case TRIG_INT: + async->inttrig = pci230_ao_inttrig_scan_begin; + break; + } + if (devpriv->hwver >= 2) { + /* Using DAC FIFO. Enable DAC FIFO interrupt. */ + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + devpriv->ier |= PCI230P2_INT_DAC; + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); } } @@ -1467,22 +1350,18 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->scan_begin_src == TRIG_TIMER) { /* Claim Z2-CT1. */ - if (!get_one_resource(dev, RES_Z2CT1, OWNER_AOCMD)) + if (!pci230_claim_shared(dev, RES_Z2CT1, OWNER_AOCMD)) return -EBUSY; } - /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->ao_scan_count = cmd->stop_arg; - else /* TRIG_NONE, user calls cancel */ - devpriv->ao_scan_count = 0; + devpriv->ao_scan_count = cmd->stop_arg; /* * Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ range = CR_RANGE(cmd->chanlist[0]); - devpriv->ao_bipolar = pci230_ao_bipolar[range]; + devpriv->ao_bipolar = comedi_range_is_bipolar(s, range); daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI; /* Use DAC FIFO for hardware version 2 onwards. */ if (devpriv->hwver >= 2) { @@ -1494,7 +1373,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dacen |= 1 << CR_CHAN(cmd->chanlist[i]); /* Set channel scan list. */ - outw(dacen, dev->iobase + PCI230P2_DACEN); + outw(dacen, devpriv->daqio + PCI230P2_DACEN); /* * Enable DAC FIFO. * Set DAC scan source to 'none'. @@ -1509,7 +1388,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Set DACCON. */ - outw(daccon, dev->iobase + PCI230_DACCON); + outw(daccon, devpriv->daqio + PCI230_DACCON); /* Preserve most of DACCON apart from write-only, transient bits. */ devpriv->daccon = daccon & ~(PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR); @@ -1520,8 +1399,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * cmd->scan_begin_arg is sampling period in ns. * Gate it off for now. */ - outb(GAT_CONFIG(1, GAT_GND), - devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(GAT_CONFIG(1, GAT_GND), dev->iobase + PCI230_ZGAT_SCE); pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3, cmd->scan_begin_arg, cmd->flags); @@ -1550,8 +1428,8 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) chanlist_len = 1; min_scan_period = chanlist_len * cmd->convert_arg; - if ((min_scan_period < chanlist_len) || - (min_scan_period < cmd->convert_arg)) { + if (min_scan_period < chanlist_len || + min_scan_period < cmd->convert_arg) { /* Arithmetic overflow. */ min_scan_period = UINT_MAX; err++; @@ -1573,7 +1451,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, unsigned int prev_chan = 0; unsigned int prev_range = 0; unsigned int prev_aref = 0; - unsigned int prev_polarity = 0; + bool prev_bipolar = false; unsigned int subseq_len = 0; int i; @@ -1582,7 +1460,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, unsigned int chan = CR_CHAN(chanspec); unsigned int range = CR_RANGE(chanspec); unsigned int aref = CR_AREF(chanspec); - unsigned int polarity = pci230_ai_bipolar[range]; + bool bipolar = comedi_range_is_bipolar(s, range); if (aref == AREF_DIFF && chan >= max_diff_chan) { dev_dbg(dev->class_dev, @@ -1614,7 +1492,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, return -EINVAL; } - if (polarity != prev_polarity) { + if (bipolar != prev_bipolar) { dev_dbg(dev->class_dev, "%s: channel sequence ranges must be all bipolar or all unipolar\n", __func__); @@ -1632,7 +1510,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, prev_chan = chan; prev_range = range; prev_aref = aref; - prev_polarity = polarity; + prev_bipolar = bipolar; } if (subseq_len == 0) @@ -1670,7 +1548,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; int err = 0; unsigned int tmp; @@ -1680,7 +1558,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT; - if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) { + if (thisboard->have_dio || thisboard->min_hwver > 0) { /* * Unfortunately, we cannot trigger a scan off an external * source on the PCI260 board, since it uses the PPIC0 (DIO) @@ -1711,8 +1589,8 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, * If scan_begin_src is not TRIG_FOLLOW, then a monostable will be * set up to generate a fixed number of timed conversion pulses. */ - if ((cmd->scan_begin_src != TRIG_FOLLOW) && - (cmd->convert_src != TRIG_TIMER)) + if (cmd->scan_begin_src != TRIG_FOLLOW && + cmd->convert_src != TRIG_TIMER) err |= -EINVAL; if (err) @@ -1739,7 +1617,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, * PCI230 or PCI260. Max speed depends whether * single-ended or pseudo-differential. */ - if (cmd->chanlist && (cmd->chanlist_len > 0)) { + if (cmd->chanlist && cmd->chanlist_len > 0) { /* Peek analogue reference of first channel. */ if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) max_speed_ai = MAX_SPEED_AI_DIFF; @@ -1779,13 +1657,12 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, * The only flags allowed are CR_INVERT and CR_EDGE. * CR_EDGE is required. */ - if ((cmd->convert_arg & - (CR_FLAGS_MASK & ~CR_INVERT)) != CR_EDGE) { + if ((cmd->convert_arg & CR_FLAGS_MASK & ~CR_INVERT) != + CR_EDGE) { /* Set CR_EDGE, preserve CR_INVERT. */ - cmd->convert_arg = COMBINE(cmd->start_arg, - (CR_EDGE | 0), - CR_FLAGS_MASK & - ~CR_INVERT); + cmd->convert_arg = + COMBINE(cmd->start_arg, CR_EDGE | 0, + CR_FLAGS_MASK & ~CR_INVERT); err |= -EINVAL; } } else { @@ -1802,7 +1679,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (cmd->scan_begin_src == TRIG_EXT) { @@ -1850,7 +1729,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if (!pci230_ai_check_scan_period(cmd)) { /* Was below minimum required. Round up. */ pci230_ns_to_single_timer(&cmd->scan_begin_arg, - TRIG_ROUND_UP); + CMDF_ROUND_UP); pci230_ai_check_scan_period(cmd); } if (tmp != cmd->scan_begin_arg) @@ -1880,37 +1759,30 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, unsigned short triglev; unsigned short adccon; - if (cmd->flags & TRIG_WAKE_EOS) { - /* Wake at end of scan. */ + if (cmd->flags & CMDF_WAKE_EOS) wake = scanlen - devpriv->ai_scan_pos; - } else { - if (cmd->stop_src != TRIG_COUNT || - devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || - scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) { - wake = PCI230_ADC_FIFOLEVEL_HALFFULL; - } else { - wake = (devpriv->ai_scan_count * scanlen) - - devpriv->ai_scan_pos; - } - } + else if (cmd->stop_src != TRIG_COUNT || + devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) + wake = PCI230_ADC_FIFOLEVEL_HALFFULL; + else + wake = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos; if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) { triglev = PCI230_ADC_INT_FIFO_HALF; - } else { - if ((wake > 1) && (devpriv->hwver > 0)) { - /* PCI230+/260+ programmable FIFO interrupt level. */ - if (devpriv->adcfifothresh != wake) { - devpriv->adcfifothresh = wake; - outw(wake, dev->iobase + PCI230P_ADCFFTH); - } - triglev = PCI230P_ADC_INT_FIFO_THRESH; - } else { - triglev = PCI230_ADC_INT_FIFO_NEMPTY; + } else if (wake > 1 && devpriv->hwver > 0) { + /* PCI230+/260+ programmable FIFO interrupt level. */ + if (devpriv->adcfifothresh != wake) { + devpriv->adcfifothresh = wake; + outw(wake, devpriv->daqio + PCI230P_ADCFFTH); } + triglev = PCI230P_ADC_INT_FIFO_THRESH; + } else { + triglev = PCI230_ADC_INT_FIFO_NEMPTY; } adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev; if (adccon != devpriv->adccon) { devpriv->adccon = adccon; - outw(adccon, dev->iobase + PCI230_ADCCON); + outw(adccon, devpriv->daqio + PCI230_ADCCON); } } @@ -1920,43 +1792,39 @@ static int pci230_ai_inttrig_convert(struct comedi_device *dev, { struct pci230_private *devpriv = dev->private; unsigned long irqflags; + unsigned int delayus; if (trig_num) return -EINVAL; spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - if (test_bit(AI_CMD_STARTED, &devpriv->state)) { - unsigned int delayus; - - /* - * Trigger conversion by toggling Z2-CT2 output. - * Finish with output high. - */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE0); - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE1); - /* - * Delay. Should driver be responsible for this? An - * alternative would be to wait until conversion is complete, - * but we can't tell when it's complete because the ADC busy - * bit has a different meaning when FIFO enabled (and when - * FIFO not enabled, it only works for software triggers). - */ - if (((devpriv->adccon & PCI230_ADC_IM_MASK) == - PCI230_ADC_IM_DIF) && (devpriv->hwver == 0)) { - /* PCI230/260 in differential mode */ - delayus = 8; - } else { - /* single-ended or PCI230+/260+ */ - delayus = 4; - } + if (!devpriv->ai_cmd_started) { spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); - udelay(delayus); + return 1; + } + /* + * Trigger conversion by toggling Z2-CT2 output. + * Finish with output high. + */ + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); + /* + * Delay. Should driver be responsible for this? An + * alternative would be to wait until conversion is complete, + * but we can't tell when it's complete because the ADC busy + * bit has a different meaning when FIFO enabled (and when + * FIFO not enabled, it only works for software triggers). + */ + if ((devpriv->adccon & PCI230_ADC_IM_MASK) == PCI230_ADC_IM_DIF && + devpriv->hwver == 0) { + /* PCI230/260 in differential mode */ + delayus = 8; } else { - spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + /* single-ended or PCI230+/260+ */ + delayus = 4; } - + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + udelay(delayus); return 1; } @@ -1972,12 +1840,12 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev, return -EINVAL; spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - if (test_bit(AI_CMD_STARTED, &devpriv->state)) { + if (devpriv->ai_cmd_started) { /* Trigger scan by waggling CT0 gate source. */ zgat = GAT_CONFIG(0, GAT_GND); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); zgat = GAT_CONFIG(0, GAT_VCC); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); } spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); @@ -1990,10 +1858,11 @@ static void pci230_ai_stop(struct comedi_device *dev, struct pci230_private *devpriv = dev->private; unsigned long irqflags; struct comedi_cmd *cmd; - int started; + bool started; spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state); + started = devpriv->ai_cmd_started; + devpriv->ai_cmd_started = false; spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); if (!started) return; @@ -2011,15 +1880,12 @@ static void pci230_ai_stop(struct comedi_device *dev, * Disable ADC interrupt and wait for interrupt routine to finish * running unless we are called from the interrupt routine. */ - devpriv->int_en &= ~PCI230_INT_ADC; + devpriv->ier &= ~PCI230_INT_ADC; while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); } - if (devpriv->ier != devpriv->int_en) { - devpriv->ier = devpriv->int_en; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - } + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); /* * Reset FIFO, disable FIFO and set start conversion source to none. @@ -2029,9 +1895,9 @@ static void pci230_ai_stop(struct comedi_device *dev, (devpriv->adccon & (PCI230_ADC_IR_MASK | PCI230_ADC_IM_MASK)) | PCI230_ADC_TRIG_NONE; outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, - dev->iobase + PCI230_ADCCON); + devpriv->daqio + PCI230_ADCCON); /* Release resources. */ - put_all_resources(dev, OWNER_AICMD); + pci230_release_all_resources(dev, OWNER_AICMD); } static void pci230_ai_start(struct comedi_device *dev, @@ -2043,145 +1909,132 @@ static void pci230_ai_start(struct comedi_device *dev, struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - set_bit(AI_CMD_STARTED, &devpriv->state); - if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { - /* An empty acquisition! */ - async->events |= COMEDI_CB_EOA; - pci230_ai_stop(dev, s); - comedi_event(dev, s); - } else { - /* Enable ADC FIFO trigger level interrupt. */ - spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en |= PCI230_INT_ADC; - devpriv->ier |= PCI230_INT_ADC; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + devpriv->ai_cmd_started = true; - /* - * Update conversion trigger source which is currently set - * to CT2 output, which is currently stuck high. - */ - switch (cmd->convert_src) { - default: - conv = PCI230_ADC_TRIG_NONE; - break; - case TRIG_TIMER: - /* Using CT2 output. */ - conv = PCI230_ADC_TRIG_Z2CT2; - break; - case TRIG_EXT: - if (cmd->convert_arg & CR_EDGE) { - if ((cmd->convert_arg & CR_INVERT) == 0) { - /* Trigger on +ve edge. */ - conv = PCI230_ADC_TRIG_EXTP; - } else { - /* Trigger on -ve edge. */ - conv = PCI230_ADC_TRIG_EXTN; - } + /* Enable ADC FIFO trigger level interrupt. */ + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + devpriv->ier |= PCI230_INT_ADC; + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + + /* + * Update conversion trigger source which is currently set + * to CT2 output, which is currently stuck high. + */ + switch (cmd->convert_src) { + default: + conv = PCI230_ADC_TRIG_NONE; + break; + case TRIG_TIMER: + /* Using CT2 output. */ + conv = PCI230_ADC_TRIG_Z2CT2; + break; + case TRIG_EXT: + if (cmd->convert_arg & CR_EDGE) { + if ((cmd->convert_arg & CR_INVERT) == 0) { + /* Trigger on +ve edge. */ + conv = PCI230_ADC_TRIG_EXTP; } else { - /* Backwards compatibility. */ - if (cmd->convert_arg) { - /* Trigger on +ve edge. */ - conv = PCI230_ADC_TRIG_EXTP; - } else { - /* Trigger on -ve edge. */ - conv = PCI230_ADC_TRIG_EXTN; - } + /* Trigger on -ve edge. */ + conv = PCI230_ADC_TRIG_EXTN; + } + } else { + /* Backwards compatibility. */ + if (cmd->convert_arg) { + /* Trigger on +ve edge. */ + conv = PCI230_ADC_TRIG_EXTP; + } else { + /* Trigger on -ve edge. */ + conv = PCI230_ADC_TRIG_EXTN; } - break; - case TRIG_INT: - /* - * Use CT2 output for software trigger due to problems - * in differential mode on PCI230/260. - */ - conv = PCI230_ADC_TRIG_Z2CT2; - break; } - devpriv->adccon = - (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv; - outw(devpriv->adccon, dev->iobase + PCI230_ADCCON); - if (cmd->convert_src == TRIG_INT) - async->inttrig = pci230_ai_inttrig_convert; - + break; + case TRIG_INT: /* - * Update FIFO interrupt trigger level, which is currently - * set to "full". + * Use CT2 output for software trigger due to problems + * in differential mode on PCI230/260. */ - pci230_ai_update_fifo_trigger_level(dev, s); - if (cmd->convert_src == TRIG_TIMER) { - /* Update timer gates. */ - unsigned char zgat; + conv = PCI230_ADC_TRIG_Z2CT2; + break; + } + devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv; + outw(devpriv->adccon, devpriv->daqio + PCI230_ADCCON); + if (cmd->convert_src == TRIG_INT) + async->inttrig = pci230_ai_inttrig_convert; - if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* + * Update FIFO interrupt trigger level, which is currently + * set to "full". + */ + pci230_ai_update_fifo_trigger_level(dev, s); + if (cmd->convert_src == TRIG_TIMER) { + /* Update timer gates. */ + unsigned char zgat; + + if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* + * Conversion timer CT2 needs to be gated by + * inverted output of monostable CT2. + */ + zgat = GAT_CONFIG(2, GAT_NOUTNM2); + } else { + /* + * Conversion timer CT2 needs to be gated on + * continuously. + */ + zgat = GAT_CONFIG(2, GAT_VCC); + } + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); + if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* Set monostable CT0 trigger source. */ + switch (cmd->scan_begin_src) { + default: + zgat = GAT_CONFIG(0, GAT_VCC); + break; + case TRIG_EXT: /* - * Conversion timer CT2 needs to be gated by - * inverted output of monostable CT2. + * For CT0 on PCI230, the external trigger + * (gate) signal comes from PPC0, which is + * channel 16 of the DIO subdevice. The + * application needs to configure this as an + * input in order to use it as an external scan + * trigger. */ - zgat = GAT_CONFIG(2, GAT_NOUTNM2); - } else { + zgat = GAT_CONFIG(0, GAT_EXT); + break; + case TRIG_TIMER: /* - * Conversion timer CT2 needs to be gated on - * continuously. + * Monostable CT0 triggered by rising edge on + * inverted output of CT1 (falling edge on CT1). */ - zgat = GAT_CONFIG(2, GAT_VCC); + zgat = GAT_CONFIG(0, GAT_NOUTNM2); + break; + case TRIG_INT: + /* + * Monostable CT0 is triggered by inttrig + * function waggling the CT0 gate source. + */ + zgat = GAT_CONFIG(0, GAT_VCC); + break; } - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); - if (cmd->scan_begin_src != TRIG_FOLLOW) { - /* Set monostable CT0 trigger source. */ - switch (cmd->scan_begin_src) { - default: - zgat = GAT_CONFIG(0, GAT_VCC); - break; - case TRIG_EXT: - /* - * For CT0 on PCI230, the external - * trigger (gate) signal comes from - * PPC0, which is channel 16 of the DIO - * subdevice. The application needs to - * configure this as an input in order - * to use it as an external scan - * trigger. - */ - zgat = GAT_CONFIG(0, GAT_EXT); - break; - case TRIG_TIMER: - /* - * Monostable CT0 triggered by rising - * edge on inverted output of CT1 - * (falling edge on CT1). - */ - zgat = GAT_CONFIG(0, GAT_NOUTNM2); - break; - case TRIG_INT: - /* - * Monostable CT0 is triggered by - * inttrig function waggling the CT0 - * gate source. - */ - zgat = GAT_CONFIG(0, GAT_VCC); - break; - } - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); - switch (cmd->scan_begin_src) { - case TRIG_TIMER: - /* - * Scan period timer CT1 needs to be - * gated on to start counting. - */ - zgat = GAT_CONFIG(1, GAT_VCC); - outb(zgat, devpriv->iobase1 + - PCI230_ZGAT_SCE); - break; - case TRIG_INT: - async->inttrig = - pci230_ai_inttrig_scan_begin; - break; - } + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); + switch (cmd->scan_begin_src) { + case TRIG_TIMER: + /* + * Scan period timer CT1 needs to be + * gated on to start counting. + */ + zgat = GAT_CONFIG(1, GAT_VCC); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); + break; + case TRIG_INT: + async->inttrig = pci230_ai_inttrig_scan_begin; + break; } - } else if (cmd->convert_src != TRIG_INT) { - /* No longer need Z2-CT2. */ - put_one_resource(dev, RES_Z2CT2, OWNER_AICMD); } + } else if (cmd->convert_src != TRIG_INT) { + /* No longer need Z2-CT2. */ + pci230_release_shared(dev, RES_Z2CT2, OWNER_AICMD); } } @@ -2218,12 +2071,11 @@ static void pci230_handle_ai(struct comedi_device *dev, todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } else if (devpriv->ai_scan_count == 0) { todo = 0; - } else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL) || - (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) { + } else if (devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL) { todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } else { - todo = (devpriv->ai_scan_count * scanlen) - - devpriv->ai_scan_pos; + todo = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos; if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL) todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } @@ -2233,7 +2085,7 @@ static void pci230_handle_ai(struct comedi_device *dev, for (i = 0; i < todo; i++) { if (fifoamount == 0) { /* Read FIFO state. */ - status_fifo = inw(dev->iobase + PCI230_ADCCON); + status_fifo = inw(devpriv->daqio + PCI230_ADCCON); if (status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) { /* * Report error otherwise FIFO overruns will go @@ -2248,19 +2100,15 @@ static void pci230_handle_ai(struct comedi_device *dev, } else if (status_fifo & PCI230_ADC_FIFO_HALF) { /* FIFO half full. */ fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL; + } else if (devpriv->hwver > 0) { + /* Read PCI230+/260+ ADC FIFO level. */ + fifoamount = inw(devpriv->daqio + + PCI230P_ADCFFLEV); + if (fifoamount == 0) + break; /* Shouldn't happen. */ } else { /* FIFO not empty. */ - if (devpriv->hwver > 0) { - /* Read PCI230+/260+ ADC FIFO level. */ - fifoamount = - inw(dev->iobase + PCI230P_ADCFFLEV); - if (fifoamount == 0) { - /* Shouldn't happen. */ - break; - } - } else { - fifoamount = 1; - } + fifoamount = 1; } } /* Read sample and store in Comedi's circular buffer. */ @@ -2316,25 +2164,20 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * Need Z2-CT2 to supply a conversion trigger source at a high * logic level, even if not doing timed conversions. */ - res_mask |= (1U << RES_Z2CT2); + res_mask |= RES_Z2CT2; if (cmd->scan_begin_src != TRIG_FOLLOW) { /* Using Z2-CT0 monostable to gate Z2-CT2 conversion timer */ - res_mask |= (1U << RES_Z2CT0); + res_mask |= RES_Z2CT0; if (cmd->scan_begin_src == TRIG_TIMER) { /* Using Z2-CT1 for scan frequency */ - res_mask |= (1U << RES_Z2CT1); + res_mask |= RES_Z2CT1; } } /* Claim resources. */ - if (!get_resources(dev, res_mask, OWNER_AICMD)) + if (!pci230_claim_shared(dev, res_mask, OWNER_AICMD)) return -EBUSY; - - /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scan_count = cmd->stop_arg; - else /* TRIG_NONE, user calls cancel */ - devpriv->ai_scan_count = 0; + devpriv->ai_scan_count = cmd->stop_arg; devpriv->ai_scan_pos = 0; /* Position within scan. */ /* @@ -2369,7 +2212,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } range = CR_RANGE(cmd->chanlist[0]); - devpriv->ai_bipolar = pci230_ai_bipolar[range]; + devpriv->ai_bipolar = comedi_range_is_bipolar(s, range); if (devpriv->ai_bipolar) adccon |= PCI230_ADC_IR_BIP; else @@ -2396,7 +2239,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) adcen |= 1 << gainshift; } } else { - gainshift = (chan & ~1); + gainshift = chan & ~1; adcen |= 1 << chan; } devpriv->adcg = (devpriv->adcg & ~(3 << gainshift)) | @@ -2404,16 +2247,16 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Set channel scan list. */ - outw(adcen, dev->iobase + PCI230_ADCEN); + outw(adcen, devpriv->daqio + PCI230_ADCEN); /* Set channel gains. */ - outw(devpriv->adcg, dev->iobase + PCI230_ADCG); + outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); /* * Set counter/timer 2 output high for use as the initial start * conversion source. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); /* * Temporarily use CT2 output as conversion trigger source and @@ -2429,7 +2272,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * PCI230/260, but that will be dealt with later. */ devpriv->adccon = adccon; - outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); + outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON); /* * Delay - @@ -2443,7 +2286,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) usleep_range(25, 100); /* Reset FIFO again. */ - outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); + outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON); if (cmd->convert_src == TRIG_TIMER) { /* @@ -2452,7 +2295,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * connector: PCI230 pin 21, PCI260 pin 18. */ zgat = GAT_CONFIG(2, GAT_GND); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); /* Set counter/timer 2 to the specified conversion period. */ pci230_ct_setup_ns_mode(dev, 2, I8254_MODE3, cmd->convert_arg, cmd->flags); @@ -2470,11 +2313,11 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * source will be changed later. */ zgat = GAT_CONFIG(0, GAT_VCC); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); pci230_ct_setup_ns_mode(dev, 0, I8254_MODE1, ((uint64_t)cmd->convert_arg * cmd->scan_end_arg), - TRIG_ROUND_UP); + CMDF_ROUND_UP); if (cmd->scan_begin_src == TRIG_TIMER) { /* * Monostable on CT0 will be triggered by @@ -2483,7 +2326,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * Set up CT1 but gate it off for now. */ zgat = GAT_CONFIG(1, GAT_GND); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3, cmd->scan_begin_arg, cmd->flags); @@ -2509,29 +2352,28 @@ static int pci230_ai_cancel(struct comedi_device *dev, /* Interrupt handler */ static irqreturn_t pci230_interrupt(int irq, void *d) { - unsigned char status_int, valid_status_int; + unsigned char status_int, valid_status_int, temp_ier; struct comedi_device *dev = (struct comedi_device *)d; struct pci230_private *devpriv = dev->private; struct comedi_subdevice *s; unsigned long irqflags; /* Read interrupt status/enable register. */ - status_int = inb(devpriv->iobase1 + PCI230_INT_STAT); + status_int = inb(dev->iobase + PCI230_INT_STAT); if (status_int == PCI230_INT_DISABLE) return IRQ_NONE; - spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - valid_status_int = devpriv->int_en & status_int; + valid_status_int = devpriv->ier & status_int; /* * Disable triggered interrupts. * (Only those interrupts that need re-enabling, are, later in the * handler). */ - devpriv->ier = devpriv->int_en & ~status_int; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - devpriv->intr_running = 1; + temp_ier = devpriv->ier & ~status_int; + outb(temp_ier, dev->iobase + PCI230_INT_SCE); + devpriv->intr_running = true; devpriv->intr_cpuid = THISCPU; spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); @@ -2563,11 +2405,9 @@ static irqreturn_t pci230_interrupt(int irq, void *d) /* Reenable interrupts. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - if (devpriv->ier != devpriv->int_en) { - devpriv->ier = devpriv->int_en; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - } - devpriv->intr_running = 0; + if (devpriv->ier != temp_ier) + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); + devpriv->intr_running = false; spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); return IRQ_HANDLED; @@ -2603,49 +2443,17 @@ static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev) return NULL; } -/* Look for PCI device matching requested board name, bus and slot. */ -static struct pci_dev *pci230_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - const struct pci230_board *thisboard = comedi_board(dev); - struct pci_dev *pci_dev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pci_dev) { - /* Check vendor ID (same for all supported PCI boards). */ - if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON) - continue; - /* If bus/slot specified, check them. */ - if ((bus || slot) && - (bus != pci_dev->bus->number || - slot != PCI_SLOT(pci_dev->devfn))) - continue; - if (thisboard->id == PCI_DEVICE_ID_INVALID) { - /* Wildcard board matches any supported PCI board. */ - const struct pci230_board *foundboard; - - foundboard = pci230_find_pci_board(pci_dev); - if (foundboard == NULL) - continue; - /* Replace wildcard board_ptr. */ - dev->board_ptr = foundboard; - } else { - /* Need to match a specific board. */ - if (!pci230_match_pci_board(thisboard, pci_dev)) - continue; - } - return pci_dev; - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -static int pci230_alloc_private(struct comedi_device *dev) +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 *thisboard; 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) @@ -2655,22 +2463,14 @@ static int pci230_alloc_private(struct comedi_device *dev) spin_lock_init(&devpriv->res_spinlock); spin_lock_init(&devpriv->ai_stop_spinlock); spin_lock_init(&devpriv->ao_stop_spinlock); - return 0; -} - -/* Common part of attach and auto_attach. */ -static int pci230_attach_common(struct comedi_device *dev, - struct pci_dev *pci_dev) -{ - const struct pci230_board *thisboard = comedi_board(dev); - struct pci230_private *devpriv = dev->private; - struct comedi_subdevice *s; - unsigned long iobase1, iobase2; - /* PCI230's I/O spaces 1 and 2 respectively. */ - int rc; - - comedi_set_hw_dev(dev, &pci_dev->dev); + dev->board_ptr = pci230_find_pci_board(pci_dev); + if (dev->board_ptr == NULL) { + dev_err(dev->class_dev, + "amplc_pci230: BUG! cannot determine board type!\n"); + return -EINVAL; + } + thisboard = dev->board_ptr; dev->board_name = thisboard->name; rc = comedi_pci_enable(dev); @@ -2681,15 +2481,14 @@ static int pci230_attach_common(struct comedi_device *dev, * Read base addresses of the PCI230's two I/O regions from PCI * configuration register. */ - iobase1 = pci_resource_start(pci_dev, 2); - iobase2 = pci_resource_start(pci_dev, 3); + 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, iobase1, iobase2); - devpriv->iobase1 = iobase1; - dev->iobase = iobase2; + dev->board_name, dev->iobase, devpriv->daqio); /* Read bits of DACCON register - only the output range. */ - devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK; + devpriv->daccon = inw(devpriv->daqio + PCI230_DACCON) & + PCI230_DAC_OR_MASK; /* * Read hardware version register and set extended function register * if they exist. @@ -2697,7 +2496,7 @@ static int pci230_attach_common(struct comedi_device *dev, if (pci_resource_len(pci_dev, 3) >= 32) { unsigned short extfunc = 0; - devpriv->hwver = inw(dev->iobase + PCI230P_HWVER); + devpriv->hwver = inw(devpriv->daqio + PCI230P_HWVER); if (devpriv->hwver < thisboard->min_hwver) { dev_err(dev->class_dev, "%s - bad hardware version - got %u, need %u\n", @@ -2716,13 +2515,12 @@ static int pci230_attach_common(struct comedi_device *dev, */ extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG; } - if ((thisboard->ao_chans > 0) && - (devpriv->hwver >= 2)) { + if (thisboard->ao_bits && devpriv->hwver >= 2) { /* Enable DAC FIFO functionality. */ extfunc |= PCI230P2_EXTFUNC_DACFIFO; } } - outw(extfunc, dev->iobase + PCI230P_EXTFUNC); + outw(extfunc, devpriv->daqio + PCI230P_EXTFUNC); if (extfunc & PCI230P2_EXTFUNC_DACFIFO) { /* * Temporarily enable DAC FIFO, reset it and disable @@ -2730,23 +2528,23 @@ static int pci230_attach_common(struct comedi_device *dev, */ outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN | PCI230P2_DAC_FIFO_RESET, - dev->iobase + PCI230_DACCON); + devpriv->daqio + PCI230_DACCON); /* Clear DAC FIFO channel enable register. */ - outw(0, dev->iobase + PCI230P2_DACEN); + outw(0, devpriv->daqio + PCI230P2_DACEN); /* Disable DAC FIFO. */ - outw(devpriv->daccon, dev->iobase + PCI230_DACCON); + outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON); } } /* Disable board's interrupts. */ - outb(0, devpriv->iobase1 + PCI230_INT_SCE); + 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(1 << 0, dev->iobase + PCI230_ADCEN); - outw(devpriv->adcg, dev->iobase + PCI230_ADCG); + outw(1 << 0, devpriv->daqio + PCI230_ADCEN); + outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, - dev->iobase + PCI230_ADCCON); + devpriv->daqio + PCI230_ADCCON); if (pci_dev->irq) { rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED, @@ -2763,10 +2561,10 @@ static int pci230_attach_common(struct comedi_device *dev, /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; - s->n_chan = thisboard->ai_chans; + s->n_chan = 16; s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &pci230_ai_range; - s->insn_read = pci230_ai_rinsn; + s->insn_read = pci230_ai_insn_read; s->len_chanlist = 256; /* but there are restrictions. */ if (dev->irq) { dev->read_subdev = s; @@ -2778,15 +2576,15 @@ static int pci230_attach_common(struct comedi_device *dev, s = &dev->subdevices[1]; /* analog output subdevice */ - if (thisboard->ao_chans > 0) { + if (thisboard->ao_bits) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = thisboard->ao_chans; + s->n_chan = 2; s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = &pci230_ao_range; - s->insn_write = pci230_ao_winsn; - s->insn_read = pci230_ao_rinsn; - s->len_chanlist = thisboard->ao_chans; + s->insn_write = pci230_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + s->len_chanlist = 2; if (dev->irq) { dev->write_subdev = s; s->subdev_flags |= SDF_CMD_WRITE; @@ -2794,6 +2592,10 @@ static int pci230_attach_common(struct comedi_device *dev, 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; } @@ -2801,8 +2603,7 @@ static int pci230_attach_common(struct comedi_device *dev, s = &dev->subdevices[2]; /* digital i/o subdevice */ if (thisboard->have_dio) { - rc = subdev_8255_init(dev, s, NULL, - devpriv->iobase1 + PCI230_PPI_X_BASE); + rc = subdev_8255_init(dev, s, NULL, PCI230_PPI_X_BASE); if (rc) return rc; } else { @@ -2812,74 +2613,11 @@ static int pci230_attach_common(struct comedi_device *dev, return 0; } -static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct pci230_board *thisboard = comedi_board(dev); - struct pci_dev *pci_dev; - int rc; - - dev_info(dev->class_dev, "amplc_pci230: attach %s %d,%d\n", - thisboard->name, it->options[0], it->options[1]); - - rc = pci230_alloc_private(dev); - if (rc) - return rc; - - pci_dev = pci230_find_pci_dev(dev, it); - if (!pci_dev) - return -EIO; - return pci230_attach_common(dev, pci_dev); -} - -static int pci230_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pci_dev = comedi_to_pci_dev(dev); - int rc; - - dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n", - pci_name(pci_dev)); - - rc = pci230_alloc_private(dev); - if (rc) - return rc; - - dev->board_ptr = pci230_find_pci_board(pci_dev); - if (dev->board_ptr == NULL) { - dev_err(dev->class_dev, - "amplc_pci230: BUG! cannot determine board type!\n"); - return -EINVAL; - } - /* - * Need to 'get' the PCI device to match the 'put' in pci230_detach(). - * TODO: Remove the pci_dev_get() and matching pci_dev_put() once - * support for manual attachment of PCI devices via pci230_attach() - * has been removed. - */ - pci_dev_get(pci_dev); - return pci230_attach_common(dev, pci_dev); -} - -static void pci230_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); - if (pcidev) - pci_dev_put(pcidev); -} - static struct comedi_driver amplc_pci230_driver = { .driver_name = "amplc_pci230", .module = THIS_MODULE, - .attach = pci230_attach, .auto_attach = pci230_auto_attach, - .detach = pci230_detach, - .board_name = &pci230_boards[0].name, - .offset = sizeof(pci230_boards[0]), - .num_names = ARRAY_SIZE(pci230_boards), + .detach = comedi_pci_detach, }; static int amplc_pci230_pci_probe(struct pci_dev *dev, @@ -2905,5 +2643,5 @@ static struct pci_driver amplc_pci230_pci_driver = { module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Amplicon PCI230(+) and PCI260(+)"); MODULE_LICENSE("GPL"); |