diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/ni_labpc_common.c')
-rw-r--r-- | drivers/staging/comedi/drivers/ni_labpc_common.c | 239 |
1 files changed, 121 insertions, 118 deletions
diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c index b88ee26..863afb2 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_common.c +++ b/drivers/staging/comedi/drivers/ni_labpc_common.c @@ -20,12 +20,12 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/slab.h> #include "../comedidev.h" -#include "8253.h" +#include "comedi_8254.h" #include "8255.h" -#include "comedi_fc.h" #include "ni_labpc.h" #include "ni_labpc_regs.h" #include "ni_labpc_isadma.h" @@ -108,32 +108,6 @@ static void labpc_writeb(struct comedi_device *dev, writeb(byte, dev->mmio + reg); } -static void labpc_counter_load(struct comedi_device *dev, - unsigned long reg, - unsigned int counter_number, - unsigned int count, - unsigned int mode) -{ - if (dev->mmio) { - i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode); - i8254_mm_write(dev->mmio + reg, 0, counter_number, count); - } else { - i8254_set_mode(dev->iobase + reg, 0, counter_number, mode); - i8254_write(dev->iobase + reg, 0, counter_number, count); - } -} - -static void labpc_counter_set_mode(struct comedi_device *dev, - unsigned long reg, - unsigned int counter_number, - unsigned int mode) -{ - if (dev->mmio) - i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode); - else - i8254_set_mode(dev->iobase + reg, 0, counter_number, mode); -} - static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct labpc_private *devpriv = dev->private; @@ -284,7 +258,7 @@ static int labpc_ai_insn_read(struct comedi_device *dev, devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); /* initialize pacer counter to prevent any problems */ - labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2); + comedi_8254_set_mode(devpriv->counter, 0, I8254_MODE2 | I8254_BINARY); labpc_clear_adc_fifo(dev); @@ -367,83 +341,81 @@ static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, enum scan_mode mode) { - struct labpc_private *devpriv = dev->private; + struct comedi_8254 *pacer = dev->pacer; + unsigned int convert_period = labpc_ai_convert_period(cmd, mode); + unsigned int scan_period = labpc_ai_scan_period(cmd, mode); unsigned int base_period; - unsigned int scan_period; - unsigned int convert_period; /* - * if both convert and scan triggers are TRIG_TIMER, then they - * both rely on counter b0 + * If both convert and scan triggers are TRIG_TIMER, then they + * both rely on counter b0. If only one TRIG_TIMER is used, we + * can use the generic cascaded timing functions. */ - convert_period = labpc_ai_convert_period(cmd, mode); - scan_period = labpc_ai_scan_period(cmd, mode); if (convert_period && scan_period) { /* - * pick the lowest b0 divisor value we can (for maximum input + * pick the lowest divisor value we can (for maximum input * clock speed on convert and scan counters) */ - devpriv->divisor_b0 = (scan_period - 1) / - (I8254_OSC_BASE_2MHZ * 0x10000) + 1; + pacer->next_div1 = (scan_period - 1) / + (pacer->osc_base * I8254_MAX_COUNT) + 1; - cfc_check_trigger_arg_min(&devpriv->divisor_b0, 2); - cfc_check_trigger_arg_max(&devpriv->divisor_b0, 0x10000); + comedi_check_trigger_arg_min(&pacer->next_div1, 2); + comedi_check_trigger_arg_max(&pacer->next_div1, + I8254_MAX_COUNT); - base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0; + base_period = pacer->osc_base * pacer->next_div1; /* set a0 for conversion frequency and b1 for scan frequency */ switch (cmd->flags & CMDF_ROUND_MASK) { default: case CMDF_ROUND_NEAREST: - devpriv->divisor_a0 = DIV_ROUND_CLOSEST(convert_period, - base_period); - devpriv->divisor_b1 = DIV_ROUND_CLOSEST(scan_period, - base_period); + pacer->next_div = DIV_ROUND_CLOSEST(convert_period, + base_period); + pacer->next_div2 = DIV_ROUND_CLOSEST(scan_period, + base_period); break; case CMDF_ROUND_UP: - devpriv->divisor_a0 = DIV_ROUND_UP(convert_period, - base_period); - devpriv->divisor_b1 = DIV_ROUND_UP(scan_period, - base_period); + pacer->next_div = DIV_ROUND_UP(convert_period, + base_period); + pacer->next_div2 = DIV_ROUND_UP(scan_period, + base_period); break; case CMDF_ROUND_DOWN: - devpriv->divisor_a0 = convert_period / base_period; - devpriv->divisor_b1 = scan_period / base_period; + pacer->next_div = convert_period / base_period; + pacer->next_div2 = scan_period / base_period; break; } /* make sure a0 and b1 values are acceptable */ - cfc_check_trigger_arg_min(&devpriv->divisor_a0, 2); - cfc_check_trigger_arg_max(&devpriv->divisor_a0, 0x10000); - cfc_check_trigger_arg_min(&devpriv->divisor_b1, 2); - cfc_check_trigger_arg_max(&devpriv->divisor_b1, 0x10000); + comedi_check_trigger_arg_min(&pacer->next_div, 2); + comedi_check_trigger_arg_max(&pacer->next_div, I8254_MAX_COUNT); + comedi_check_trigger_arg_min(&pacer->next_div2, 2); + comedi_check_trigger_arg_max(&pacer->next_div2, + I8254_MAX_COUNT); + /* write corrected timings to command */ labpc_set_ai_convert_period(cmd, mode, - base_period * devpriv->divisor_a0); + base_period * pacer->next_div); labpc_set_ai_scan_period(cmd, mode, - base_period * devpriv->divisor_b1); - /* - * if only one TRIG_TIMER is used, we can employ the generic - * cascaded timing functions - */ + base_period * pacer->next_div2); } else if (scan_period) { /* * calculate cascaded counter values * that give desired scan timing + * (pacer->next_div2 / pacer->next_div1) */ - i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, - &devpriv->divisor_b1, - &devpriv->divisor_b0, - &scan_period, cmd->flags); + comedi_8254_cascade_ns_to_timer(pacer, &scan_period, + cmd->flags); labpc_set_ai_scan_period(cmd, mode, scan_period); } else if (convert_period) { /* * calculate cascaded counter values * that give desired conversion timing + * (pacer->next_div / pacer->next_div1) */ - i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, - &devpriv->divisor_a0, - &devpriv->divisor_b0, - &convert_period, cmd->flags); + comedi_8254_cascade_ns_to_timer(pacer, &convert_period, + cmd->flags); + /* transfer div2 value so correct timer gets updated */ + pacer->next_div = pacer->next_div2; labpc_set_ai_convert_period(cmd, mode, convert_period); } } @@ -457,7 +429,7 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) return MODE_SINGLE_CHAN; /* chanlist may be NULL during cmdtest */ - if (cmd->chanlist == NULL) + if (!cmd->chanlist) return MODE_MULT_CHAN_UP; chan0 = CR_CHAN(cmd->chanlist[0]); @@ -482,9 +454,6 @@ static int labpc_ai_check_chanlist(struct comedi_device *dev, unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; - if (mode == MODE_SINGLE_CHAN) - return 0; - for (i = 0; i < cmd->chanlist_len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned int range = CR_RANGE(cmd->chanlist[i]); @@ -543,26 +512,27 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, /* Step 1 : check if triggers are trivially valid */ - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, + err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= comedi_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT); + err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); stop_mask = TRIG_COUNT | TRIG_NONE; if (board->is_labpc1200) stop_mask |= TRIG_EXT; - err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask); + err |= comedi_check_trigger_src(&cmd->stop_src, stop_mask); if (err) return 1; /* Step 2a : make sure trigger sources are unique */ - err |= cfc_check_trigger_is_unique(cmd->start_src); - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); + err |= comedi_check_trigger_is_unique(cmd->start_src); + err |= comedi_check_trigger_is_unique(cmd->scan_begin_src); + err |= comedi_check_trigger_is_unique(cmd->convert_src); + err |= comedi_check_trigger_is_unique(cmd->stop_src); /* Step 2b : and mutually compatible */ @@ -577,7 +547,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, switch (cmd->start_src) { case TRIG_NOW: - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); break; case TRIG_EXT: /* start_arg value is ignored */ @@ -586,27 +556,33 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, if (!cmd->chanlist_len) err |= -EINVAL; - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, + cmd->chanlist_len); - if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - board->ai_speed); + if (cmd->convert_src == TRIG_TIMER) { + err |= comedi_check_trigger_arg_min(&cmd->convert_arg, + board->ai_speed); + } /* make sure scan timing is not too fast */ if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - cmd->convert_arg * cmd->chanlist_len); - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - board->ai_speed * cmd->chanlist_len); + if (cmd->convert_src == TRIG_TIMER) { + err |= comedi_check_trigger_arg_min(&cmd-> + scan_begin_arg, + cmd->convert_arg * + cmd->chanlist_len); + } + err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, + board->ai_speed * + cmd->chanlist_len); } switch (cmd->stop_src) { case TRIG_COUNT: - err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); break; case TRIG_NONE: - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); break; /* * TRIG_EXT doesn't care since it doesn't @@ -670,11 +646,12 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * load counter a1 with count of 3 * (pc+ manual says this is minimum allowed) using mode 0 */ - labpc_counter_load(dev, COUNTER_A_BASE_REG, - 1, 3, I8254_MODE0); + comedi_8254_load(devpriv->counter, 1, + 3, I8254_MODE0 | I8254_BINARY); } else { /* just put counter a1 in mode 0 to set its output low */ - labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 1, I8254_MODE0); + comedi_8254_set_mode(devpriv->counter, 1, + I8254_MODE0 | I8254_BINARY); } /* figure out what method we will use to transfer data */ @@ -715,27 +692,24 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) { - /* set up pacing */ - labpc_adc_timing(dev, cmd, mode); - /* load counter b0 in mode 3 */ - labpc_counter_load(dev, COUNTER_B_BASE_REG, - 0, devpriv->divisor_b0, I8254_MODE3); - } - /* set up conversion pacing */ - if (labpc_ai_convert_period(cmd, mode)) { - /* load counter a0 in mode 2 */ - labpc_counter_load(dev, COUNTER_A_BASE_REG, - 0, devpriv->divisor_a0, I8254_MODE2); - } else { - /* initialize pacer counter to prevent any problems */ - labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2); - } + struct comedi_8254 *pacer = dev->pacer; + struct comedi_8254 *counter = devpriv->counter; + + comedi_8254_update_divisors(pacer); - /* set up scan pacing */ - if (labpc_ai_scan_period(cmd, mode)) { - /* load counter b1 in mode 2 */ - labpc_counter_load(dev, COUNTER_B_BASE_REG, - 1, devpriv->divisor_b1, I8254_MODE2); + /* set up pacing */ + comedi_8254_load(pacer, 0, pacer->divisor1, + I8254_MODE3 | I8254_BINARY); + + /* set up conversion pacing */ + comedi_8254_set_mode(counter, 0, I8254_MODE2 | I8254_BINARY); + if (labpc_ai_convert_period(cmd, mode)) + comedi_8254_write(counter, 0, pacer->divisor); + + /* set up scan pacing */ + if (labpc_ai_scan_period(cmd, mode)) + comedi_8254_load(pacer, 1, pacer->divisor2, + I8254_MODE2 | I8254_BINARY); } labpc_clear_adc_fifo(dev); @@ -1240,6 +1214,26 @@ int labpc_common_attach(struct comedi_device *dev, dev->irq = irq; } + if (dev->mmio) { + dev->pacer = comedi_8254_mm_init(dev->mmio + COUNTER_B_BASE_REG, + I8254_OSC_BASE_2MHZ, + I8254_IO8, 0); + devpriv->counter = comedi_8254_mm_init(dev->mmio + + COUNTER_A_BASE_REG, + I8254_OSC_BASE_2MHZ, + I8254_IO8, 0); + } else { + dev->pacer = comedi_8254_init(dev->iobase + COUNTER_B_BASE_REG, + I8254_OSC_BASE_2MHZ, + I8254_IO8, 0); + devpriv->counter = comedi_8254_init(dev->iobase + + COUNTER_A_BASE_REG, + I8254_OSC_BASE_2MHZ, + I8254_IO8, 0); + } + if (!dev->pacer || !devpriv->counter) + return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 5); if (ret) return ret; @@ -1336,6 +1330,15 @@ int labpc_common_attach(struct comedi_device *dev, } EXPORT_SYMBOL_GPL(labpc_common_attach); +void labpc_common_detach(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + if (devpriv) + kfree(devpriv->counter); +} +EXPORT_SYMBOL_GPL(labpc_common_detach); + static int __init labpc_common_init(void) { return 0; |