-struct event_t {
- struct work_struct tq;
- char buf[256];
- char *argv[3];
- char *envp[6];
-};
-
-static void hotplug_button(struct event_t *event)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- call_usermodehelper (event->argv[0], event->argv, event->envp, 1);
-#else
- call_usermodehelper (event->argv[0], event->argv, event->envp);
-#endif
- kfree(event);
-}
-
-static void set_irqenable(int enabled)
-{
- unsigned int coreidx;
- unsigned long flags;
- chipcregs_t *cc;
-
- spin_lock_irqsave(sbh_lock, flags);
- coreidx = sb_coreidx(sbh);
- if ((cc = sb_setcore(sbh, SB_CC, 0))) {
- int intmask;
-
- intmask = readl(&cc->intmask);
- if (enabled)
- intmask |= CI_GPIO;
- else
- intmask &= ~CI_GPIO;
- writel(intmask, &cc->intmask);
- }
- sb_setcoreidx(sbh, coreidx);
- spin_unlock_irqrestore(sbh_lock, flags);
-}
-
-
-static irqreturn_t button_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct button_t *b;
- int in = sb_gpioin(sbh);
- struct event_t *event;
-
- set_irqenable(0);
- for (b = platform.buttons; b->name; b++) {
- if (b->gpio & gpiomask)
- continue;
-
- if (b->polarity != (in & b->gpio)) {
- b->pressed ^= 1;
-
- if ((event = (struct event_t *)kmalloc (sizeof(struct event_t), GFP_ATOMIC))) {
- int i;
- char *scratch = event->buf;
-
- i = 0;
- event->argv[i++] = hotplug_path;
- event->argv[i++] = "button";
- event->argv[i] = 0;
-
- i = 0;
- event->envp[i++] = "HOME=/";
- event->envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
- event->envp[i++] = scratch;
- scratch += sprintf (scratch, "ACTION=%s", b->pressed?"pressed":"released") + 1;
- event->envp[i++] = scratch;
- scratch += sprintf (scratch, "BUTTON=%s", b->name) + 1;
- event->envp[i++] = scratch;
- scratch += sprintf (scratch, "SEEN=%ld", (jiffies - b->seen)/HZ) + 1;
- event->envp[i] = 0;
-
- INIT_WORK(&event->tq, (void *)(void *)hotplug_button, (void *)event);
- schedule_work(&event->tq);
- }
-
- b->seen = jiffies;
- b->polarity ^= b->gpio;
- sb_gpiointpolarity(sbh, b->gpio, b->polarity, GPIO_DRV_PRIORITY);
- }
- }
- set_irqenable(1);
- return IRQ_HANDLED;
-}
-
-static struct timer_list led_timer = {
- function: &led_flash
-};
-
-static void led_flash(unsigned long dummy) {
- struct led_t *l;
- unsigned mask = 0;
- unsigned extif_blink = 0;
-
- for (l = platform.leds; l->name; l++) {
- if (l->flash) {
- if (l->gpio & GPIO_TYPE_EXTIF) {
- extif_blink = 1;
- l->state = !l->state;
- set_led_extif(l);
- } else {
- mask |= l->gpio;
- }
- }
- }
-
- mask &= ~gpiomask;
- if (mask) {
- unsigned val;
-
- val = ~sb_gpioin(sbh);
- val &= mask;
-
- sb_gpioouten(sbh, mask, mask, GPIO_DRV_PRIORITY);
- sb_gpiocontrol(sbh, mask, 0, GPIO_DRV_PRIORITY);
- sb_gpioout(sbh, mask, val, GPIO_DRV_PRIORITY);
- }
- if (mask || extif_blink) {
- mod_timer(&led_timer, jiffies + FLASH_TIME);
- }
-}
-
-static void __init register_buttons(struct button_t *b)
-{
- int irq = sb_irq(sbh) + 2;
-
- request_irq(irq, button_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, "gpio", button_handler);
-
- for (; b->name; b++) {
- if (b->gpio & gpiomask)
- continue;
-
- sb_gpioouten(sbh, b->gpio,0, GPIO_DRV_PRIORITY);
- sb_gpiocontrol(sbh, b->gpio,0, GPIO_DRV_PRIORITY);
- b->polarity = sb_gpioin(sbh) & b->gpio;
- sb_gpiointpolarity(sbh, b->gpio, b->polarity, GPIO_DRV_PRIORITY);
- sb_gpiointmask(sbh, b->gpio, b->gpio, GPIO_DRV_PRIORITY);
- }
- set_irqenable(1);
-}
-
-static void __exit unregister_buttons(struct button_t *b)
-{
- int irq = sb_irq(sbh) + 2;
-
- for (; b->name; b++)
- sb_gpiointmask(sbh, b->gpio, 0, GPIO_DRV_PRIORITY);
-
- free_irq(irq, button_handler);
-}
-
-static void __init register_leds(struct led_t *l)
-{
- struct proc_dir_entry *p;
-
- leds = proc_mkdir("led", diag);
- if (!leds)
- return;
-
- for(; l->name; l++) {
- if (l->gpio & gpiomask)
- continue;
-
- if (l->gpio & GPIO_TYPE_EXTIF) {
- l->state = 0;
- set_led_extif(l);
- } else {
- sb_gpioouten(sbh, l->gpio, l->gpio, GPIO_DRV_PRIORITY);
- sb_gpiocontrol(sbh, l->gpio, 0, GPIO_DRV_PRIORITY);
- sb_gpioout(sbh, l->gpio, (l->polarity == NORMAL)?0:l->gpio, GPIO_DRV_PRIORITY);
- }
-
- if ((p = create_proc_entry(l->name, S_IRUSR, leds))) {
- l->proc.type = PROC_LED;
- l->proc.ptr = l;
- p->data = (void *) &l->proc;
- p->proc_fops = &diag_proc_fops;
- }
- }
-}
-
-static void __exit unregister_leds(struct led_t *l)
-{
- for(; l->name; l++)
- remove_proc_entry(l->name, leds);
-
- remove_proc_entry("led", diag);
-}
-
-static void __exit diag_exit(void)
-{
-
- del_timer(&led_timer);
-
- if (platform.buttons)
- unregister_buttons(platform.buttons);
-
- if (platform.leds)
- unregister_leds(platform.leds);
-
- remove_proc_entry("model", diag);
- remove_proc_entry("gpiomask", diag);
- remove_proc_entry("diag", NULL);
-}
-
-static struct prochandler_t proc_model = { .type = PROC_MODEL };
-static struct prochandler_t proc_gpiomask = { .type = PROC_GPIOMASK };
-