diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/s526.c')
-rw-r--r-- | drivers/staging/comedi/drivers/s526.c | 602 |
1 files changed, 153 insertions, 449 deletions
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 737a194dfce3..a1e256293bd6 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -83,36 +83,6 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3 #define REG_EED 0x32 #define REG_EEC 0x34 -static const int s526_ports[] = { - REG_TCR, - REG_WDC, - REG_DAC, - REG_ADC, - REG_ADD, - REG_DIO, - REG_IER, - REG_ISR, - REG_MSC, - REG_C0L, - REG_C0H, - REG_C0M, - REG_C0C, - REG_C1L, - REG_C1H, - REG_C1M, - REG_C1C, - REG_C2L, - REG_C2H, - REG_C2M, - REG_C2C, - REG_C3L, - REG_C3H, - REG_C3M, - REG_C3C, - REG_EED, - REG_EEC -}; - struct counter_mode_register_t { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned short coutSource:1; @@ -148,122 +118,48 @@ union cmReg { unsigned short value; }; -#define MAX_GPCT_CONFIG_DATA 6 - -/* Different Application Classes for GPCT Subdevices */ -/* The list is not exhaustive and needs discussion! */ -enum S526_GPCT_APP_CLASS { - CountingAndTimeMeasurement, - SinglePulseGeneration, - PulseTrainGeneration, - PositionMeasurement, - Miscellaneous -}; - -/* Config struct for different GPCT subdevice Application Classes and - their options -*/ -struct s526GPCTConfig { - enum S526_GPCT_APP_CLASS app; - int data[MAX_GPCT_CONFIG_DATA]; -}; - -/* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. - */ -struct s526_board { - const char *name; - int gpct_chans; - int gpct_bits; - int ad_chans; - int ad_bits; - int da_chans; - int da_bits; - int have_dio; -}; - -static const struct s526_board s526_boards[] = { - { - .name = "s526", - .gpct_chans = 4, - .gpct_bits = 24, - .ad_chans = 8, - .ad_bits = 16, - .da_chans = 4, - .da_bits = 16, - .have_dio = 1, - } -}; - -#define ADDR_REG(reg) (dev->iobase + (reg)) -#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8) - -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device - struct. -*/ struct s526_private { unsigned int ao_readback[2]; - struct s526GPCTConfig s526_gpct_config[4]; - unsigned short s526_ai_config; + unsigned int gpct_config[4]; + unsigned short ai_config; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct s526_private *)dev->private) - static int s526_gpct_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int i; /* counts the Data */ - int counter_channel = CR_CHAN(insn->chanspec); - unsigned short datalow; - unsigned short datahigh; - - /* Check if (n > 0) */ - if (insn->n <= 0) { - printk(KERN_ERR "s526: INSN_READ: n should be > 0\n"); - return -EINVAL; - } - /* Read the low word first */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; + unsigned int lo; + unsigned int hi; + int i; + for (i = 0; i < insn->n; i++) { - datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel)); - datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); - data[i] = (int)(datahigh & 0x00FF); - data[i] = (data[i] << 16) | (datalow & 0xFFFF); - /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", - counter_channel, data[i], datahigh, datalow); */ + /* Read the low word first */ + lo = inw(chan_iobase + REG_C0L) & 0xffff; + hi = inw(chan_iobase + REG_C0H) & 0xff; + + data[i] = (hi << 16) | lo; } - return i; + + return insn->n; } static int s526_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ - int i; - short value; + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; + unsigned int val; union cmReg cmReg; - /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", - subdev_channel); */ - - for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { - devpriv->s526_gpct_config[subdev_channel].data[i] = - insn->data[i]; -/* printk("data[%d]=%x\n", i, insn->data[i]); */ - } - /* Check what type of Counter the user requested, data[0] contains */ /* the Application type */ - switch (insn->data[0]) { + switch (data[0]) { case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: /* data[0]: Application Type @@ -271,9 +167,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[2]: Pre-load Register Value data[3]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); - devpriv->s526_gpct_config[subdev_channel].app = - PositionMeasurement; + devpriv->gpct_config[chan] = data[0]; #if 0 /* Example of Counter Application */ @@ -290,34 +184,32 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + outw(0x0001, chan_iobase + REG_C0H); + outw(0x3C68, chan_iobase + REG_C0L); /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x4000, chan_iobase + REG_C0C); /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x0008, chan_iobase + REG_C0C); #endif #if 1 /* Set Counter Mode Register */ - cmReg.value = insn->data[1] & 0xFFFF; - -/* printk("s526: Counter Mode register=%x\n", cmReg.value); */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + cmReg.value = data[1] & 0xffff; + outw(cmReg.value, chan_iobase + REG_C0M); /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 - * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + * outw(0x4000, chan_iobase + REG_C0C); */ } #else @@ -325,47 +217,47 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.countDirCtrl = 0; /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ - if (insn->data[1] == GPCT_X2) + if (data[1] == GPCT_X2) cmReg.reg.clockSource = 1; - else if (insn->data[1] == GPCT_X4) + else if (data[1] == GPCT_X4) cmReg.reg.clockSource = 2; else cmReg.reg.clockSource = 0; /* When to take into account the indexpulse: */ - /*if (insn->data[2] == GPCT_IndexPhaseLowLow) { - } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { - } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { - } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { + /*if (data[2] == GPCT_IndexPhaseLowLow) { + } else if (data[2] == GPCT_IndexPhaseLowHigh) { + } else if (data[2] == GPCT_IndexPhaseHighLow) { + } else if (data[2] == GPCT_IndexPhaseHighHigh) { }*/ /* Take into account the index pulse? */ - if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) + if (data[3] == GPCT_RESET_COUNTER_ON_INDEX) /* Auto load with INDEX^ */ cmReg.reg.autoLoadResetRcap = 4; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + cmReg.value = data[1] & 0xffff; + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[3] != 0) { - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[3]) { + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0C); } /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x4000, chan_iobase + REG_C0C); } #endif break; @@ -378,40 +270,38 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n"); - devpriv->s526_gpct_config[subdev_channel].app = - SinglePulseGeneration; + devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 0 high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 0 low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 1 high word */ - value = (short)((insn->data[3] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[3] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 1 low word */ - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[4] != 0) { - value = (short)(insn->data[4] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[4]) { + val = data[4] & 0xffff; + outw(val, chan_iobase + REG_C0C); } break; @@ -423,45 +313,42 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n"); - devpriv->s526_gpct_config[subdev_channel].app = - PulseTrainGeneration; + devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 0 high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 0 low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 1 high word */ - value = (short)((insn->data[3] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[3] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 1 low word */ - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[4] != 0) { - value = (short)(insn->data[4] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[4]) { + val = data[4] & 0xffff; + outw(val, chan_iobase + REG_C0C); } break; default: - printk(KERN_ERR "s526: unsupported GPCT_insn_config\n"); return -EINVAL; break; } @@ -470,65 +357,40 @@ static int s526_gpct_insn_config(struct comedi_device *dev, } static int s526_gpct_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ - short value; - union cmReg cmReg; - - printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n", - subdev_channel); - cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); - printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value); - /* Check what Application of Counter this channel is configured for */ - switch (devpriv->s526_gpct_config[subdev_channel].app) { - case PositionMeasurement: - printk(KERN_INFO "S526: INSN_WRITE: PM\n"); - outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, - subdev_channel)); - outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); - break; + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; - case SinglePulseGeneration: - printk(KERN_INFO "S526: INSN_WRITE: SPG\n"); - outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, - subdev_channel)); - outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); - break; + inw(chan_iobase + REG_C0M); /* Is this read required? */ - case PulseTrainGeneration: + /* Check what Application of Counter this channel is configured for */ + switch (devpriv->gpct_config[chan]) { + case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: /* data[0] contains the PULSE_WIDTH data[1] contains the PULSE_PERIOD @pre PULSE_PERIOD > PULSE_WIDTH > 0 The above periods must be expressed as a multiple of the pulse frequency on the selected source */ - printk(KERN_INFO "S526: INSN_WRITE: PTG\n"); - if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) { - (devpriv->s526_gpct_config[subdev_channel]).data[0] = - insn->data[0]; - (devpriv->s526_gpct_config[subdev_channel]).data[1] = - insn->data[1]; - } else { - printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n", - insn->data[0], insn->data[1]); + if ((data[1] <= data[0]) || !data[0]) return -EINVAL; - } - value = (short)((*data >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - value = (short)(*data & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + /* Fall thru to write the PULSE_WIDTH */ + + case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: + case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: + outw((data[0] >> 16) & 0xffff, chan_iobase + REG_C0H); + outw(data[0] & 0xffff, chan_iobase + REG_C0L); break; - default: /* Impossible */ - printk - ("s526: INSN_WRITE: Functionality %d not implemented yet\n", - devpriv->s526_gpct_config[subdev_channel].app); + + default: return -EINVAL; - break; } - /* return the number of samples written */ + return insn->n; } @@ -537,6 +399,7 @@ static int s526_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; int result = -EINVAL; if (insn->n < 1) @@ -552,62 +415,50 @@ static int s526_ai_insn_config(struct comedi_device *dev, * INSN_READ handler. */ /* Enable ADC interrupt */ - outw(ISR_ADC_DONE, ADDR_REG(REG_IER)); -/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */ - devpriv->s526_ai_config = (data[0] & 0x3FF) << 5; + outw(ISR_ADC_DONE, dev->iobase + REG_IER); + devpriv->ai_config = (data[0] & 0x3ff) << 5; if (data[1] > 0) - devpriv->s526_ai_config |= 0x8000; /* set the delay */ + devpriv->ai_config |= 0x8000; /* set the delay */ - devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */ + devpriv->ai_config |= 0x0001; /* ADC start bit */ return result; } -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int n, i; - int chan = CR_CHAN(insn->chanspec); unsigned short value; unsigned int d; unsigned int status; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ - value = (devpriv->s526_ai_config & 0x8000) | - ((1 << 5) << chan) | (chan << 1) | 0x0001; + value = (devpriv->ai_config & 0x8000) | + ((1 << 5) << chan) | (chan << 1) | 0x0001; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - outw(value, ADDR_REG(REG_ADC)); -/* printk("s526: Wrote 0x%04x to ADC\n", value); */ -/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */ + outw(value, dev->iobase + REG_ADC); #define TIMEOUT 100 /* wait for conversion to end */ for (i = 0; i < TIMEOUT; i++) { - status = inw(ADDR_REG(REG_ISR)); + status = inw(dev->iobase + REG_ISR); if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, ADDR_REG(REG_ISR)); + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); break; } } - if (i == TIMEOUT) { - /* printk() should be used instead of printk() - * whenever the code can be called from real-time. */ - printk(KERN_ERR "s526: ADC(0x%04x) timeout\n", - inw(ADDR_REG(REG_ISR))); + if (i == TIMEOUT) return -ETIMEDOUT; - } /* read data */ - d = inw(ADDR_REG(REG_ADD)); -/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */ + d = inw(dev->iobase + REG_ADD); /* munge data */ data[n] = d ^ 0x8000; @@ -620,40 +471,30 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i; - int chan = CR_CHAN(insn->chanspec); + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); unsigned short val; + int i; -/* printk("s526_ao_winsn\n"); */ val = chan << 1; -/* outw(val, dev->iobase + REG_DAC); */ - outw(val, ADDR_REG(REG_DAC)); + outw(val, dev->iobase + REG_DAC); - /* 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++) { - /* a typical programming sequence */ - /* write the data to preload register - * outw(data[i], dev->iobase + REG_ADD); - */ - /* write the data to preload register */ - outw(data[i], ADDR_REG(REG_ADD)); + outw(data[i], dev->iobase + REG_ADD); devpriv->ao_readback[chan] = data[i]; -/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ - outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/ + /* starts the D/A conversion */ + outw(val + 1, dev->iobase + REG_DAC); } - /* 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 s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; @@ -661,30 +502,18 @@ static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ static int s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ if (data[0]) { s->state &= ~data[0]; s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outw(s->state, ADDR_REG(REG_DIO)); + + outw(s->state, dev->iobase + REG_DIO); } - /* on return, data[1] contains the value of the digital - * input and output lines. */ - data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state & 0xFF; */ + data[1] = inw(dev->iobase + REG_DIO) & 0xff; return insn->n; } @@ -693,16 +522,9 @@ static int s526_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); int group, mask; - printk(KERN_INFO "S526 DIO insn_config\n"); - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - group = chan >> 2; mask = 0xF << (group << 2); switch (data[0]) { @@ -721,88 +543,60 @@ static int s526_dio_insn_config(struct comedi_device *dev, default: return -EINVAL; } - outw(s->state, ADDR_REG(REG_DIO)); + outw(s->state, dev->iobase + REG_DIO); return 1; } static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct s526_board *board = comedi_board(dev); + struct s526_private *devpriv; struct comedi_subdevice *s; int iobase; - int i, n; int ret; -/* short value; */ -/* int subdev_channel = 0; */ - union cmReg cmReg; - printk(KERN_INFO "comedi%d: s526: ", dev->minor); + dev->board_name = dev->driver->driver_name; iobase = it->options[0]; - if (!iobase || !request_region(iobase, S526_IOSIZE, board->name)) { + if (!iobase || !request_region(iobase, S526_IOSIZE, dev->board_name)) { comedi_error(dev, "I/O port conflict"); return -EIO; } dev->iobase = iobase; - printk("iobase=0x%lx\n", dev->iobase); - - /*** make it a little quieter, exw, 8/29/06 - for (i = 0; i < S526_NUM_PORTS; i++) { - printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), - inw(ADDR_REG(s526_ports[i]))); - } - ***/ - - dev->board_name = board->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct s526_private)) < 0) - return -ENOMEM; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; - /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ - s->n_chan = board->gpct_chans; + s->n_chan = 4; s->maxdata = 0x00ffffff; /* 24 bit counter */ s->insn_read = s526_gpct_rinsn; s->insn_config = s526_gpct_insn_config; s->insn_write = s526_gpct_winsn; - /* Command are not implemented yet, however they are necessary to - allocate the necessary memory for the comedi_async struct (used - to trigger the GPCT in case of pulsegenerator function */ - /* s->do_cmd = s526_gpct_cmd; */ - /* s->do_cmdtest = s526_gpct_cmdtest; */ - /* s->cancel = s526_gpct_cancel; */ - - s = dev->subdevices + 1; - /* dev->read_subdev=s; */ + s = &dev->subdevices[1]; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; - /* we support differential */ s->subdev_flags = SDF_READABLE | SDF_DIFF; /* channels 0 to 7 are the regular differential inputs */ /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ s->n_chan = 10; s->maxdata = 0xffff; s->range_table = &range_bipolar10; - s->len_chanlist = 16; /* This is the maximum chanlist length that - the board can handle */ + s->len_chanlist = 16; s->insn_read = s526_ai_rinsn; s->insn_config = s526_ai_insn_config; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -812,105 +606,18 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = s526_ao_winsn; s->insn_read = s526_ao_rinsn; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* digital i/o subdevice */ - if (board->have_dio) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = s526_dio_insn_bits; - s->insn_config = s526_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - printk(KERN_INFO "attached\n"); - - return 1; - -#if 0 - /* Example of Counter Application */ - /* One-shot (software trigger) */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ - cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 2; /* Hardware */ - cmReg.reg.clockSource = 2; /* Internal */ - cmReg.reg.countDir = 1; /* Down */ - cmReg.reg.countDirCtrl = 1; /* Software */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - -#else - - /* Set Counter Mode Register */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 0; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ - cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ - cmReg.reg.clockSource = 3; /* x4 */ - cmReg.reg.countDir = 0; /* up */ - cmReg.reg.countDirCtrl = 0; /* quadrature */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - n = 0; - printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", - cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); - - /* Load the pre-load register high word */ -/* value = (short) (0x55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ - - /* Load the pre-load register low word */ -/* value = (short)(0xaa55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ - - /* Write the Counter Control Register */ -/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ - - /* Reset the counter if it is software preload */ - if (cmReg.reg.autoLoadResetRcap == 0) { - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); - } + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = s526_dio_insn_bits; + s->insn_config = s526_dio_insn_config; - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); + dev_info(dev->class_dev, "%s attached\n", dev->board_name); -#endif - printk(KERN_INFO "Current registres:\n"); - - for (i = 0; i < S526_NUM_PORTS; i++) { - printk(KERN_INFO "0x%02lx: 0x%04x\n", - ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); - } return 1; } @@ -925,9 +632,6 @@ static struct comedi_driver s526_driver = { .module = THIS_MODULE, .attach = s526_attach, .detach = s526_detach, - .board_name = &s526_boards[0].name, - .offset = sizeof(struct s526_board), - .num_names = ARRAY_SIZE(s526_boards), }; module_comedi_driver(s526_driver); |