X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/f4e6645a5dedcc0f0626b2c239948147c0930911..df40b4d7da7611671393534c7e833663d4f8f9a3:/package/broadcom-diag/src/diag.c diff --git a/package/broadcom-diag/src/diag.c b/package/broadcom-diag/src/diag.c index 88881b950..c53ff2f97 100644 --- a/package/broadcom-diag/src/diag.c +++ b/package/broadcom-diag/src/diag.c @@ -2,7 +2,7 @@ * diag.c - GPIO interface driver for Broadcom boards * * Copyright (C) 2006 Mike Baker , - * Felix Fietkau + * Copyright (C) 2006-2007 Felix Fietkau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,10 +28,13 @@ #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -#include +#ifndef LINUX_2_4 #include -#define hotplug_path uevent_helper +#include +#include +#include +extern struct sock *uevent_sock; +extern u64 uevent_next_seqnum(void); #else #include #define INIT_WORK INIT_TQUEUE @@ -43,6 +46,7 @@ #include "diag.h" #define getvar(str) (nvram_get(str)?:"") +static int fill_event(struct event_t *); static unsigned int gpiomask = 0; module_param(gpiomask, int, 0644); @@ -62,7 +66,9 @@ enum { WL500G, WL500GD, WL500GP, + WL500W, ASUS_4702, + WL700GE, /* Buffalo */ WBR2_G54, @@ -99,8 +105,29 @@ enum { /* Trendware */ TEW411BRPP, + + /* SimpleTech */ + STI_NAS, + + /* D-Link */ + DIR130, + DIR330, }; +static void __init bcm4780_init(void) { + int pin = 1 << 3; + + /* Enables GPIO 3 that controls HDD and led power on ASUS WL-700gE */ + printk(MODULE_NAME ": Spinning up HDD and enabling leds\n"); + gpio_outen(pin, pin); + gpio_control(pin, 0); + gpio_out(pin, pin); + + /* Wait 5s, so the HDD can spin up */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 5); +} + static struct platform_t __initdata platforms[] = { /* Linksys */ [WAP54GV1] = { @@ -195,6 +222,7 @@ static struct platform_t __initdata platforms[] = { }, .leds = { { .name = "power", .gpio = 1 << 0, .polarity = REVERSE }, + { .name = "usb", .gpio = 1 << 2, .polarity = NORMAL }, }, }, [WL300G] = { @@ -234,6 +262,16 @@ static struct platform_t __initdata platforms[] = { { .name = "power", .gpio = 1 << 1, .polarity = REVERSE }, }, }, + [WL500W] = { + .name = "ASUS WL-500W", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 7 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 5, .polarity = REVERSE }, + }, + }, [ASUS_4702] = { .name = "ASUS (unknown, BCM4702)", .buttons = { @@ -243,6 +281,25 @@ static struct platform_t __initdata platforms[] = { { .name = "power", .gpio = 1 << 0, .polarity = REVERSE }, }, }, + [WL700GE] = { + .name = "ASUS WL-700gE", + .buttons = { + { .name = "reset", .gpio = 1 << 7 }, // on back, hardwired, always resets device regardless OS state + { .name = "ses", .gpio = 1 << 4 }, // on back, actual name ezsetup + { .name = "power", .gpio = 1 << 0 }, // on front + { .name = "copy", .gpio = 1 << 6 }, // on front + }, + .leds = { +#if 0 + // GPIO that controls power led also enables/disables some essential functions + // - power to HDD + // - switch leds + { .name = "power", .gpio = 1 << 3, .polarity = NORMAL }, // actual name power +#endif + { .name = "diag", .gpio = 1 << 1, .polarity = REVERSE }, // actual name ready + }, + .platform_init = bcm4780_init, + }, /* Buffalo */ [WHR_G54S] = { .name = "Buffalo WHR-G54S", @@ -256,6 +313,7 @@ static struct platform_t __initdata platforms[] = { { .name = "internal", .gpio = 1 << 3, .polarity = REVERSE }, { .name = "ses", .gpio = 1 << 6, .polarity = REVERSE }, { .name = "bridge", .gpio = 1 << 1, .polarity = REVERSE }, + { .name = "wlan", .gpio = 1 << 2, .polarity = REVERSE }, }, }, [WBR2_G54] = { @@ -277,8 +335,10 @@ static struct platform_t __initdata platforms[] = { }, .leds = { { .name = "diag", .gpio = 1 << 7, .polarity = REVERSE }, + { .name = "internal", .gpio = 1 << 3, .polarity = REVERSE }, { .name = "bridge", .gpio = 1 << 1, .polarity = REVERSE }, { .name = "ses", .gpio = 1 << 6, .polarity = REVERSE }, + { .name = "wlan", .gpio = 1 << 2, .polarity = REVERSE }, }, }, [WHR2_A54G54] = { @@ -454,7 +514,7 @@ static struct platform_t __initdata platforms[] = { { .name = "reset", .gpio = 1 << 2 }, }, .leds = { - { .name = "power", .gpio = 1 << 3, .polarity = REVERSE }, + { .name = "power", .gpio = 1 << 3, .polarity = NORMAL }, }, }, /* Trendware */ @@ -469,6 +529,42 @@ static struct platform_t __initdata platforms[] = { { .name = "bridge", .gpio = 1 << 6, .polarity = NORMAL }, }, }, + /* SimpleTech */ + [STI_NAS] = { + .name = "SimpleTech SimpleShare NAS", + .buttons = { + { .name = "reset", .gpio = 1 << 7 }, // on back, hardwired, always resets device regardless OS state + { .name = "power", .gpio = 1 << 0 }, // on back + }, + .leds = { + { .name = "diag", .gpio = 1 << 1, .polarity = REVERSE }, // actual name ready + }, + .platform_init = bcm4780_init, + }, + /* D-Link */ + [DIR130] = { + .name = "D-Link DIR-130", + .buttons = { + { .name = "reset", .gpio = 1 << 3}, + { .name = "reserved", .gpio = 1 << 7}, + }, + .leds = { + { .name = "diag", .gpio = 1 << 0}, + { .name = "blue", .gpio = 1 << 6}, + }, + }, + [DIR330] = { + .name = "D-Link DIR-330", + .buttons = { + { .name = "reset", .gpio = 1 << 3}, + { .name = "reserved", .gpio = 1 << 7}, + }, + .leds = { + { .name = "diag", .gpio = 1 << 0}, + { .name = "usb", .gpio = 1 << 4}, + { .name = "blue", .gpio = 1 << 6}, + }, + }, }; static struct platform_t __init *platform_detect(void) @@ -477,10 +573,17 @@ static struct platform_t __init *platform_detect(void) boardnum = getvar("boardnum"); boardtype = getvar("boardtype"); + + if (strcmp(getvar("nvram_type"), "cfe") == 0) + return &platforms[WGT634U]; + + if (strncmp(getvar("model_no"), "WL700",5) == 0) + return &platforms[WL700GE]; + if (strncmp(getvar("pmon_ver"), "CFE", 3) == 0) { /* CFE based - newer hardware */ if (!strcmp(boardnum, "42")) { /* Linksys */ - if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), 1)) + if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), "1")) return &platforms[WRT350N]; if (!strcmp(boardtype, "0x0101") && !strcmp(getvar("boot_ver"), "v3.6")) @@ -496,12 +599,21 @@ static struct platform_t __init *platform_detect(void) if (!strcmp(boardnum, "45")) { /* ASUS */ if (!strcmp(boardtype,"0x042f")) return &platforms[WL500GP]; + else if (!strcmp(boardtype,"0x0472")) + return &platforms[WL500W]; else return &platforms[WL500GD]; } if (!strcmp(boardnum, "10496")) return &platforms[USR5461]; + + /* D-Link */ + if (!strcmp(getvar("model_name"), "DIR-130")) + return &platforms[DIR130]; + if (!strcmp(getvar("model_name"), "DIR-330")) + return &platforms[DIR330]; + } else { /* PMON based - old stuff */ /* Dell TrueMobile 2300 */ @@ -575,6 +687,9 @@ static struct platform_t __init *platform_detect(void) return &platforms[TEW411BRPP]; } + if (!strncmp(boardnum, "04FN52", 6)) /* SimpleTech SimpleShare */ + return &platforms[STI_NAS]; + /* not found */ return NULL; } @@ -602,17 +717,104 @@ static void unregister_buttons(struct button_t *b) gpio_set_irqenable(0, button_handler); } + +#ifndef LINUX_2_4 +static void add_msg(struct event_t *event, char *msg, int argv) +{ + char *s; + + if (argv) + return; + + s = skb_put(event->skb, strlen(msg) + 1); + strcpy(s, msg); +} + +static void hotplug_button(struct work_struct *work) +{ + struct event_t *event = container_of(work, struct event_t, wq); + char *s; + + if (!uevent_sock) + return; + + event->skb = alloc_skb(2048, GFP_KERNEL); + + s = skb_put(event->skb, strlen(event->action) + 2); + sprintf(s, "%s@", event->action); + fill_event(event); + + NETLINK_CB(event->skb).dst_group = 1; + netlink_broadcast(uevent_sock, event->skb, 0, 1, GFP_KERNEL); + + kfree(event); +} + +#else /* !LINUX_2_4 */ +static inline char *kzalloc(unsigned int size, unsigned int gfp) +{ + char *p; + + p = kmalloc(size, gfp); + if (p == NULL) + return NULL; + + memset(p, 0, size); + + return p; +} + +static void add_msg(struct event_t *event, char *msg, int argv) +{ + if (argv) + event->argv[event->anr++] = event->scratch; + else + event->envp[event->enr++] = event->scratch; + + event->scratch += sprintf(event->scratch, "%s", msg) + 1; +} + 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 + char *scratch = kzalloc(256, GFP_KERNEL); + event->scratch = scratch; + + add_msg(event, hotplug_path, 1); + add_msg(event, "button", 1); + fill_event(event); call_usermodehelper (event->argv[0], event->argv, event->envp); -#endif + kfree(scratch); kfree(event); } +#endif /* !LINUX_2_4 */ + +static int fill_event (struct event_t *event) +{ + static char buf[128]; + + add_msg(event, "HOME=/", 0); + add_msg(event, "PATH=/sbin:/bin:/usr/sbin:/usr/bin", 0); + add_msg(event, "SUBSYSTEM=button", 0); + snprintf(buf, 128, "ACTION=%s", event->action); + add_msg(event, buf, 0); + snprintf(buf, 128, "BUTTON=%s", event->name); + add_msg(event, buf, 0); + snprintf(buf, 128, "SEEN=%ld", event->seen); + add_msg(event, buf, 0); +#ifndef LINUX_2_4 + snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum()); + add_msg(event, buf, 0); +#endif + + return 0; +} + +#ifndef LINUX_2_4 +static irqreturn_t button_handler(int irq, void *dev_id) +#else static irqreturn_t button_handler(int irq, void *dev_id, struct pt_regs *regs) +#endif { struct button_t *b; u32 in, changed; @@ -631,27 +833,15 @@ static irqreturn_t button_handler(int irq, void *dev_id, struct pt_regs *regs) 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; - + if ((event = (struct event_t *)kzalloc (sizeof(struct event_t), GFP_ATOMIC))) { + event->seen = (jiffies - b->seen)/HZ; + event->name = b->name; + event->action = b->pressed ? "pressed" : "released"; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_WORK(&event->wq, (void *)(void *)hotplug_button); +#else INIT_WORK(&event->wq, (void *)(void *)hotplug_button, (void *)event); +#endif schedule_work(&event->wq); } @@ -791,6 +981,7 @@ static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t len = 0; } + kfree(page); return len; } @@ -872,6 +1063,9 @@ static int __init diag_init(void) memcpy(&platform, detected, sizeof(struct platform_t)); printk(MODULE_NAME ": Detected '%s'\n", platform.name); + if (platform.platform_init != NULL) { + platform.platform_init(); + } if (!(diag = proc_mkdir("diag", NULL))) { printk(MODULE_NAME ": proc_mkdir on /proc/diag failed\n"); @@ -899,7 +1093,6 @@ static int __init diag_init(void) static void __exit diag_exit(void) { - del_timer(&led_timer); if (platform.buttons)