sync kmod-switch with whiterussian
[openwrt/staging/dedeckeh.git] / openwrt / target / linux / package / switch / src / switch-adm.c
index aebaaf6d2be72bd4472de0697bb3dff9214914db..2ce87e777fee15d3408a4516982110207ae51537 100644 (file)
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 
-#include "gpio.h"
 #include "switch-core.h"
+#include "gpio.h"
 
 #define DRIVER_NAME "adm6996"
+#define DRIVER_VERSION "0.01"
 
-static int eecs = 2;
-static int eesk = 3;
-static int eedi = 5;
-static int eerc = 6;
+static int eecs = 0;
+static int eesk = 0;
+static int eedi = 0;
+static int eerc = 0;
 static int force = 0;
 
 MODULE_AUTHOR("Felix Fietkau <openwrt@nbd.name>");
@@ -57,8 +58,35 @@ MODULE_PARM(force, "i");
 #define adm_write16(cs, w) { __u16 val = hton16(w); adm_write(cs, (__u8 *)&val, sizeof(val)*8); }
 #define adm_write32(cs, i) { uint32 val = hton32(i); adm_write(cs, (__u8 *)&val, sizeof(val)*8); }
 
+#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
 
-extern int getintvar(char **vars, char *name);
+#if defined(BCMGPIO2) || defined(BCMGPIO)
+extern char *nvram_get(char *name);
+
+/* Return gpio pin number assigned to the named pin */
+/*
+* Variable should be in format:
+*
+*      gpio<N>=pin_name
+*
+* 'def_pin' is returned if there is no such variable found.
+*/
+static unsigned int getgpiopin(char *pin_name, unsigned int def_pin)
+{
+       char name[] = "gpioXXXX";
+       char *val;
+       unsigned int pin;
+
+       /* Go thru all possibilities till a match in pin name */
+       for (pin = 0; pin < 16; pin ++) {
+               sprintf(name, "gpio%d", pin);
+               val = nvram_get(name);
+               if (val && !strcmp(val, pin_name))
+                       return pin;
+       }
+       return def_pin;
+}
+#endif
 
 
 static void adm_write(int cs, char *buf, unsigned int bits)
@@ -240,7 +268,7 @@ static int port_conf[] = { 0x01, 0x03, 0x05, 0x07, 0x08, 0x09 };
 /* Bits in VLAN port mapping */
 static int vlan_ports[] = { 1 << 0, 1 << 2, 1 << 4, 1 << 6, 1 << 7, 1 << 8 };
 
-static int handle_vlan_port_read(char *buf, int nr)
+static int handle_vlan_port_read(void *driver, char *buf, int nr)
 {
        int ports, i, c, len = 0;
                        
@@ -253,7 +281,16 @@ static int handle_vlan_port_read(char *buf, int nr)
        for (i = 0; i <= 5; i++) {
                if (ports & vlan_ports[i]) {
                        c = adm_rreg(0, port_conf[i]);
-                       len += sprintf(buf + len, (c & (1 << 4) ? "%dt\t" : (i == 5 ? "%du\t" : "%d\t")), i);
+                       
+                       len += sprintf(buf + len, "%d", i);
+                       if (c & (1 << 4)) {
+                               buf[len++] = 't';
+                               if (((c & (0xf << 10)) >> 10) == nr)
+                                       buf[len++] = '*';
+                       } else if (i == 5)
+                               buf[len++] = 'u';
+
+                       buf[len++] = '\t';
                }
        }
        len += sprintf(buf + len, "\n");
@@ -261,30 +298,33 @@ static int handle_vlan_port_read(char *buf, int nr)
        return len;
 }
 
-static int handle_vlan_port_write(char *buf, int nr)
+static int handle_vlan_port_write(void *driver, char *buf, int nr)
 {
-       int i, c, ports;
-       int map = switch_parse_vlan(buf);
+       int i, cfg, ports;
+       switch_driver *d = (switch_driver *) driver;
+       switch_vlan_config *c = switch_parse_vlan(d, buf);
 
-       if (map == -1)
+       if (c == NULL)
                return -1;
 
        ports = adm_rreg(0, 0x13 + nr);
-       for (i = 0; i <= 5; i++) {
-               if (map & (1 << i)) {
+       for (i = 0; i < d->ports; i++) {
+               if (c->port & (1 << i)) {
                        ports |= vlan_ports[i];
 
-                       c = adm_rreg(0, port_conf[i]);
+                       cfg = adm_rreg(0, port_conf[i]);
                        
                        /* Tagging */
-                       if (map & (1 << (8 + i)))
-                               c |= (1 << 4);
+                       if (c->untag & (1 << i))
+                               cfg &= ~(1 << 4);
                        else
-                               c &= ~(1 << 4);
-
-                       c = (c & ~(0xf << 10)) | (nr << 10);
+                               cfg |= (1 << 4);
                        
-                       adm_wreg(port_conf[i], (__u16) c);
+                       if ((c->untag | c->pvid) & (1 << i)) {
+                               cfg = (cfg & ~(0xf << 10)) | (nr << 10);
+                       }
+                       
+                       adm_wreg(port_conf[i], (__u16) cfg);
                } else {
                        ports &= ~(vlan_ports[i]);
                }
@@ -294,12 +334,12 @@ static int handle_vlan_port_write(char *buf, int nr)
        return 0;
 }
 
-static int handle_port_enable_read(char *buf, int nr)
+static int handle_port_enable_read(void *driver, char *buf, int nr)
 {
        return sprintf(buf, "%d\n", ((adm_rreg(0, port_conf[nr]) & (1 << 5)) ? 0 : 1));
 }
 
-static int handle_port_enable_write(char *buf, int nr)
+static int handle_port_enable_write(void *driver, char *buf, int nr)
 {
        int reg = adm_rreg(0, port_conf[nr]);
        
@@ -313,7 +353,7 @@ static int handle_port_enable_write(char *buf, int nr)
        return 0;
 }
 
-static int handle_port_media_read(char *buf, int nr)
+static int handle_port_media_read(void *driver, char *buf, int nr)
 {
        int len;
        int media = 0;
@@ -330,7 +370,7 @@ static int handle_port_media_read(char *buf, int nr)
        return len + sprintf(buf + len, "\n");
 }
 
-static int handle_port_media_write(char *buf, int nr)
+static int handle_port_media_write(void *driver, char *buf, int nr)
 {
        int media = switch_parse_media(buf);
        int reg = adm_rreg(0, port_conf[nr]);
@@ -351,12 +391,12 @@ static int handle_port_media_write(char *buf, int nr)
        return 0;
 }
 
-static int handle_vlan_enable_read(char *buf, int nr)
+static int handle_vlan_enable_read(void *driver, char *buf, int nr)
 {
        return sprintf(buf, "%d\n", ((adm_rreg(0, 0x11) & (1 << 5)) ? 1 : 0));
 }
 
-static int handle_vlan_enable_write(char *buf, int nr)
+static int handle_vlan_enable_write(void *driver, char *buf, int nr)
 {
        int reg = adm_rreg(0, 0x11);
        
@@ -370,7 +410,7 @@ static int handle_vlan_enable_write(char *buf, int nr)
        return 0;
 }
 
-static int handle_reset(char *buf, int nr)
+static int handle_reset(void *driver, char *buf, int nr)
 {
        int i;
 
@@ -381,23 +421,24 @@ static int handle_reset(char *buf, int nr)
         * reset logic therefore we must explicitly perform the
         * sequence in software.
         */
-       /* Keep RC high for at least 20ms */
-       adm_enout(eerc, eerc);
-       for (i = 0; i < 20; i ++)
-               udelay(1000);
-       /* Keep RC low for at least 100ms */
-       adm_enout(eerc, 0);
-       for (i = 0; i < 100; i++)
-               udelay(1000);
-       /* Set default configuration */
-       adm_enout((__u8)(eesk | eedi), eesk);
-       /* Keep RC high for at least 30ms */
-       adm_enout(eerc, eerc);
-       for (i = 0; i < 30; i++)
-               udelay(1000);
-       /* Leave RC high and disable GPIO outputs */
-       adm_disout((__u8)(eecs | eesk | eedi));
-
+       if (eerc) {
+               /* Keep RC high for at least 20ms */
+               adm_enout(eerc, eerc);
+               for (i = 0; i < 20; i ++)
+                       udelay(1000);
+               /* Keep RC low for at least 100ms */
+               adm_enout(eerc, 0);
+               for (i = 0; i < 100; i++)
+                       udelay(1000);
+               /* Set default configuration */
+               adm_enout((__u8)(eesk | eedi), eesk);
+               /* Keep RC high for at least 30ms */
+               adm_enout(eerc, eerc);
+               for (i = 0; i < 30; i++)
+                       udelay(1000);
+               /* Leave RC high and disable GPIO outputs */
+               adm_disout((__u8)(eecs | eesk | eedi));
+       }
        /* set up initial configuration for ports */
        for (i = 0; i <= 5; i++) {
                int cfg = 0x8000 | /* Auto MDIX */
@@ -412,7 +453,7 @@ static int handle_reset(char *buf, int nr)
        return 0;
 }
 
-static int handle_registers(char *buf, int nr)
+static int handle_registers(void *driver, char *buf, int nr)
 {
        int i, len = 0;
        
@@ -423,7 +464,7 @@ static int handle_registers(char *buf, int nr)
        return len;
 }
 
-static int handle_counters(char *buf, int nr)
+static int handle_counters(void *driver, char *buf, int nr)
 {
        int i, len = 0;
 
@@ -439,15 +480,36 @@ static int detect_adm()
        int ret = 0;
 
 #if defined(BCMGPIO2) || defined(BCMGPIO)
-#ifdef LINUX_2_4
-       int boardflags = getintvar(NULL, "boardflags");
-#else
-       extern int boardflags;
-#endif
-       if ((boardflags & 0x80) || force)
+       int boardflags = atoi(nvram_get("boardflags"));
+
+       if ((boardflags & 0x80) || force) {
+               ret = 1;
+
+               eecs = getgpiopin("adm_eecs", 2);
+               eesk = getgpiopin("adm_eesk", 3);
+               eedi = getgpiopin("adm_eedi", 4);
+               eerc = getgpiopin("adm_rc", 0);
+
+       } else if ((strcmp(nvram_get("boardtype"), "bcm94710dev") == 0) &&
+                       (strncmp(nvram_get("boardnum"), "42", 2) == 0)) {
+               /* WRT54G v1.1 hack */
+               eecs = 2;
+               eesk = 3;
+               eedi = 5;
+               eerc = 6;
+
                ret = 1;
-       else 
+       } else
                printk("BFL_ENETADM not set in boardflags. Use force=1 to ignore.\n");
+               
+       if (eecs)
+               eecs = (1 << eecs);
+       if (eesk)
+               eesk = (1 << eesk);
+       if (eedi)
+               eedi = (1 << eedi);
+       if (eerc)
+               eerc = (1 << eerc);
 #else
        ret = 1;
 #endif
@@ -465,7 +527,7 @@ static int __init adm_init()
                {NULL, NULL, NULL}
        };
        switch_config port[] = {
-               {"enabled", handle_port_enable_read, handle_port_enable_write},
+               {"enable", handle_port_enable_read, handle_port_enable_write},
                {"media", handle_port_media_read, handle_port_media_write},
                {NULL, NULL, NULL}
        };
@@ -475,17 +537,16 @@ static int __init adm_init()
        };
        switch_driver driver = {
                name: DRIVER_NAME,
+               version: DRIVER_VERSION,
+               interface: "eth0",
                ports: 6,
+               cpuport: 5,
                vlans: 16,
                driver_handlers: cfg,
                port_handlers: port,
                vlan_handlers: vlan,
        };
 
-       eecs = (1 << eecs);
-       eesk = (1 << eesk);
-       eedi = (1 << eedi);
-
        if (!detect_adm())
                return -ENODEV;