diff --git a/openwrt/target/linux/package/switch/src/switch-adm.c b/openwrt/target/linux/package/switch/src/switch-adm.c index 0b70a694c1..6ad98447b3 100644 --- a/openwrt/target/linux/package/switch/src/switch-adm.c +++ b/openwrt/target/linux/package/switch/src/switch-adm.c @@ -240,7 +240,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; @@ -261,30 +261,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 +297,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 +316,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 +333,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 +354,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 +373,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; @@ -412,7 +415,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 +426,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; @@ -451,6 +454,13 @@ static int detect_adm() #else ret = 1; #endif + if (ret == 1) { + int i = adm_rreg(0, 0); + if ((i == 0) || (i == 0xffff)) { + printk("No ADM6996 chip detected.\n"); + ret = 0; + } + } return ret; } @@ -475,7 +485,9 @@ static int __init adm_init() }; switch_driver driver = { name: DRIVER_NAME, + interface: "eth0", ports: 6, + cpuport: 5, vlans: 16, driver_handlers: cfg, port_handlers: port, diff --git a/openwrt/target/linux/package/switch/src/switch-core.c b/openwrt/target/linux/package/switch/src/switch-core.c index 8b4419b298..c0e5cc9eaa 100644 --- a/openwrt/target/linux/package/switch/src/switch-core.c +++ b/openwrt/target/linux/package/switch/src/switch-core.c @@ -37,6 +37,7 @@ typedef struct { struct list_head list; struct proc_dir_entry *parent; int nr; + void *driver; switch_config handler; } switch_proc_handler; @@ -47,7 +48,6 @@ typedef struct { int nr; } switch_priv; - static ssize_t switch_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); static ssize_t switch_proc_write(struct file *file, const char *buf, size_t count, void *data); @@ -56,7 +56,7 @@ static struct file_operations switch_proc_fops = { write: switch_proc_write }; -static char *strdup(char *str) +static inline char *strdup(char *str) { char *new = kmalloc(strlen(str) + 1, GFP_KERNEL); strcpy(new, str); @@ -80,7 +80,7 @@ static ssize_t switch_proc_read(struct file *file, char *buf, size_t count, loff if (dent->data != NULL) { switch_proc_handler *handler = (switch_proc_handler *) dent->data; if (handler->handler.read != NULL) - len += handler->handler.read(page + len, handler->nr); + len += handler->handler.read(handler->driver, page + len, handler->nr); } len += 1; @@ -122,7 +122,7 @@ static ssize_t switch_proc_write(struct file *file, const char *buf, size_t coun if (dent->data != NULL) { switch_proc_handler *handler = (switch_proc_handler *) dent->data; if (handler->handler.write != NULL) { - if ((ret = handler->handler.write(page, handler->nr)) >= 0) + if ((ret = handler->handler.write(handler->driver, page, handler->nr)) >= 0) ret = count; } } @@ -131,8 +131,9 @@ static ssize_t switch_proc_write(struct file *file, const char *buf, size_t coun return ret; } -static void add_handlers(switch_priv *priv, switch_config *handlers, struct proc_dir_entry *parent, int nr) +static void add_handlers(switch_driver *driver, switch_config *handlers, struct proc_dir_entry *parent, int nr) { + switch_priv *priv = (switch_priv *) driver->data; switch_proc_handler *tmp; int i, mode; struct proc_dir_entry *p; @@ -142,6 +143,7 @@ static void add_handlers(switch_priv *priv, switch_config *handlers, struct proc INIT_LIST_HEAD(&tmp->list); tmp->parent = parent; tmp->nr = nr; + tmp->driver = driver; memcpy(&tmp->handler, &(handlers[i]), sizeof(switch_config)); list_add(&tmp->list, &priv->data.list); @@ -192,7 +194,7 @@ static void do_unregister(switch_driver *driver) kfree(priv->vlans); remove_proc_entry("vlan", priv->driver_dir); - remove_proc_entry(driver->name, switch_root); + remove_proc_entry(driver->interface, switch_root); if (priv->nr == (drv_num - 1)) drv_num--; @@ -213,10 +215,9 @@ static int do_register(switch_driver *driver) INIT_LIST_HEAD(&priv->data.list); priv->nr = drv_num++; - sprintf(buf, "%d", priv->nr); - priv->driver_dir = proc_mkdir(buf, switch_root); + priv->driver_dir = proc_mkdir(driver->interface, switch_root); if (driver->driver_handlers != NULL) - add_handlers(priv, driver->driver_handlers, priv->driver_dir, 0); + add_handlers(driver, driver->driver_handlers, priv->driver_dir, 0); priv->port_dir = proc_mkdir("port", priv->driver_dir); priv->ports = kmalloc((driver->ports + 1) * sizeof(struct proc_dir_entry *), GFP_KERNEL); @@ -224,7 +225,7 @@ static int do_register(switch_driver *driver) sprintf(buf, "%d", i); priv->ports[i] = proc_mkdir(buf, priv->port_dir); if (driver->port_handlers != NULL) - add_handlers(priv, driver->port_handlers, priv->ports[i], i); + add_handlers(driver, driver->port_handlers, priv->ports[i], i); } priv->ports[i] = NULL; @@ -234,7 +235,7 @@ static int do_register(switch_driver *driver) sprintf(buf, "%d", i); priv->vlans[i] = proc_mkdir(buf, priv->vlan_dir); if (driver->vlan_handlers != NULL) - add_handlers(priv, driver->vlan_handlers, priv->vlans[i], i); + add_handlers(driver, driver->vlan_handlers, priv->vlans[i], i); } priv->vlans[i] = NULL; @@ -242,7 +243,7 @@ static int do_register(switch_driver *driver) return 0; } -static int isspace(char c) { +static inline int isspace(char c) { switch(c) { case ' ': case 0x09: @@ -298,39 +299,57 @@ int switch_print_media(char *buf, int media) return len; } -int switch_parse_vlan(char *buf) +switch_vlan_config *switch_parse_vlan(switch_driver *driver, char *buf) { - char vlan = 0, tag = 0, pvid_port = 0; - int untag, j; + switch_vlan_config *c; + int j, u, p, s; + + c = kmalloc(sizeof(switch_vlan_config), GFP_KERNEL); + memset(c, 0, sizeof(switch_vlan_config)); while (isspace(*buf)) buf++; - + j = 0; while (*buf >= '0' && *buf <= '9') { - j = *buf++ - '0'; - vlan |= 1 << j; - - untag = 0; - /* untag if needed, CPU port requires special handling */ - if (*buf == 'u' || (j != 5 && (isspace(*buf) || *buf == 0))) { - untag = 1; - if (*buf) buf++; - } else if (*buf == '*') { - pvid_port |= (1 << j); - buf++; - } else if (*buf == 't' || isspace(*buf)) { - buf++; - } else break; + j *= 10; + j += *buf++ - '0'; - if (!untag) - tag |= 1 << j; + u = ((j == driver->cpuport) ? 0 : 1); + p = 0; + s = !(*buf >= '0' && *buf <= '9'); + + if (s) { + while (s && !isspace(*buf) && (*buf != 0)) { + switch(*buf) { + case 'u': + u = 1; + break; + case 't': + u = 0; + break; + case '*': + p = 1; + break; + } + buf++; + } + c->port |= (1 << j); + if (u) + c->untag |= (1 << j); + if (p) + c->pvid |= (1 << j); + + j = 0; + } while (isspace(*buf)) buf++; } - - if (*buf) - return -1; + if (*buf != 0) return NULL; - return (pvid_port << 16) | (tag << 8) | vlan; + c->port &= (1 << driver->ports) - 1; + c->untag &= (1 << driver->ports) - 1; + c->pvid &= (1 << driver->ports) - 1; + + return c; } @@ -345,11 +364,16 @@ int switch_register_driver(switch_driver *driver) printk("Switch driver '%s' already exists in the kernel\n", driver->name); return -EINVAL; } + if (strcmp(list_entry(pos, switch_driver, list)->interface, driver->interface) == 0) { + printk("There is already a switch registered on the device '%s'\n", driver->interface); + return -EINVAL; + } } new = kmalloc(sizeof(switch_driver), GFP_KERNEL); memcpy(new, driver, sizeof(switch_driver)); new->name = strdup(driver->name); + new->interface = strdup(driver->interface); if ((ret = do_register(new)) < 0) { kfree(new->name); diff --git a/openwrt/target/linux/package/switch/src/switch-core.h b/openwrt/target/linux/package/switch/src/switch-core.h index 9927e85192..bdf0ae1f89 100644 --- a/openwrt/target/linux/package/switch/src/switch-core.h +++ b/openwrt/target/linux/package/switch/src/switch-core.h @@ -17,27 +17,33 @@ #define LINUX_2_4 #endif -typedef int (*switch_handler)(char *buf, int nr); +typedef int (*switch_handler)(void *driver, char *buf, int nr); typedef struct { char *name; switch_handler read, write; } switch_config; - typedef struct { struct list_head list; char *name; + char *interface; + int cpuport; int ports; int vlans; switch_config *driver_handlers, *port_handlers, *vlan_handlers; void *data; + void *priv; } switch_driver; +typedef struct { + u32 port, untag, pvid; +} switch_vlan_config; + extern int switch_register_driver(switch_driver *driver); extern void switch_unregister_driver(char *name); -extern int switch_parse_vlan(char *buf); +extern switch_vlan_config *switch_parse_vlan(switch_driver *driver, char *buf); extern int switch_parse_media(char *buf); extern int switch_print_media(char *buf, int media); diff --git a/openwrt/target/linux/package/switch/src/switch-robo.c b/openwrt/target/linux/package/switch/src/switch-robo.c index d596dc6536..57978bce06 100644 --- a/openwrt/target/linux/package/switch/src/switch-robo.c +++ b/openwrt/target/linux/package/switch/src/switch-robo.c @@ -56,18 +56,6 @@ static int max_vlans, max_ports; static struct ifreq ifr; static struct net_device *dev; -static int isspace(char c) { - switch(c) { - case ' ': - case 0x09: - case 0x0a: - case 0x0d: - return 1; - default: - return 0; - } -} - static int do_ioctl(int cmd, void *buf) { mm_segment_t old_fs = get_fs(); @@ -297,7 +285,7 @@ static int robo_probe(char *devname) } -static int handle_vlan_port_read(char *buf, int nr) +static int handle_vlan_port_read(void *driver, char *buf, int nr) { __u16 val16; int len = 0; @@ -337,45 +325,34 @@ 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 untag = 0; - int member = 0; + switch_driver *d = (switch_driver *) driver; + switch_vlan_config *c = switch_parse_vlan(d, buf); int j; __u16 val16; - while (*buf >= '0' && *buf <= '9') { - j = *buf++ - '0'; - member |= 1 << j; - - /* untag if needed, CPU port requires special handling */ - if (*buf == 'u' || (j != 5 && (isspace(*buf) || *buf == 0))) { - untag |= 1 << j; - if (*buf) buf++; + if (c == NULL) + return -EINVAL; + + for (j = 0; j < d->ports; j++) { + if ((c->untag | c->pvid) & (1 << j)) /* change default vlan tag */ robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (j << 1), nr); - } else if (*buf == '*' || *buf == 't' || isspace(*buf)) { - buf++; - } else break; - - while (isspace(*buf)) buf++; } - - if (*buf) { - return -1; + + /* write config now */ + val16 = (nr) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */; + if (is_5350) { + robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, + (1 << 20) /* valid */ | (c->untag << 6) | c->port); + robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); } else { - /* write config now */ - val16 = (nr) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */; - if (is_5350) { - robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, - (1 << 20) /* valid */ | (untag << 6) | member); - robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); - } else { - robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, - (1 << 14) /* valid */ | (untag << 7) | member); - robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16); - } + robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, + (1 << 14) /* valid */ | (c->untag << 7) | c->port); + robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16); } + return 0; } @@ -387,6 +364,7 @@ static int __init robo_init() for (device[3] = '0'; (device[3] <= '3') && notfound; device[3]++) { notfound = robo_probe(device); } + device[3]--; if (notfound) return -ENODEV; @@ -397,6 +375,8 @@ static int __init robo_init() }; switch_driver driver = { name: DRIVER_NAME, + interface: device, + cpuport: max_ports - 1, ports: max_ports, vlans: max_vlans, driver_handlers: NULL,