X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/fa8fb4e7c3be746703fee0dd34285f462ba104ec..013e04a018a55287faff4ec9f5fe3305525e03cd:/openwrt/target/linux/package/switch/src/switch-core.c diff --git a/openwrt/target/linux/package/switch/src/switch-core.c b/openwrt/target/linux/package/switch/src/switch-core.c index 8b4419b29..821664637 100644 --- a/openwrt/target/linux/package/switch/src/switch-core.c +++ b/openwrt/target/linux/package/switch/src/switch-core.c @@ -18,6 +18,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id: $ + * + * Basic doc of driver's /proc interface: + * /proc/switch// + * registers: read-only + * counters: read-only + * reset: write causes hardware reset + * enable_vlan: "0", "1" + * port// + * enabled: "0", "1" + * media: "AUTO", "100FD", "100HD", "10FD", "10HD" + * vlan// + * ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*") */ #include @@ -37,6 +49,7 @@ typedef struct { struct list_head list; struct proc_dir_entry *parent; int nr; + void *driver; switch_config handler; } switch_proc_handler; @@ -47,7 +60,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 +68,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 +92,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 +134,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,28 +143,50 @@ 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 int handle_driver_name(void *driver, char *buf, int nr) { - switch_proc_handler *tmp; - int i, mode; + char *name = ((switch_driver *) driver)->name; + return sprintf(buf, "%s\n", name); +} + +static int handle_driver_version(void *driver, char *buf, int nr) +{ + char *version = ((switch_driver *) driver)->version; + strcpy(buf, version); + return sprintf(buf, "%s\n", version); +} + +static void add_handler(switch_driver *driver, switch_config *handler, struct proc_dir_entry *parent, int nr) +{ + switch_priv *priv = (switch_priv *) driver->data; struct proc_dir_entry *p; + int mode; + + switch_proc_handler *tmp; + tmp = (switch_proc_handler *) kmalloc(sizeof(switch_proc_handler), GFP_KERNEL); + INIT_LIST_HEAD(&tmp->list); + tmp->parent = parent; + tmp->nr = nr; + tmp->driver = driver; + memcpy(&tmp->handler, handler, sizeof(switch_config)); + list_add(&tmp->list, &priv->data.list); + + mode = 0; + if (handler->read != NULL) mode |= S_IRUSR; + if (handler->write != NULL) mode |= S_IWUSR; + + if ((p = create_proc_entry(handler->name, mode, parent)) != NULL) { + p->data = (void *) tmp; + p->proc_fops = &switch_proc_fops; + } +} + +static inline void add_handlers(switch_driver *driver, switch_config *handlers, struct proc_dir_entry *parent, int nr) +{ + int i; for (i = 0; handlers[i].name != NULL; i++) { - tmp = kmalloc(sizeof(switch_proc_handler), GFP_KERNEL); - INIT_LIST_HEAD(&tmp->list); - tmp->parent = parent; - tmp->nr = nr; - memcpy(&tmp->handler, &(handlers[i]), sizeof(switch_config)); - list_add(&tmp->list, &priv->data.list); - - mode = 0; - if (handlers[i].read != NULL) mode |= S_IRUSR; - if (handlers[i].write != NULL) mode |= S_IWUSR; - - if ((p = create_proc_entry(handlers[i].name, mode, parent)) != NULL) { - p->data = (void *) tmp; - p->proc_fops = &switch_proc_fops; - } + add_handler(driver, &(handlers[i]), parent, nr); } } @@ -192,7 +226,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--; @@ -200,6 +234,12 @@ static void do_unregister(switch_driver *driver) kfree(priv); } +switch_config global_driver_handlers[] = { + {"driver", handle_driver_name, NULL}, + {"version", handle_driver_version, NULL}, + {NULL, NULL, NULL} +}; + static int do_register(switch_driver *driver) { switch_priv *priv; @@ -213,10 +253,11 @@ 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); - if (driver->driver_handlers != NULL) - add_handlers(priv, driver->driver_handlers, priv->driver_dir, 0); + priv->driver_dir = proc_mkdir(driver->interface, switch_root); + if (driver->driver_handlers != NULL) { + add_handlers(driver, driver->driver_handlers, priv->driver_dir, 0); + add_handlers(driver, global_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 +265,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 +275,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 +283,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 +339,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; - - if (!untag) - tag |= 1 << j; + j *= 10; + j += *buf++ - '0'; + + 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 +404,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); @@ -393,7 +457,7 @@ static int __init switch_init() static void __exit switch_exit() { - remove_proc_entry("vlan", NULL); + remove_proc_entry("switch", NULL); } MODULE_AUTHOR("Felix Fietkau ");