#include <sbconfig.h>
#include <sbchipc.h>
-#define MODULE_NAME "diag"
-
-#define MAX_GPIO 8
-#define FLASH_TIME HZ/6
-
-#define EXTIF_ADDR 0x1f000000
-#define EXTIF_UART (EXTIF_ADDR + 0x00800000)
-
-/* For LEDs */
-#define GPIO_TYPE_NORMAL (0x0 << 24)
-#define GPIO_TYPE_EXTIF (0x1 << 24)
-#define GPIO_TYPE_MASK (0xf << 24)
+#include "diag.h"
static unsigned int gpiomask = 0;
module_param(gpiomask, int, 0644);
-enum polarity_t {
- REVERSE = 0,
- NORMAL = 1,
-};
-
-enum {
- PROC_BUTTON,
- PROC_LED,
- PROC_MODEL,
- PROC_GPIOMASK
-};
-
-struct prochandler_t {
- int type;
- void *ptr;
-};
-
-struct button_t {
- struct prochandler_t proc;
- char *name;
- u32 gpio;
- unsigned long seen;
- u8 pressed;
-};
-
-struct led_t {
- struct prochandler_t proc;
- char *name;
- u32 gpio;
- u8 polarity;
- u8 flash;
- u8 state;
-};
-
-struct platform_t {
- char *name;
-
- struct button_t buttons[MAX_GPIO];
- u32 button_mask;
- u32 button_polarity;
-
- struct led_t leds[MAX_GPIO];
-};
-
enum {
/* Linksys */
WAP54GV1,
},
};
-static struct proc_dir_entry *diag, *leds;
-
-extern void *bcm947xx_sbh;
-#define sbh bcm947xx_sbh
-extern spinlock_t bcm947xx_sbh_lock;
-#define sbh_lock bcm947xx_sbh_lock
-
-static int sb_irq(void *sbh);
-static struct platform_t platform;
-
-extern char *nvram_get(char *str);
-
-static void led_flash(unsigned long dummy);
-
static inline char __init *getvar(char *str)
{
return nvram_get(str)?:"";
}
-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 struct platform_t __init *platform_detect(void)
{
char *boardnum, *boardtype, *buf;
return NULL;
}
-static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos);
-static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, void *data);
-static struct file_operations diag_proc_fops = {
- read: diag_proc_read,
- write: diag_proc_write
-};
-
-
-
-static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
-#ifdef LINUX_2_4
- struct inode *inode = file->f_dentry->d_inode;
- struct proc_dir_entry *dent = inode->u.generic_ip;
-#else
- struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
-#endif
- 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;
- if (led->flash) {
- len = sprintf(page, "f\n");
- } else {
- if (led->gpio & GPIO_TYPE_EXTIF) {
- len = sprintf(page, "%d\n", led->state);
- } else {
- u32 in = (sb_gpioin(sbh) & led->gpio ? 1 : 0);
- u8 p = (led->polarity == NORMAL ? 0 : 1);
- 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, "%d\n", gpiomask);
- break;
- }
- }
- len += 1;
-
- if (*ppos < len) {
- len = min_t(int, len - *ppos, count);
- if (copy_to_user(buf, (page + *ppos), len)) {
- kfree(page);
- return -EFAULT;
- }
- *ppos += len;
- } else {
- len = 0;
- }
-
- return len;
-}
-
-
-static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, void *data)
-{
-#ifdef LINUX_2_4
- struct inode *inode = file->f_dentry->d_inode;
- struct proc_dir_entry *dent = inode->u.generic_ip;
-#else
- struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
-#endif
- char *page;
- int ret = -EINVAL;
-
- if ((page = kmalloc(count + 1, GFP_KERNEL)) == NULL)
- return -ENOBUFS;
-
- if (copy_from_user(page, buf, count)) {
- kfree(page);
- return -EINVAL;
- }
- 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 (!(led->gpio & GPIO_TYPE_EXTIF) && (led->gpio & gpiomask))
- break;
-
- if (page[0] == 'f') {
- led->flash = 1;
- led_flash(0);
- } else {
- led->flash = 0;
- if (led->gpio & GPIO_TYPE_EXTIF) {
- led->state = p ^ ((page[0] == '1') ? 1 : 0);
- set_led_extif(led);
- } else {
- sb_gpioouten(sbh, led->gpio, led->gpio);
- sb_gpiocontrol(sbh, led->gpio, 0);
- sb_gpioout(sbh, led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0));
- }
- }
- break;
- }
- case PROC_GPIOMASK: {
- u32 mask;
- gpiomask = simple_strtoul(page, NULL, 16);
-
- mask = platform.button_mask & ~gpiomask;
-
- sb_gpioouten(sbh, mask, 0);
- sb_gpiocontrol(sbh, mask, 0);
- platform.button_polarity = sb_gpioin(sbh) & mask;
- sb_gpiointpolarity(sbh, mask, platform.button_polarity);
- sb_gpiointmask(sbh, mask, mask);
-
- break;
- }
- }
- ret = count;
- }
-
- kfree(page);
- return ret;
-}
-
-struct event_t {
- struct tq_struct tq;
- char buf[256];
- char *argv[3];
- char *envp[6];
-};
-
-static void hotplug_button(struct event_t *event)
-{
- call_usermodehelper (event->argv[0], event->argv, event->envp);
- kfree(event);
-}
-
static void set_irqenable(int enabled)
{
unsigned int coreidx;
unsigned long flags;
chipcregs_t *cc;
+ int irq;
spin_lock_irqsave(sbh_lock, flags);
coreidx = sb_coreidx(sbh);
+
+
+ irq = sb_irq(sbh) + 2;
+ if (enabled)
+ request_irq(irq, button_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, "gpio", button_handler);
+ else
+ free_irq(irq, button_handler);
+
if ((cc = sb_setcore(sbh, SB_CC, 0))) {
int intmask;
spin_unlock_irqrestore(sbh_lock, flags);
}
+static void register_buttons(struct button_t *b)
+{
+ for (; b->name; b++)
+ platform.button_mask |= b->gpio;
+
+ platform.button_mask &= ~gpiomask;
+
+ sb_gpioouten(sbh, platform.button_mask, 0);
+ sb_gpiocontrol(sbh, platform.button_mask, 0);
+ platform.button_polarity = sb_gpioin(sbh) & platform.button_mask;
+ sb_gpiointpolarity(sbh, platform.button_mask, platform.button_polarity);
+ sb_gpiointmask(sbh, platform.button_mask, platform.button_mask);
+
+ set_irqenable(1);
+}
+
+static void unregister_buttons(struct button_t *b)
+{
+
+ sb_gpiointmask(sbh, platform.button_mask, 0);
+
+ set_irqenable(0);
+}
+
+static void hotplug_button(struct event_t *event)
+{
+ call_usermodehelper (event->argv[0], event->argv, event->envp);
+ kfree(event);
+}
+
static void button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
changed = platform.button_polarity ^ in;
platform.button_polarity = in;
- set_irqenable(0);
for (b = platform.buttons; b->name; b++) {
struct event_t *event;
b->seen = jiffies;
}
- set_irqenable(1);
}
-static struct timer_list led_timer = {
- function: &led_flash
-};
+static void register_leds(struct led_t *l)
+{
+ struct proc_dir_entry *p;
+ u32 mask;
+ u32 val;
+
+ 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 {
+ mask |= l->gpio;
+ val |= (l->polarity == NORMAL)?0:l->gpio;
+ }
+
+ 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;
+ }
+ }
+
+ sb_gpioouten(sbh, mask, mask);
+ sb_gpiocontrol(sbh, mask, 0);
+ sb_gpioout(sbh, mask, val);
+}
+
+static void unregister_leds(struct led_t *l)
+{
+ for(; l->name; l++)
+ remove_proc_entry(l->name, leds);
+
+ remove_proc_entry("led", diag);
+}
+
+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 void __init register_buttons(struct button_t *b)
-{
- int irq = sb_irq(sbh) + 2;
- u32 mask;
-
- request_irq(irq, button_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, "gpio", button_handler);
-
- for (; b->name; b++)
- platform.button_mask |= b->gpio;
-
- mask = platform.button_mask & ~gpiomask;
-
- sb_gpioouten(sbh, mask, 0);
- sb_gpiocontrol(sbh, mask, 0);
- platform.button_polarity = sb_gpioin(sbh) & mask;
- sb_gpiointpolarity(sbh, mask, platform.button_polarity);
- sb_gpiointmask(sbh, mask, mask);
-
- set_irqenable(1);
-}
-
-static void __exit unregister_buttons(struct button_t *b)
-{
- int irq = sb_irq(sbh) + 2;
-
- sb_gpiointmask(sbh, platform.button_mask, 0);
-
- free_irq(irq, button_handler);
-}
-
-static void __init register_leds(struct led_t *l)
+static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
- struct proc_dir_entry *p;
-
- leds = proc_mkdir("led", diag);
- if (!leds)
- return;
-
- for(; l->name; l++) {
- if (l->gpio & gpiomask)
- continue;
+#ifdef LINUX_2_4
+ struct inode *inode = file->f_dentry->d_inode;
+ struct proc_dir_entry *dent = inode->u.generic_ip;
+#else
+ struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
+#endif
+ char *page;
+ int len = 0;
- if (l->gpio & GPIO_TYPE_EXTIF) {
- l->state = 0;
- set_led_extif(l);
- } else {
- sb_gpioouten(sbh, l->gpio, l->gpio);
- sb_gpiocontrol(sbh, l->gpio, 0);
- sb_gpioout(sbh, l->gpio, (l->polarity == NORMAL)?0:l->gpio);
+ 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;
+ if (led->flash) {
+ len = sprintf(page, "f\n");
+ } else {
+ if (led->gpio & GPIO_TYPE_EXTIF) {
+ len = sprintf(page, "%d\n", led->state);
+ } else {
+ u32 in = (sb_gpioin(sbh) & led->gpio ? 1 : 0);
+ u8 p = (led->polarity == NORMAL ? 0 : 1);
+ 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, "%d\n", gpiomask);
+ break;
}
+ }
+ len += 1;
- 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;
+ if (*ppos < len) {
+ len = min_t(int, len - *ppos, count);
+ if (copy_to_user(buf, (page + *ppos), len)) {
+ kfree(page);
+ return -EFAULT;
}
+ *ppos += len;
+ } else {
+ len = 0;
}
-}
-
-static void __exit unregister_leds(struct led_t *l)
-{
- for(; l->name; l++)
- remove_proc_entry(l->name, leds);
- remove_proc_entry("led", diag);
+ return len;
}
-static void __exit diag_exit(void)
+
+static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, void *data)
{
+#ifdef LINUX_2_4
+ struct inode *inode = file->f_dentry->d_inode;
+ struct proc_dir_entry *dent = inode->u.generic_ip;
+#else
+ struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
+#endif
+ char *page;
+ int ret = -EINVAL;
- del_timer(&led_timer);
+ if ((page = kmalloc(count + 1, GFP_KERNEL)) == NULL)
+ return -ENOBUFS;
- if (platform.buttons)
- unregister_buttons(platform.buttons);
+ if (copy_from_user(page, buf, count)) {
+ kfree(page);
+ return -EINVAL;
+ }
+ 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_EXTIF) {
+ led->state = p ^ ((page[0] == '1') ? 1 : 0);
+ set_led_extif(led);
+ } else {
+ sb_gpioouten(sbh, led->gpio, led->gpio);
+ sb_gpiocontrol(sbh, led->gpio, 0);
+ sb_gpioout(sbh, led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0));
+ }
+ }
+ break;
+ }
+ case PROC_GPIOMASK:
+ gpiomask = simple_strtoul(page, NULL, 16);
- if (platform.leds)
- unregister_leds(platform.leds);
+ if (platform.buttons) {
+ unregister_buttons(platform.buttons);
+ register_buttons(platform.buttons);
+ }
- remove_proc_entry("model", diag);
- remove_proc_entry("gpiomask", diag);
- remove_proc_entry("diag", NULL);
-}
+ if (platform.leds) {
+ unregister_leds(platform.leds);
+ register_leds(platform.leds);
+ }
+ break;
+ }
+ ret = count;
+ }
-static struct prochandler_t proc_model = { .type = PROC_MODEL };
-static struct prochandler_t proc_gpiomask = { .type = PROC_GPIOMASK };
+ kfree(page);
+ return ret;
+}
static int __init diag_init(void)
{
return 0;
}
+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);
+}
+
EXPORT_NO_SYMBOLS;
module_init(diag_init);
MODULE_AUTHOR("Mike Baker, Felix Fietkau / OpenWrt.org");
MODULE_LICENSE("GPL");
-
-/* TODO: export existing sb_irq instead */
-static int sb_irq(void *sbh)
-{
- uint idx;
- void *regs;
- sbconfig_t *sb;
- uint32 flag, sbipsflag;
- uint irq = 0;
-
- regs = sb_coreregs(sbh);
- sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
- flag = (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
-
- idx = sb_coreidx(sbh);
-
- if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
- (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
- sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-
- /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
- sbipsflag = R_REG(&sb->sbipsflag);
- for (irq = 1; irq <= 4; irq++, sbipsflag >>= 8) {
- if ((sbipsflag & 0x3f) == flag)
- break;
- }
- if (irq == 5)
- irq = 0;
- }
-
- sb_setcoreidx(sbh, idx);
-
- return irq;
-}
--- /dev/null
+/*
+ * diag.h - GPIO interface driver for Broadcom boards
+ *
+ * Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
+ * Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id:$
+ */
+
+#define MODULE_NAME "diag"
+
+#define MAX_GPIO 8
+#define FLASH_TIME HZ/6
+
+enum polarity_t {
+ REVERSE = 0,
+ NORMAL = 1,
+};
+
+enum {
+ PROC_BUTTON,
+ PROC_LED,
+ PROC_MODEL,
+ PROC_GPIOMASK
+};
+
+struct prochandler_t {
+ int type;
+ void *ptr;
+};
+
+struct button_t {
+ struct prochandler_t proc;
+ char *name;
+ u32 gpio;
+ unsigned long seen;
+ u8 pressed;
+};
+
+struct led_t {
+ struct prochandler_t proc;
+ char *name;
+ u32 gpio;
+ u8 polarity;
+ u8 flash;
+ u8 state;
+};
+
+struct platform_t {
+ char *name;
+
+ struct button_t buttons[MAX_GPIO];
+ u32 button_mask;
+ u32 button_polarity;
+
+ struct led_t leds[MAX_GPIO];
+};
+
+struct event_t {
+ struct tq_struct tq;
+ char buf[256];
+ char *argv[3];
+ char *envp[6];
+};
+
+#define sbh bcm947xx_sbh
+#define sbh_lock bcm947xx_sbh_lock
+
+extern void *bcm947xx_sbh;
+extern spinlock_t bcm947xx_sbh_lock;
+extern char *nvram_get(char *str);
+
+static struct platform_t platform;
+
+/* buttons */
+
+static void set_irqenable(int enabled);
+
+static void register_buttons(struct button_t *b);
+static void unregister_buttons(struct button_t *b);
+
+static void hotplug_button(struct event_t *event);
+static void button_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+/* leds */
+
+static void register_leds(struct led_t *l);
+static void unregister_leds(struct led_t *l);
+
+#define EXTIF_ADDR 0x1f000000
+#define EXTIF_UART (EXTIF_ADDR + 0x00800000)
+
+#define GPIO_TYPE_NORMAL (0x0 << 24)
+#define GPIO_TYPE_EXTIF (0x1 << 24)
+#define GPIO_TYPE_MASK (0xf << 24)
+
+static void set_led_extif(struct led_t *led);
+static void led_flash(unsigned long dummy);
+
+static struct timer_list led_timer = {
+ function: &led_flash
+};
+
+/* proc */
+
+static struct proc_dir_entry *diag, *leds;
+
+static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, void *data);
+
+static struct file_operations diag_proc_fops = {
+ read: diag_proc_read,
+ write: diag_proc_write
+};
+
+static struct prochandler_t proc_model = { .type = PROC_MODEL };
+static struct prochandler_t proc_gpiomask = { .type = PROC_GPIOMASK };
+
+/* TODO: export existing sb_irq instead */
+static int sb_irq(void *sbh)
+{
+ uint idx;
+ void *regs;
+ sbconfig_t *sb;
+ uint32 flag, sbipsflag;
+ uint irq = 0;
+
+ regs = sb_coreregs(sbh);
+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+ flag = (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
+
+ idx = sb_coreidx(sbh);
+
+ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
+ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
+ /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
+ sbipsflag = R_REG(&sb->sbipsflag);
+ for (irq = 1; irq <= 4; irq++, sbipsflag >>= 8) {
+ if ((sbipsflag & 0x3f) == flag)
+ break;
+ }
+ if (irq == 5)
+ irq = 0;
+ }
+
+ sb_setcoreidx(sbh, idx);
+
+ return irq;
+}