static unsigned int gpiomask = 0;
module_param(gpiomask, int, 0644);
+extern char *nvram_get(char *str);
+static void led_flash(unsigned long dummy);
+
+static struct platform_t platform;
+
+static struct timer_list led_timer = TIMER_INITIALIZER(&led_flash, 0, 0);
+
+static struct proc_dir_entry *diag, *leds;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
+static inline struct inode *file_inode(struct file *f)
+{
+ return f->f_path.dentry->d_inode;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+static inline void *PDE_DATA(const struct inode *inode)
+{
+ return PDE(inode)->data;
+}
+#endif
+
+
enum {
/* Linksys */
WAP54GV1,
WRT160NV1,
WRT160NV3,
WRT300NV11,
+ WRT310NV1,
WRT350N,
WRT600N,
WRT600NV11,
WRT610N,
WRT610NV2,
E1000V1,
+ E1000V21,
+ E2000V1,
E3000V1,
E3200V1,
+ E4200V1,
/* ASUS */
WLHDD,
WL520GU,
ASUS_4702,
WL700GE,
+ RTN12,
RTN16,
+ RTN66U,
/* Buffalo */
WBR2_G54,
WZR_G300N,
WZR_RS_G54,
WZR_RS_G54HP,
- BUFFALO_UNKNOWN,
BUFFALO_UNKNOWN_4710,
/* Siemens */
/* Belkin */
BELKIN_UNKNOWN,
+ BELKIN_F7D330X, /* covers F7D7302,F7D3302,F7D3301, and F7D7301 */
BELKIN_F7D4301,
/* Netgear */
/* Edimax */
PS1208MFG,
+
+ /* Huawei */
+ HUAWEI_E970,
};
static void __init bcm4780_init(void) {
},
.platform_init = bcm57xx_init,
},
+ [WRT310NV1] = {
+ .name = "Linksys WRT310N V1",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 6 }, // "Reset" on back panel
+ { .name = "ses", .gpio = 1 << 8 }, // "Reserved" on top panel
+ },
+ .leds = {
+ { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, // Power LED
+ { .name = "ses_amber", .gpio = 1 << 3, .polarity = REVERSE }, // "Security" Amber
+ { .name = "ses_blue", .gpio = 1 << 9, .polarity = REVERSE }, // "Security" Blue
+ },
+ },
[WRT350N] = {
.name = "Linksys WRT350N",
.buttons = {
{ .name = "ses_orange", .gpio = 1 << 2, .polarity = REVERSE }, /* nvram get gpio2=wps_status_led */
},
},
+ [E1000V21] = {
+ .name = "Linksys E1000 V2.1",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 10 }, /* nvram get reset_gpio=10 */
+ { .name = "wps", .gpio = 1 << 9 }, /* nvram get gpio9=wps_button */
+ },
+ .leds = {
+ { .name = "power", .gpio = 1 << 6, .polarity = REVERSE },
+ { .name = "wlan", .gpio = 1 << 5, .polarity = NORMAL },
+ { .name = "ses_blue", .gpio = 1 << 8, .polarity = NORMAL }, /* nvram get gpio8=wps_led */
+ { .name = "ses_orange", .gpio = 1 << 7, .polarity = NORMAL }, /* nvram get gpio7=wps_status_led */
+ },
+ },
+ [E2000V1] = {
+ .name = "Linksys E2000 V1",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 8 },
+ { .name = "ses", .gpio = 1 << 5 },
+ },
+ .leds = {
+ { .name = "power", .gpio = 1 << 2, .polarity = NORMAL },
+ { .name = "ses_amber", .gpio = 1 << 4, .polarity = REVERSE },
+ { .name = "ses_blue", .gpio = 1 << 3, .polarity = REVERSE },
+ { .name = "wlan", .gpio = 1 << 1, .polarity = NORMAL },
+ },
+ },
[E3000V1] = {
.name = "Linksys E3000 V1",
.buttons = {
{ .name = "power", .gpio = 1 << 3, .polarity = REVERSE }, /* Power LED */
},
},
+ [E4200V1] = {
+ .name = "Linksys E4200 V1",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 6 },
+ { .name = "wps", .gpio = 1 << 4 },
+ },
+ .leds = {
+ { .name = "power", .gpio = 1 << 5, .polarity = REVERSE },
+ },
+ },
/* Asus */
[WLHDD] = {
.name = "ASUS WL-HDD",
},
.platform_init = bcm4780_init,
},
+ [RTN12] = {
+ .name = "ASUS RT-N12",
+ .buttons = {
+ { .name = "wps", .gpio = 1 << 0 },
+ { .name = "reset", .gpio = 1 << 1 },
+ // this is the router/repeater/ap switch
+ { .name = "sw1", .gpio = 1 << 4 },
+ { .name = "sw2", .gpio = 1 << 5 },
+ { .name = "sw3", .gpio = 1 << 6 },
+ },
+ .leds = {
+ { .name = "power", .gpio = 1 << 2, .polarity = REVERSE },
+ { .name = "wlan", .gpio = 1 << 7, .polarity = NORMAL },
+ // gpio3 forces WAN and LAN1-4 all on
+ //{ .name = "eth", .gpio = 1 << 3, .polarity = REVERSE },
+ },
+ },
[RTN16] = {
.name = "ASUS RT-N16",
.buttons = {
{ .name = "reset", .gpio = 1 << 8 },
- { .name = "ses", .gpio = 1 << 5 },
+ { .name = "ses", .gpio = 1 << 6 },
},
.leds = {
{ .name = "power", .gpio = 1 << 1, .polarity = REVERSE },
{ .name = "wlan", .gpio = 1 << 7, .polarity = NORMAL },
},
},
+ [RTN66U] = {
+ .name = "ASUS RT-N66U",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 9 },
+ { .name = "wps", .gpio = 1 << 4 },
+ },
+ .leds = {
+ { .name = "power", .gpio = 1 << 12, .polarity = REVERSE },
+ { .name = "usb", .gpio = 1 << 15, .polarity = REVERSE },
+ },
+ },
/* Buffalo */
[WHR_G54S] = {
.name = "Buffalo WHR-G54S",
{ .name = "vpn", .gpio = 1 << 1, .polarity = REVERSE },
},
},
- [BUFFALO_UNKNOWN] = {
- .name = "Buffalo (unknown)",
- .buttons = {
- { .name = "reset", .gpio = 1 << 7 },
- },
- .leds = {
- { .name = "diag", .gpio = 1 << 1, .polarity = REVERSE },
- },
- },
[BUFFALO_UNKNOWN_4710] = {
.name = "Buffalo (unknown, BCM4710)",
.buttons = {
{ .name = "connected", .gpio = 1 << 0, .polarity = NORMAL },
},
},
+ [BELKIN_F7D330X] = {
+ .name = "Belkin F7D330X",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 6 },
+ { .name = "wps", .gpio = 1 << 8 },
+ },
+ .leds = {
+ /* green */
+ { .name = "power", .gpio = 1 << 10, .polarity = REVERSE },
+ /* orange power */
+ { .name = "warn", .gpio = 1 << 11, .polarity = REVERSE },
+ /* green */
+ { .name = "wps", .gpio = 1 << 12, .polarity = REVERSE },
+ /* orange wps */
+ { .name = "wlan", .gpio = 1 << 13, .polarity = REVERSE },
+ { .name = "usb0", .gpio = 1 << 14, .polarity = REVERSE },
+ /* shipped unconnected in the F7D3302 */
+ { .name = "usb1", .gpio = 1 << 15, .polarity = REVERSE },
+ },
+ },
[BELKIN_F7D4301] = {
.name = "Belkin PlayMax F7D4301",
.buttons = {
{ .name = "wps", .gpio = 1 << 8 },
},
.leds = {
- { .name = "power", .gpio = 1 << 11, .polarity = REVERSE },
+ { .name = "power", .gpio = 1 << 10, .polarity = REVERSE },
+ { .name = "warn", .gpio = 1 << 11, .polarity = REVERSE },
+ { .name = "wps", .gpio = 1 << 12, .polarity = REVERSE },
{ .name = "wlan", .gpio = 1 << 13, .polarity = REVERSE },
- { .name = "led0", .gpio = 1 << 14, .polarity = REVERSE },
- { .name = "led1", .gpio = 1 << 15, .polarity = REVERSE },
+ { .name = "usb0", .gpio = 1 << 14, .polarity = REVERSE },
+ { .name = "usb1", .gpio = 1 << 15, .polarity = REVERSE },
},
},
/* Netgear */
{ .name = "wlan", .gpio = 1 << 0, .polarity = NORMAL },
},
},
+ /* Huawei */
+ [HUAWEI_E970] = {
+ .name = "Huawei E970",
+ .buttons = {
+ { .name = "reset", .gpio = 1 << 6 },
+ },
+ .leds = {
+ { .name = "wlan", .gpio = 1 << 0, .polarity = NORMAL },
+ },
+ },
};
static struct platform_t __init *platform_detect_legacy(void)
{
- char *boardnum, *boardtype, *buf;
+ char *boardnum, *boardtype;
if (strcmp(getvar("nvram_type"), "cfe") == 0)
return &platforms[WGT634U];
if (!strcmp(boardtype, "0x0101") && !strcmp(getvar("boot_ver"), "v3.6"))
return &platforms[WRT54G3G];
- if (!strcmp(getvar("et1phyaddr"),"5") && !strcmp(getvar("et1mdcport"), "1"))
- return &platforms[WRTSL54GS];
-
- /* default to WRT54G */
- return &platforms[WRT54G];
+ /* default to WRT54G if no boot_hw_model is set */
+ if (nvram_get("boot_hw_model") == NULL)
+ return &platforms[WRT54G];
}
if (!strcmp(boardnum, "1024") && !strcmp(boardtype, "0x0446"))
return &platforms[WAP54GV2];
return &platforms[TM2300V2]; /* Dell TrueMobile 2300 v2 */
}
- if (!strcmp(boardnum, "45")) { /* ASUS */
- if (!strcmp(boardtype,"0x0472"))
- return &platforms[WL500W];
- else if (!strcmp(boardtype,"0x467"))
- return &platforms[WL320GE];
- else
- return &platforms[WL500GD];
- }
-
if (!strcmp(boardnum, "10496"))
return &platforms[USR5461];
else
return &platforms[WL500G];
}
- if (startswith(getvar("hardware_version"), "WL300-")) {
- /* Either WL-300g or WL-HDD, do more extensive checks */
- if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) &&
- (simple_strtoul(getvar("et1phyaddr"), NULL, 0) == 1))
- return &platforms[WLHDD];
- if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) &&
- (simple_strtoul(getvar("et1phyaddr"), NULL, 0) == 10))
- return &platforms[WL300G];
- }
/* Sitecom WL-105b */
if (startswith(boardnum, "2") && simple_strtoul(getvar("GemtekPmonVer"), NULL, 0) == 1)
return &platforms[WL105B];
}
}
- if (buf || !strcmp(boardnum, "00")) {/* probably buffalo */
+ if (boardnum || !strcmp(boardnum, "00")) {/* probably buffalo */
if (startswith(boardtype, "bcm94710ap"))
return &platforms[BUFFALO_UNKNOWN_4710];
- else
- return &platforms[BUFFALO_UNKNOWN];
}
if (startswith(getvar("CFEver"), "MotoWRv2") ||
board = bcm47xx_board_get();
board_name = bcm47xx_board_get_name();
- if (board != BCM47XX_BOARD_UNKNOWN && board != BCM47XX_BOARD_NON)
+ if (board != BCM47XX_BOARD_UNKNOWN && board != BCM47XX_BOARD_NO)
printk(MODULE_NAME ": kernel found a \"%s\"\n", board_name);
switch(board) {
+ case BCM47XX_BOARD_ASUS_RTN12:
+ return &platforms[RTN12];
case BCM47XX_BOARD_ASUS_RTN16:
return &platforms[RTN16];
+ case BCM47XX_BOARD_ASUS_RTN66U:
+ return &platforms[RTN66U];
+ case BCM47XX_BOARD_ASUS_WL300G:
+ return &platforms[WL300G];
+ case BCM47XX_BOARD_ASUS_WL320GE:
+ return &platforms[WL320GE];
case BCM47XX_BOARD_ASUS_WL330GE:
return &platforms[WL330GE];
+ case BCM47XX_BOARD_ASUS_WL500GD:
+ return &platforms[WL500GD];
case BCM47XX_BOARD_ASUS_WL500GPV1:
return &platforms[WL500GP];
case BCM47XX_BOARD_ASUS_WL500GPV2:
return &platforms[WL500GPV2];
+ case BCM47XX_BOARD_ASUS_WL500W:
+ return &platforms[WL500W];
case BCM47XX_BOARD_ASUS_WL520GC:
return &platforms[WL520GC];
case BCM47XX_BOARD_ASUS_WL520GU:
return &platforms[WL520GU];
case BCM47XX_BOARD_ASUS_WL700GE:
return &platforms[WL700GE];
+ case BCM47XX_BOARD_ASUS_WLHDD:
+ return &platforms[WLHDD];
case BCM47XX_BOARD_BELKIN_F7D4301:
return &platforms[BELKIN_F7D4301];
+ case BCM47XX_BOARD_BELKIN_F7D330X:
+ return &platforms[BELKIN_F7D330X];
case BCM47XX_BOARD_BUFFALO_WBR2_G54:
return &platforms[WBR2_G54];
case BCM47XX_BOARD_BUFFALO_WHR2_A54G54:
return &platforms[DIR130];
case BCM47XX_BOARD_DLINK_DIR330:
return &platforms[DIR330];
+ case BCM47XX_BOARD_HUAWEI_E970:
+ return &platforms[HUAWEI_E970];
case BCM47XX_BOARD_LINKSYS_E1000V1:
return &platforms[E1000V1];
+ case BCM47XX_BOARD_LINKSYS_E1000V21:
+ return &platforms[E1000V21];
+ case BCM47XX_BOARD_LINKSYS_E2000V1:
+ return &platforms[E2000V1];
case BCM47XX_BOARD_LINKSYS_E3000V1:
return &platforms[E3000V1];
case BCM47XX_BOARD_LINKSYS_E3200V1:
return &platforms[E3200V1];
+ case BCM47XX_BOARD_LINKSYS_E4200V1:
+ return &platforms[E4200V1];
case BCM47XX_BOARD_LINKSYS_WRT150NV1:
return &platforms[WRT150NV1];
case BCM47XX_BOARD_LINKSYS_WRT150NV11:
return &platforms[WRT160NV3];
case BCM47XX_BOARD_LINKSYS_WRT300NV11:
return &platforms[WRT300NV11];
+ case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+ return &platforms[WRT310NV1];
+ case BCM47XX_BOARD_LINKSYS_WRT54GSV1:
+ return &platforms[WRT54G];
case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
return &platforms[WRT54G3GV2_VF];
case BCM47XX_BOARD_LINKSYS_WRT610NV1:
return &platforms[WRT610N];
case BCM47XX_BOARD_LINKSYS_WRT610NV2:
return &platforms[WRT610NV2];
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ return &platforms[WRTSL54GS];
case BCM47XX_BOARD_MOTOROLA_WE800G:
return &platforms[WE800G];
case BCM47XX_BOARD_MOTOROLA_WR850GP:
case BCM47XX_BOARD_NETGEAR_WNDR3700V3:
return &platforms[WNDR3700V3];
case BCM47XX_BOARD_UNKNOWN:
- case BCM47XX_BOARD_NON:
+ case BCM47XX_BOARD_NO:
printk(MODULE_NAME ": unknown board found, try legacy detect\n");
printk(MODULE_NAME ": please open a ticket at https://dev.openwrt.org and attach the complete nvram\n");
return platform_detect_legacy();
static void gpio_set_irqenable(int enabled, irqreturn_t (*handler)(int, void *))
{
int irq;
+ int err;
irq = gpio_to_irq(0);
- if (irq == -EINVAL) return;
+ if (irq < 0) {
+ pr_err("no irq for gpio available\n");
+ return;
+ }
if (enabled) {
- if (request_irq(irq, handler, IRQF_SHARED, "gpio", handler))
+ err = request_irq(irq, handler, IRQF_SHARED, "gpio", handler);
+ if (err) {
+ pr_err("can not reqeust irq\n");
return;
+ }
} else {
free_irq(irq, handler);
}
}
}
-static void register_buttons(struct button_t *b)
-{
- for (; b->name; b++)
- platform.button_mask |= b->gpio;
-
- platform.button_mask &= ~gpiomask;
-
- bcm47xx_gpio_outen(platform.button_mask, 0);
- bcm47xx_gpio_control(platform.button_mask, 0);
- platform.button_polarity = bcm47xx_gpio_in(~0) & platform.button_mask;
- bcm47xx_gpio_polarity(platform.button_mask, platform.button_polarity);
- bcm47xx_gpio_intmask(platform.button_mask, platform.button_mask);
-
- gpio_set_irqenable(1, button_handler);
-}
-
-static void unregister_buttons(struct button_t *b)
-{
- bcm47xx_gpio_intmask(platform.button_mask, 0);
-
- gpio_set_irqenable(0, button_handler);
-}
-
-
-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);
kfree(event);
}
-
-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);
- snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
- add_msg(event, buf, 0);
-
- return 0;
-}
-
-
static irqreturn_t button_handler(int irq, void *dev_id)
{
struct button_t *b;
return IRQ_HANDLED;
}
-static void register_leds(struct led_t *l)
+static void register_buttons(struct button_t *b)
{
- struct proc_dir_entry *p;
- u32 mask = 0;
- u32 oe_mask = 0;
- u32 val = 0;
-
- leds = proc_mkdir("led", diag);
- if (!leds)
- return;
+ for (; b->name; b++)
+ platform.button_mask |= b->gpio;
- for(; l->name; l++) {
- if (l->gpio & gpiomask)
- continue;
+ platform.button_mask &= ~gpiomask;
- switch (l->gpio & GPIO_TYPE_MASK) {
- case GPIO_TYPE_EXTIF:
- l->state = 0;
- set_led_extif(l);
- break;
- case GPIO_TYPE_SHIFT:
- mask |= (SHIFTREG_DATA | SHIFTREG_CLK);
- oe_mask |= (SHIFTREG_DATA | SHIFTREG_CLK);
- l->state = (l->polarity != NORMAL);
- set_led_shift(l);
- break;
- case GPIO_TYPE_NORMAL:
- default:
- if (l->polarity != INPUT) oe_mask |= l->gpio;
- mask |= l->gpio;
- val |= (l->polarity == NORMAL)?0:l->gpio;
- break;
- }
+ bcm47xx_gpio_outen(platform.button_mask, 0);
+ bcm47xx_gpio_control(platform.button_mask, 0);
+ platform.button_polarity = bcm47xx_gpio_in(~0) & platform.button_mask;
+ bcm47xx_gpio_polarity(platform.button_mask, platform.button_polarity);
+ bcm47xx_gpio_intmask(platform.button_mask, platform.button_mask);
- if (l->polarity == INPUT) continue;
+ gpio_set_irqenable(1, button_handler);
+}
- 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 unregister_buttons(struct button_t *b)
+{
+ bcm47xx_gpio_intmask(platform.button_mask, 0);
- bcm47xx_gpio_outen(mask, oe_mask);
- bcm47xx_gpio_control(mask, 0);
- bcm47xx_gpio_out(mask, val);
- bcm47xx_gpio_intmask(mask, 0);
+ gpio_set_irqenable(0, button_handler);
}
-static void unregister_leds(struct led_t *l)
+
+static void add_msg(struct event_t *event, char *msg, int argv)
{
- for(; l->name; l++)
- remove_proc_entry(l->name, leds);
+ char *s;
- remove_proc_entry("led", diag);
+ if (argv)
+ return;
+
+ s = skb_put(event->skb, strlen(msg) + 1);
+ strcpy(s, msg);
}
-static void set_led_extif(struct led_t *led)
+static int fill_event (struct event_t *event)
{
- volatile u8 *addr = (volatile u8 *) KSEG1ADDR(EXTIF_UART) + (led->gpio & ~GPIO_TYPE_MASK);
- if (led->state)
- *addr = 0xFF;
- else
- *addr;
+ 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);
+ snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
+ add_msg(event, buf, 0);
+
+ return 0;
}
/*
}
}
+static void set_led_extif(struct led_t *led)
+{
+ volatile u8 *addr = (volatile u8 *) KSEG1ADDR(EXTIF_UART) + (led->gpio & ~GPIO_TYPE_MASK);
+ if (led->state)
+ *addr = 0xFF;
+ else
+ *addr;
+}
+
static void led_flash(unsigned long dummy) {
struct led_t *l;
}
}
-static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+static int diag_led_show(struct seq_file *m, void *v)
+{
+ struct led_t * led = m->private;
+
+ u8 p = (led->polarity == NORMAL ? 0 : 1);
+ if (led->flash) {
+ return seq_printf(m, "f\n");
+ } else if ((led->gpio & GPIO_TYPE_MASK) != GPIO_TYPE_NORMAL) {
+ return seq_printf(m, "%d\n", ((led->state ^ p) ? 1 : 0));
+ } else {
+ u32 in = (bcm47xx_gpio_in(~0) & led->gpio ? 1 : 0);
+ return seq_printf(m, "%d\n", ((in ^ p) ? 1 : 0));
+ }
+}
+
+static int diag_led_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, diag_led_show, PDE_DATA(inode));
+}
+
+static ssize_t diag_led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
- char *page;
- int len = 0;
-
- if ((page = kmalloc(1024, GFP_KERNEL)) == NULL)
- return -ENOBUFS;
-
- if (dent->data != NULL) {
- struct prochandler_t *handler = (struct prochandler_t *) dent->data;
- switch (handler->type) {
- case PROC_LED: {
- struct led_t * led = (struct led_t *) handler->ptr;
- u8 p = (led->polarity == NORMAL ? 0 : 1);
- if (led->flash) {
- len = sprintf(page, "f\n");
- } else if ((led->gpio & GPIO_TYPE_MASK) != GPIO_TYPE_NORMAL) {
- len = sprintf(page, "%d\n", ((led->state ^ p) ? 1 : 0));
- } else {
- u32 in = (bcm47xx_gpio_in(~0) & led->gpio ? 1 : 0);
- len = sprintf(page, "%d\n", ((in ^ p) ? 1 : 0));
- }
- break;
- }
- case PROC_MODEL:
- len = sprintf(page, "%s\n", platform.name);
- break;
- case PROC_GPIOMASK:
- len = sprintf(page, "0x%04x\n", gpiomask);
- break;
+ struct led_t *led = PDE_DATA(file_inode(file));
+ char cmd[5];
+ size_t len;
+ int p;
+
+ len = min(count, sizeof(cmd) - 1);
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+
+ p = (led->polarity == NORMAL ? 0 : 1);
+ if (cmd[0] == 'f') {
+ led->flash = 1;
+ led_flash(0);
+ } else {
+ led->flash = 0;
+ if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_EXTIF) {
+ led->state = p ^ ((cmd[0] == '1') ? 1 : 0);
+ set_led_extif(led);
+ } else if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_SHIFT) {
+ led->state = p ^ ((cmd[0] == '1') ? 1 : 0);
+ set_led_shift(led);
+ } else {
+ bcm47xx_gpio_outen(led->gpio, led->gpio);
+ bcm47xx_gpio_control(led->gpio, 0);
+ bcm47xx_gpio_out(led->gpio, ((p ^ (cmd[0] == '1')) ? led->gpio : 0));
}
}
- len += 1;
+ return count;
+}
+
+static const struct file_operations diag_led_fops = {
+ .open = diag_led_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = diag_led_write
+};
+
+static void register_leds(struct led_t *l)
+{
+ struct proc_dir_entry *p;
+ u32 mask = 0;
+ u32 oe_mask = 0;
+ u32 val = 0;
+
+ leds = proc_mkdir("led", diag);
+ if (!leds)
+ return;
- if (*ppos < len) {
- len = min_t(int, len - *ppos, count);
- if (copy_to_user(buf, (page + *ppos), len)) {
- kfree(page);
- return -EFAULT;
+ for(; l->name; l++) {
+ if (l->gpio & gpiomask)
+ continue;
+
+ switch (l->gpio & GPIO_TYPE_MASK) {
+ case GPIO_TYPE_EXTIF:
+ l->state = 0;
+ set_led_extif(l);
+ break;
+ case GPIO_TYPE_SHIFT:
+ mask |= (SHIFTREG_DATA | SHIFTREG_CLK);
+ oe_mask |= (SHIFTREG_DATA | SHIFTREG_CLK);
+ l->state = (l->polarity != NORMAL);
+ set_led_shift(l);
+ break;
+ case GPIO_TYPE_NORMAL:
+ default:
+ if (l->polarity != INPUT) oe_mask |= l->gpio;
+ mask |= l->gpio;
+ val |= (l->polarity == NORMAL)?0:l->gpio;
+ break;
}
- *ppos += len;
- } else {
- len = 0;
+
+ if (l->polarity == INPUT) continue;
+
+ p = proc_create_data(l->name, S_IRUSR, leds, &diag_led_fops, l);
}
- kfree(page);
- return len;
+ bcm47xx_gpio_outen(mask, oe_mask);
+ bcm47xx_gpio_control(mask, 0);
+ bcm47xx_gpio_out(mask, val);
+ bcm47xx_gpio_intmask(mask, 0);
}
+static void unregister_leds(struct led_t *l)
+{
+ for(; l->name; l++)
+ remove_proc_entry(l->name, leds);
+
+ remove_proc_entry("led", diag);
+}
-static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+static int diag_model_show(struct seq_file *m, void *v)
{
- struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
- char *page;
- int ret = -EINVAL;
+ return seq_printf(m, "%s\n", platform.name);
+}
- if ((page = kmalloc(count + 1, GFP_KERNEL)) == NULL)
- return -ENOBUFS;
+static int diag_model_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, diag_model_show, PDE_DATA(inode));
+}
- if (copy_from_user(page, buf, count)) {
- kfree(page);
- return -EINVAL;
+static const struct file_operations diag_model_fops = {
+ .open = diag_model_open,
+ .read = seq_read,
+ .llseek = seq_lseek
+};
+
+static int diag_gpiomask_show(struct seq_file *m, void *v)
+{
+ return seq_printf(m, "0x%04x\n", gpiomask);
+}
+
+static int diag_gpiomask_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, diag_gpiomask_show, PDE_DATA(inode));
+}
+
+static ssize_t diag_gpiomask_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ int err = kstrtouint_from_user(buf, count, 0, &gpiomask);
+ if (err)
+ return err;
+
+ if (platform.buttons) {
+ unregister_buttons(platform.buttons);
+ register_buttons(platform.buttons);
}
- page[count] = 0;
-
- if (dent->data != NULL) {
- struct prochandler_t *handler = (struct prochandler_t *) dent->data;
- switch (handler->type) {
- case PROC_LED: {
- struct led_t *led = (struct led_t *) handler->ptr;
- int p = (led->polarity == NORMAL ? 0 : 1);
-
- if (page[0] == 'f') {
- led->flash = 1;
- led_flash(0);
- } else {
- led->flash = 0;
- if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_EXTIF) {
- led->state = p ^ ((page[0] == '1') ? 1 : 0);
- set_led_extif(led);
- } else if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_SHIFT) {
- led->state = p ^ ((page[0] == '1') ? 1 : 0);
- set_led_shift(led);
- } else {
- bcm47xx_gpio_outen(led->gpio, led->gpio);
- bcm47xx_gpio_control(led->gpio, 0);
- bcm47xx_gpio_out(led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0));
- }
- }
- break;
- }
- case PROC_GPIOMASK:
- gpiomask = simple_strtoul(page, NULL, 0);
-
- if (platform.buttons) {
- unregister_buttons(platform.buttons);
- register_buttons(platform.buttons);
- }
-
- if (platform.leds) {
- unregister_leds(platform.leds);
- register_leds(platform.leds);
- }
- break;
- }
- ret = count;
+
+ if (platform.leds) {
+ unregister_leds(platform.leds);
+ register_leds(platform.leds);
}
- kfree(page);
- return ret;
+ return count;
}
+static const struct file_operations diag_gpiomask_fops = {
+ .open = diag_gpiomask_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = diag_gpiomask_write
+};
+
static int __init diag_init(void)
{
static struct proc_dir_entry *p;
return -EINVAL;
}
- if ((p = create_proc_entry("model", S_IRUSR, diag))) {
- p->data = (void *) &proc_model;
- p->proc_fops = &diag_proc_fops;
+ p = proc_create("model", S_IRUSR, diag, &diag_model_fops);
+ if (!p) {
+ remove_proc_entry("diag", NULL);
+ return -EINVAL;
}
- if ((p = create_proc_entry("gpiomask", S_IRUSR | S_IWUSR, diag))) {
- p->data = (void *) &proc_gpiomask;
- p->proc_fops = &diag_proc_fops;
+ p = proc_create("gpiomask", S_IRUSR | S_IWUSR, diag, &diag_gpiomask_fops);
+ if (!p) {
+ remove_proc_entry("model", diag);
+ remove_proc_entry("diag", NULL);
+ return -EINVAL;
}
if (platform.buttons)