diff --git a/drivers/zio-gpio.c b/drivers/zio-gpio.c index 7240d28df84eb374d355bc19ac4e3d5b15e2a624..151fe6690ba10dedf6109a52ef7692ec9379b4d5 100644 --- a/drivers/zio-gpio.c +++ b/drivers/zio-gpio.c @@ -22,11 +22,20 @@ #include <linux/zio-buffer.h> #define ZGPIO_NOUT 8 +#define ZGPIO_NIN 8 +/* Output and input bits are selected at load time */ static int zgp_out[ZGPIO_NOUT]; static int zgp_nout; module_param_array_named(out, zgp_out, int, &zgp_nout, 0444); +static int zgp_in[ZGPIO_NIN]; +static int zgp_nin; +module_param_array_named(in, zgp_in, int, &zgp_nin, 0444); +ZIO_PARAM_TRIGGER(zgp_trigger); +ZIO_PARAM_BUFFER(zgp_buffer); + +/* This outputs a cset, currently made up of one channel only */ static int zgp_output(struct zio_cset *cset) { struct zio_channel *chan; @@ -35,22 +44,48 @@ static int zgp_output(struct zio_cset *cset) uint8_t datum; int i; - /* we currently have one channel only, but who cares */ cset_for_each(cset, chan) { block = chan->active_block; if (!block) continue; ctrl = zio_get_ctrl(block); - /* FIXME: should use ssize */ - datum = ((unsigned char *)block->data)[ctrl->nsamples - 1]; + /* use last sample, as previous ones would be overwritten */ + i = ctrl->ssize * ctrl->nsamples; + datum = ((unsigned char *)block->data)[i - 1]; for (i = 0; i < zgp_nout; i++) gpio_set_value(zgp_out[i], datum & (1 << i)); } return 1; /* done */ } +/* Similarly, this inputs a cset. Again, currently one channel only */ +static int zgp_input(struct zio_cset *cset) +{ + struct zio_channel *chan; + struct zio_block *block; + struct zio_control *ctrl; + uint8_t datum; + int i, j; + + cset_for_each(cset, chan) { + block = chan->active_block; + if (!block) + continue; + ctrl = zio_get_ctrl(block); + /* fill the whole block */ + for (j = 0; j < ctrl->nsamples; j++) { + datum = 0; + for (i = 0; i < zgp_nin; i++) + datum |= gpio_get_value(zgp_in[i]) << i; + ((unsigned char *)block->data)[j] = datum; + } + } + return 1; /* done */ +} + static struct zio_device_operations zgp_d_op = { .output_cset = zgp_output, + .input_cset = zgp_input, }; static struct zio_cset zgp_cset[] = { @@ -59,6 +94,11 @@ static struct zio_cset zgp_cset[] = { .ssize = 1, .flags = ZIO_DIR_OUTPUT | ZCSET_TYPE_ANALOG, }, + { + .n_chan = 1, + .ssize = 1, + .flags = ZIO_DIR_INPUT | ZCSET_TYPE_ANALOG, + }, }; static struct zio_device zgp_dev = { .owner = THIS_MODULE, @@ -72,6 +112,10 @@ static int __init zgp_init(void) { int i, err; + /* The above code assumes we have one one-byte sized data */ + BUILD_BUG_ON(ZGPIO_NOUT > 8); + BUILD_BUG_ON(ZGPIO_NIN > 8); + if (zgp_nout == 0) { pr_err(KBUILD_MODNAME ": please pass out= gpio list\n"); return -ENODEV; @@ -86,17 +130,37 @@ static int __init zgp_init(void) } } + for (i = 0; i < zgp_nin; i++) { + err = gpio_request(zgp_in[i], "zio-gpio-in"); + if (err) { + pr_err(KBUILD_MODNAME ": can't request gpio %i\n", + zgp_in[i]); + goto out_input; + } + } + + if (zgp_trigger) + zgp_dev.preferred_trigger = zgp_trigger; + if (zgp_buffer) + zgp_dev.preferred_buffer = zgp_buffer; err = zio_register_dev(&zgp_dev, "gpio"); if (err) { pr_err(KBUILD_MODNAME ": can't register zio driver " "(error %i)\n", err); - goto out; + goto out_input; } for (i = 0; i < zgp_nout; i++) gpio_direction_output(zgp_out[i], 0); + for (i = 0; i < zgp_nin; i++) + gpio_direction_input(zgp_in[i]); return 0; +out_input: + /* i is one more than the last registered gpio */ + for (i--; i >= 0; i--) + gpio_free(zgp_in[i]); + i = zgp_nout; out: /* i is one more than the last registered gpio */ for (i--; i >= 0; i--) @@ -110,6 +174,8 @@ static void __exit zgp_exit(void) zio_unregister_dev(&zgp_dev); for (i = 0; i < zgp_nout; i++) gpio_free(zgp_out[i]); + for (i = 0; i < zgp_nin; i++) + gpio_free(zgp_in[i]); } module_init(zgp_init);