/* 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;
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]);
}
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]);
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;
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]);
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);
return 0;
}
-static int handle_reset(char *buf, int nr)
+static int handle_reset(void *driver, char *buf, int nr)
{
int i;
return 0;
}
-static int handle_registers(char *buf, int nr)
+static int handle_registers(void *driver, char *buf, int nr)
{
int i, len = 0;
return len;
}
-static int handle_counters(char *buf, int nr)
+static int handle_counters(void *driver, char *buf, int nr)
{
int i, len = 0;
#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;
}
};
switch_driver driver = {
name: DRIVER_NAME,
+ interface: "eth0",
ports: 6,
+ cpuport: 5,
vlans: 16,
driver_handlers: cfg,
port_handlers: port,
struct list_head list;
struct proc_dir_entry *parent;
int nr;
+ void *driver;
switch_config handler;
} switch_proc_handler;
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);
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);
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;
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;
}
}
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;
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);
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--;
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);
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;
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;
return 0;
}
-static int isspace(char c) {
+static inline int isspace(char c) {
switch(c) {
case ' ':
case 0x09:
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;
}
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);
#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);
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();
}
-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;
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;
}
for (device[3] = '0'; (device[3] <= '3') && notfound; device[3]++) {
notfound = robo_probe(device);
}
+ device[3]--;
if (notfound)
return -ENODEV;
};
switch_driver driver = {
name: DRIVER_NAME,
+ interface: device,
+ cpuport: max_ports - 1,
ports: max_ports,
vlans: max_vlans,
driver_handlers: NULL,