From ee422bb687e6dddd446d1d2c83345194f5201d2f Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 5 Apr 2013 16:09:40 -0700 Subject: [PATCH] staging: comedi: serial2002: cleanup serial2002_setup_subdevs() Define and document the bit shifts of the serial.data read from the device that is used to configure the subdevice channels. Use the new defines to tidy up the configuration process. Signed-off-by: H Hartley Sweeten Cc: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/serial2002.c | 139 +++++++++++--------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index b5c464e43215..e3243f802420 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -72,6 +72,38 @@ struct serial_data { unsigned long value; }; +/* + * The configuration serial_data.value read from the device is + * a bitmask that defines specific options of a channel: + * + * 4:0 - the channel to configure + * 7:5 - the kind of channel + * 9:8 - the command used to configure the channel + * + * The remaining bits vary in use depending on the command: + * + * BITS 15:10 - the channel bits (maxdata) + * MIN/MAX 12:10 - the units multiplier for the scale + * 13 - the sign of the scale + * 33:14 - the base value for the range + */ +#define S2002_CFG_CHAN(x) ((x) & 0x1f) +#define S2002_CFG_KIND(x) (((x) >> 5) & 0x7) +#define S2002_CFG_KIND_INVALID 0 +#define S2002_CFG_KIND_DIGITAL_IN 1 +#define S2002_CFG_KIND_DIGITAL_OUT 2 +#define S2002_CFG_KIND_ANALOG_IN 3 +#define S2002_CFG_KIND_ANALOG_OUT 4 +#define S2002_CFG_KIND_ENCODER_IN 5 +#define S2002_CFG_CMD(x) (((x) >> 8) & 0x3) +#define S2002_CFG_CMD_BITS 0 +#define S2002_CFG_CMD_MIN 1 +#define S2002_CFG_CMD_MAX 2 +#define S2002_CFG_BITS(x) (((x) >> 10) & 0x3f) +#define S2002_CFG_UNITS(x) (((x) >> 10) & 0x7) +#define S2002_CFG_SIGN(x) (((x) >> 13) & 0x1) +#define S2002_CFG_BASE(x) (((x) >> 14) & 0xfffff) + static long tty_ioctl(struct file *f, unsigned op, unsigned long param) { if (f->f_op->unlocked_ioctl) @@ -396,10 +428,10 @@ static int serial2002_setup_subdevs(struct comedi_device *dev) struct config_t *ao_cfg; struct config_t *cfg; struct comedi_subdevice *s; - int result; + int result = 0; int i; - result = 0; + /* Allocate the temporary structs to hold the configuration data */ di_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); do_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); ai_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); @@ -409,86 +441,70 @@ static int serial2002_setup_subdevs(struct comedi_device *dev) goto err_alloc_configs; } + /* Read the configuration from the connected device */ tty_setspeed(devpriv->tty, devpriv->speed); - poll_channel(devpriv->tty, 31); /* Start reading configuration */ + poll_channel(devpriv->tty, 31); while (1) { struct serial_data data; data = serial_read(devpriv->tty, 1000); if (data.kind != is_channel || data.index != 31 || - !(data.value & 0xe0)) { + S2002_CFG_KIND(data.value) == S2002_CFG_KIND_INVALID) { break; } else { - int channel = data.value & 0x1f; - int kind = (data.value >> 5) & 0x7; - int command = (data.value >> 8) & 0x3; + int channel = S2002_CFG_CHAN(data.value); + int range = S2002_CFG_BASE(data.value); - switch (kind) { - case 1: + switch (S2002_CFG_KIND(data.value)) { + case S2002_CFG_KIND_DIGITAL_IN: cfg = di_cfg; break; - case 2: + case S2002_CFG_KIND_DIGITAL_OUT: cfg = do_cfg; break; - case 3: + case S2002_CFG_KIND_ANALOG_IN: cfg = ai_cfg; break; - case 4: + case S2002_CFG_KIND_ANALOG_OUT: cfg = ao_cfg; break; - case 5: + case S2002_CFG_KIND_ENCODER_IN: cfg = ai_cfg; break; default: cfg = NULL; break; } + if (!cfg) + continue; /* unknown kind, skip it */ - if (cfg) { - short int bits = (data.value >> 10) & 0x3f; - int unit = (data.value >> 10) & 0x7; - int sign = (data.value >> 13) & 0x1; - int min = (data.value >> 14) & 0xfffff; - int max = min; + cfg[channel].kind = S2002_CFG_KIND(data.value); - cfg[channel].kind = kind; - switch (command) { + switch (S2002_CFG_CMD(data.value)) { + case S2002_CFG_CMD_BITS: + cfg[channel].bits = S2002_CFG_BITS(data.value); + break; + case S2002_CFG_CMD_MIN: + case S2002_CFG_CMD_MAX: + switch (S2002_CFG_UNITS(data.value)) { case 0: - cfg[channel].bits = bits; + range *= 1000000; break; case 1: - switch (unit) { - case 0: - min *= 1000000; - break; - case 1: - min *= 1000; - break; - case 2: - min *= 1; - break; - } - if (sign) - min = -min; - cfg[channel].min = min; + range *= 1000; break; case 2: - switch (unit) { - case 0: - max *= 1000000; - break; - case 1: - max *= 1000; - break; - case 2: - max *= 1; - break; - } - if (sign) - max = -max; - cfg[channel].max = max; + range *= 1; break; } + if (S2002_CFG_SIGN(data.value)) + range = -range; + if (S2002_CFG_CMD(data.value) == + S2002_CFG_CMD_MIN) + cfg[channel].min = range; + else + cfg[channel].max = range; + break; } } } @@ -499,46 +515,41 @@ static int serial2002_setup_subdevs(struct comedi_device *dev) struct serial2002_range_table_t *range = NULL; int kind = 0; + s = &dev->subdevices[i]; + switch (i) { case 0: cfg = di_cfg; mapping = devpriv->digital_in_mapping; - kind = 1; + kind = S2002_CFG_KIND_DIGITAL_IN; break; case 1: cfg = do_cfg; mapping = devpriv->digital_out_mapping; - kind = 2; + kind = S2002_CFG_KIND_DIGITAL_OUT; break; case 2: cfg = ai_cfg; mapping = devpriv->analog_in_mapping; range = devpriv->in_range; - kind = 3; + kind = S2002_CFG_KIND_ANALOG_IN; break; case 3: cfg = ao_cfg; mapping = devpriv->analog_out_mapping; range = devpriv->out_range; - kind = 4; + kind = S2002_CFG_KIND_ANALOG_OUT; break; case 4: cfg = ai_cfg; mapping = devpriv->encoder_in_mapping; range = devpriv->in_range; - kind = 5; - break; - default: - cfg = NULL; + kind = S2002_CFG_KIND_ENCODER_IN; break; } - if (cfg) { - s = &dev->subdevices[i]; - if (serial2002_setup_subdevice(s, cfg, range, mapping, - kind)) - break; /* err handled below */ - } + if (serial2002_setup_subdevice(s, cfg, range, mapping, kind)) + break; /* err handled below */ } if (i <= 4) { /* -- 2.30.2