X-Git-Url: http://git.linex4red.de/pub/spi-gpio-pp.git/blobdiff_plain/813458776ee097275c377f19853773b39dab193a..HEAD:/gpio_test.c diff --git a/gpio_test.c b/gpio_test.c index 90d0892..f4a5cf7 100644 --- a/gpio_test.c +++ b/gpio_test.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -30,107 +31,151 @@ // MODULE PARAMETERS //***************************************************************************** #define DRVNAME "gpio_test" /* name of the driver */ -#define DRIVER_VERSION "0.1" /* helps identifing different versions of that driver */ -#define LABEL NULL +#define DRIVER_VERSION "0.3" /* helps identifing different versions of that driver */ +#define LABEL DRVNAME -static unsigned int gpi; -static unsigned int gpo; -static unsigned int val; -static unsigned int irq = -1; +static int gpi = -1; +static int gpo = -1; +static unsigned int val = 0; +static int irq = -1; -typedef struct { +struct gpio_test { int out_cansleep; int in_cansleep; int irq; int cnt; -} gpio_t_struct; + struct tasklet_struct work_tasklet; +}; -static gpio_t_struct gt; +static struct gpio_test *gt; + + +static void gpio_tasklet(unsigned long data) +{ + struct gpio_test *g = (struct gpio_test *)data; + pr_info("%s: Tasklet triggered: %d\n", DRVNAME, g->cnt); +} static irqreturn_t gpio_test_irq_handler(int irq, void *dev_id) { - + struct gpio_test *g = (struct gpio_test *)dev_id; // todo use dev_id to get pointer to own driver structure data; // container can be memory init with GPK_KERNEL - if (irq == gt.irq) { - gt.cnt++; + if (irq == g->irq) { + g->cnt++; + tasklet_hi_schedule(&g->work_tasklet); +#if 0 val = !val; - if (!gt.in_cansleep) { - pr_info("%s: GPIO #%d in value %d with counter %d\n", DRVNAME, gpi, gpio_get_value(gpi), gt.cnt); + if (!g->in_cansleep) { + pr_info("%s: GPIO #%d in value %d with counter %d\n", DRVNAME, gpi, gpio_get_value(gpi), g->cnt); } - if (!gt.out_cansleep) { + if ((gpo >= 0) && !g->out_cansleep) { gpio_set_value(gpo, !val); } +#endif } return IRQ_HANDLED; } + + /* ** just set here the value */ static int __init gpio_test_init(void) { int err; - err = gpio_is_valid(gpo); - if (err<0) { - pr_err("%s: GPIO #%d for output is not usable\n", DRVNAME, gpo); - return err; - } - //ToDo: Test, how a text might be used as LABEL - err = gpio_request(gpo, LABEL); - if (err<0) { - pr_err("%s: GPIO #%d for output is can not be requested\n", DRVNAME, gpo); - return err; - } - gt.out_cansleep = gpio_cansleep(gpo); - pr_info("%s: GPIO #%d for output %s sleep\n", DRVNAME, gpo, ((gt.out_cansleep>0) ? "can" : "will not")); - err = gpio_direction_output(gpo, val); - if (err<0) { - pr_err("%s: GPIO #%d output direction is not possible\n", DRVNAME, gpo); - gpio_free(gpo); - return err; + gt = kzalloc(sizeof(*gt), GFP_KERNEL); + if (!gt) + return -ENOMEM; + + /* ******* GPIO INPUT ******* */ + if (gpi < 0) { + pr_err("%s: GPI input required\n", DRVNAME); + kfree(gt); + return -ENODEV; } - - err = gpio_is_valid(gpi); + err = gpio_is_valid(gpi); if (err<0) { pr_err("%s: GPIO #%d for inout is not usable\n", DRVNAME, gpi); - gpio_free(gpo); + kfree(gt); return err; } err = gpio_request(gpi, LABEL); if (err<0) { pr_err("%s: GPIO #%d for input is can not be requested\n", DRVNAME, gpi); - gpio_free(gpo); + kfree(gt); return err; } - gt.in_cansleep = gpio_cansleep(gpi); - pr_info("%s: GPIO #%d for input %s sleep\n", DRVNAME, gpi, ((gt.in_cansleep>0) ? "can" : "will not")); - gt.irq = gpio_to_irq(gpi); - if (gt.irq<0) { + gt->in_cansleep = gpio_cansleep(gpi); + pr_info("%s: GPIO #%d for input %s sleep\n", DRVNAME, gpi, ((gt->in_cansleep>0) ? "can" : "will not")); + tasklet_init(>->work_tasklet, + (void (*)(unsigned long))gpio_tasklet, + (unsigned long)gt); + + /* ******* GPIO INTERRUPT ******* */ + gt->irq = gpio_to_irq(gpi); + if (gt->irq<0) { pr_info("%s: GPIO #%d IRQ is not supported\n", DRVNAME, gpi); - gt.irq = irq; - if (gt.irq >= 0) { - pr_info("%s: we force interrupt to IRQ %d\n", DRVNAME, gt.irq); + gt->irq = irq; + if (gt->irq >= 0) { + pr_info("%s: we force interrupt to IRQ %d\n", DRVNAME, gt->irq); } } else { - pr_info("%s: GPIO #%d IRQ %d is supported\n", DRVNAME, gpi, gt.irq); + pr_info("%s: GPIO #%d IRQ %d is supported\n", DRVNAME, gpi, gt->irq); } - /* gpio_direction_output must be call from task context, we use insmod as task context here */ + /* gpio_direction_input must be call from task context, we use insmod as task context here */ err = gpio_direction_input(gpi); if (err<0) { pr_err("%s: GPIO #%d input direction is not possible\n", DRVNAME, gpi); - gpio_free(gpo); + tasklet_kill(>->work_tasklet); gpio_free(gpi); + kfree(gt); return err; } - gt.cnt=0; /* register irq handler */ + gt->cnt=0; // ToDo: Test with other flag types: IRQF_SHARED, IRQF_TRIGGER_* - if (gt.irq >= 0) { - err = request_irq(gt.irq, gpio_test_irq_handler, IRQF_TRIGGER_NONE, "gpio_test_handler", NULL); + if (gt->irq >= 0) { + err = request_irq(gt->irq, gpio_test_irq_handler, IRQF_TRIGGER_NONE, "gpio_test_handler", (void *)gt); + if (err<0) { + pr_err("%s: GPIO #%d IRQ %d can not be requested, got %d\n", DRVNAME, gpi, gt->irq, err); + gt->irq = -1; + } + } + + + /* ******* GPIO OUTPUT ******* */ + if (gpo >= 0) { + err = gpio_is_valid(gpo); + if (err<0) { + pr_err("%s: GPIO #%d for output is not usable\n", DRVNAME, gpo); + if (gt->irq >= 0) free_irq(gt->irq, (void *)gt); + tasklet_kill(>->work_tasklet); + gpio_free(gpi); + kfree(gt); + return err; + } + err = gpio_request(gpo, LABEL); + if (err<0) { + pr_err("%s: GPIO #%d for output is can not be requested\n", DRVNAME, gpo); + if (gt->irq >= 0) free_irq(gt->irq, (void *)gt); + tasklet_kill(>->work_tasklet); + gpio_free(gpi); + kfree(gt); + return err; + } + gt->out_cansleep = gpio_cansleep(gpo); + pr_info("%s: GPIO #%d for output %s sleep\n", DRVNAME, gpo, ((gt->out_cansleep>0) ? "can" : "will not")); + err = gpio_direction_output(gpo, val); if (err<0) { - pr_err("%s: GPIO #%d IRQ %d can not be requested, got %d\n", DRVNAME, gpi, gt.irq, err); - gt.irq = -1; + pr_err("%s: GPIO #%d output direction is not possible\n", DRVNAME, gpo); + if (gt->irq >= 0) free_irq(gt->irq, (void *)gt); + tasklet_kill(>->work_tasklet); + gpio_free(gpi); + gpio_free(gpo); + kfree(gt); + return err; } } return 0; @@ -143,14 +188,18 @@ device_initcall(gpio_test_init); */ static void __exit gpio_test_exit(void) { - if (gt.out_cansleep) { - gpio_set_value_cansleep(gpo, !val); - } else { - gpio_set_value(gpo, !val); - } - if (gt.irq >= 0) free_irq(gt.irq, NULL); - gpio_free(gpo); + if (gt->irq >= 0) free_irq(gt->irq, (void *)gt); + tasklet_kill(>->work_tasklet); gpio_free(gpi); + if (gpo >= 0) { + if (gt->out_cansleep) { + gpio_set_value_cansleep(gpo, !val); + } else { + gpio_set_value(gpo, !val); + } + gpio_free(gpo); + } + kfree(gt); } module_exit(gpio_test_exit);