packages: clean up the package folder
[openwrt/staging/yousong.git] / package / utils / robocfg / src / robocfg.c
1 /*
2 * Broadcom BCM5325E/536x switch configuration utility
3 *
4 * Copyright (C) 2005 Oleg I. Vdovikin
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 */
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29
30 /* linux stuff */
31 typedef u_int64_t u64;
32 typedef u_int32_t u32;
33 typedef u_int16_t u16;
34 typedef u_int8_t u8;
35
36 #include <linux/if.h>
37 #include <linux/sockios.h>
38 #include <linux/ethtool.h>
39 #include <linux/mii.h>
40
41 #include "etc53xx.h"
42 #define ROBO_PHY_ADDR 0x1E /* robo switch phy address */
43
44 /* MII registers */
45 #define REG_MII_PAGE 0x10 /* MII Page register */
46 #define REG_MII_ADDR 0x11 /* MII Address register */
47 #define REG_MII_DATA0 0x18 /* MII Data register 0 */
48
49 #define REG_MII_PAGE_ENABLE 1
50 #define REG_MII_ADDR_WRITE 1
51 #define REG_MII_ADDR_READ 2
52
53 /* Private et.o ioctls */
54 #define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9)
55 #define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10)
56
57 typedef struct {
58 struct ifreq ifr;
59 int fd;
60 int et; /* use private ioctls */
61 } robo_t;
62
63 static u16 mdio_read(robo_t *robo, u16 phy_id, u8 reg)
64 {
65 if (robo->et) {
66 int args[2] = { reg };
67
68 if (phy_id != ROBO_PHY_ADDR) {
69 fprintf(stderr,
70 "Access to real 'phy' registers unavaliable.\n"
71 "Upgrade kernel driver.\n");
72
73 return 0xffff;
74 }
75
76 robo->ifr.ifr_data = (caddr_t) args;
77 if (ioctl(robo->fd, SIOCGETCPHYRD, (caddr_t)&robo->ifr) < 0) {
78 perror("SIOCGETCPHYRD");
79 exit(1);
80 }
81
82 return args[1];
83 } else {
84 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data;
85 mii->phy_id = phy_id;
86 mii->reg_num = reg;
87 if (ioctl(robo->fd, SIOCGMIIREG, &robo->ifr) < 0) {
88 perror("SIOCGMIIREG");
89 exit(1);
90 }
91 return mii->val_out;
92 }
93 }
94
95 static void mdio_write(robo_t *robo, u16 phy_id, u8 reg, u16 val)
96 {
97 if (robo->et) {
98 int args[2] = { reg, val };
99
100 if (phy_id != ROBO_PHY_ADDR) {
101 fprintf(stderr,
102 "Access to real 'phy' registers unavaliable.\n"
103 "Upgrade kernel driver.\n");
104 return;
105 }
106
107 robo->ifr.ifr_data = (caddr_t) args;
108 if (ioctl(robo->fd, SIOCSETCPHYWR, (caddr_t)&robo->ifr) < 0) {
109 perror("SIOCGETCPHYWR");
110 exit(1);
111 }
112 } else {
113 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data;
114 mii->phy_id = phy_id;
115 mii->reg_num = reg;
116 mii->val_in = val;
117 if (ioctl(robo->fd, SIOCSMIIREG, &robo->ifr) < 0) {
118 perror("SIOCSMIIREG");
119 exit(1);
120 }
121 }
122 }
123
124 static int robo_reg(robo_t *robo, u8 page, u8 reg, u8 op)
125 {
126 int i = 3;
127
128 /* set page number */
129 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_PAGE,
130 (page << 8) | REG_MII_PAGE_ENABLE);
131
132 /* set register address */
133 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_ADDR,
134 (reg << 8) | op);
135
136 /* check if operation completed */
137 while (i--) {
138 if ((mdio_read(robo, ROBO_PHY_ADDR, REG_MII_ADDR) & 3) == 0)
139 return 0;
140 }
141
142 fprintf(stderr, "robo_reg: timeout\n");
143 exit(1);
144
145 return 0;
146 }
147
148 static void robo_read(robo_t *robo, u8 page, u8 reg, u16 *val, int count)
149 {
150 int i;
151
152 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
153
154 for (i = 0; i < count; i++)
155 val[i] = mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i);
156 }
157
158 static u16 robo_read16(robo_t *robo, u8 page, u8 reg)
159 {
160 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
161
162 return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0);
163 }
164
165 static u32 robo_read32(robo_t *robo, u8 page, u8 reg)
166 {
167 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
168
169 return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0) +
170 (mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1) << 16);
171 }
172
173 static void robo_write16(robo_t *robo, u8 page, u8 reg, u16 val16)
174 {
175 /* write data */
176 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val16);
177
178 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
179 }
180
181 static void robo_write32(robo_t *robo, u8 page, u8 reg, u32 val32)
182 {
183 /* write data */
184 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val32 & 65535);
185 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1, val32 >> 16);
186
187 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
188 }
189
190 /* checks that attached switch is 5325E/5350 */
191 static int robo_vlan5350(robo_t *robo)
192 {
193 /* set vlan access id to 15 and read it back */
194 u16 val16 = 15;
195 robo_write16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
196
197 /* 5365 will refuse this as it does not have this reg */
198 return (robo_read16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) == val16);
199 }
200
201 u8 port[6] = { 0, 1, 2, 3, 4, 8 };
202 char ports[6] = { 'W', '4', '3', '2', '1', 'C' };
203 char *rxtx[4] = { "enabled", "rx_disabled", "tx_disabled", "disabled" };
204 char *stp[8] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" };
205
206 struct {
207 char *name;
208 u16 bmcr;
209 } media[5] = { { "auto", BMCR_ANENABLE | BMCR_ANRESTART },
210 { "10HD", 0 }, { "10FD", BMCR_FULLDPLX },
211 { "100HD", BMCR_SPEED100 }, { "100FD", BMCR_SPEED100 | BMCR_FULLDPLX } };
212
213 struct {
214 char *name;
215 u16 value;
216 } mdix[3] = { { "auto", 0x0000 }, { "on", 0x1800 }, { "off", 0x0800 } };
217
218 void usage()
219 {
220 fprintf(stderr, "Broadcom BCM5325E/536x switch configuration utility\n"
221 "Copyright (C) 2005 Oleg I. Vdovikin\n\n"
222 "This program is distributed in the hope that it will be useful,\n"
223 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
224 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
225 "GNU General Public License for more details.\n\n");
226
227 fprintf(stderr, "Usage: robocfg <op> ... <op>\n"
228 "Operations are as below:\n"
229 "\tshow\n"
230 "\tswitch <enable|disable>\n"
231 "\tport <port_number> [state <%s|%s|%s|%s>]\n\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n"
232 "\t\t[media %s|%s|%s|%s|%s] [mdi-x %s|%s|%s]\n"
233 "\tvlan <vlan_number> [ports <ports_list>]\n"
234 "\tvlans <enable|disable|reset>\n\n"
235 "\tports_list should be one argument, space separated, quoted if needed,\n"
236 "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n"
237 "\tport default) or by 'u' to untag packet (other ports default) before \n"
238 "\tbringing it to the port, '*' is ignored\n"
239 "\nSamples:\n"
240 "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n"
241 "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\""
242 " port 0 state enabled stp none switch enable\n"
243 "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n"
244 "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\""
245 " port 0 state enabled stp none switch enable\n",
246 rxtx[0], rxtx[1], rxtx[2], rxtx[3], stp[0], stp[1], stp[2], stp[3], stp[4], stp[5],
247 media[0].name, media[1].name, media[2].name, media[3].name, media[4].name,
248 mdix[0].name, mdix[1].name, mdix[2].name);
249 }
250
251 static robo_t robo;
252 int bcm53xx_probe(const char *dev)
253 {
254 struct ethtool_drvinfo info;
255 unsigned int phyid;
256 int ret;
257
258 fprintf(stderr, "probing %s\n", dev);
259
260 strcpy(robo.ifr.ifr_name, dev);
261 memset(&info, 0, sizeof(info));
262 info.cmd = ETHTOOL_GDRVINFO;
263 robo.ifr.ifr_data = (caddr_t)&info;
264 ret = ioctl(robo.fd, SIOCETHTOOL, (caddr_t)&robo.ifr);
265 if (ret < 0) {
266 perror("SIOCETHTOOL");
267 return ret;
268 }
269
270 if ( strcmp(info.driver, "et0") &&
271 strcmp(info.driver, "b44") &&
272 strcmp(info.driver, "bcm63xx_enet") ) {
273 fprintf(stderr, "driver not supported %s\n", info.driver);
274 return -ENOSYS;
275 }
276
277 /* try access using MII ioctls - get phy address */
278 robo.et = 0;
279 if (ioctl(robo.fd, SIOCGMIIPHY, &robo.ifr) < 0)
280 robo.et = 1;
281
282 if (robo.et) {
283 unsigned int args[2] = { 2 };
284
285 robo.ifr.ifr_data = (caddr_t) args;
286 ret = ioctl(robo.fd, SIOCGETCPHYRD, (caddr_t)&robo.ifr);
287 if (ret < 0) {
288 perror("SIOCGETCPHYRD");
289 return ret;
290 }
291 phyid = args[1] & 0xffff;
292
293 args[0] = 3;
294 robo.ifr.ifr_data = (caddr_t) args;
295 ret = ioctl(robo.fd, SIOCGETCPHYRD, (caddr_t)&robo.ifr);
296 if (ret < 0) {
297 perror("SIOCGETCPHYRD");
298 return ret;
299 }
300 phyid |= args[1] << 16;
301 } else {
302 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo.ifr.ifr_data;
303 mii->phy_id = ROBO_PHY_ADDR;
304 mii->reg_num = 2;
305 ret = ioctl(robo.fd, SIOCGMIIREG, &robo.ifr);
306 if (ret < 0) {
307 perror("SIOCGMIIREG");
308 return ret;
309 }
310 phyid = mii->val_out & 0xffff;
311
312 mii->phy_id = ROBO_PHY_ADDR;
313 mii->reg_num = 3;
314 ret = ioctl(robo.fd, SIOCGMIIREG, &robo.ifr);
315 if (ret < 0) {
316 perror("SIOCGMIIREG");
317 return ret;
318 }
319 phyid |= mii->val_out << 16;
320 }
321
322 if (phyid == 0xffffffff || phyid == 0x55210022) {
323 perror("phyid");
324 return -EIO;
325 }
326
327 return 0;
328 }
329
330 int
331 main(int argc, char *argv[])
332 {
333 u16 val16;
334 u16 mac[3];
335 int i = 0, j;
336 int robo5350 = 0;
337 u32 phyid;
338
339 if ((robo.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
340 perror("socket");
341 exit(1);
342 }
343
344 if (bcm53xx_probe("eth1")) {
345 if (bcm53xx_probe("eth0")) {
346 perror("bcm53xx_probe");
347 exit(1);
348 }
349 }
350
351 robo5350 = robo_vlan5350(&robo);
352
353 for (i = 1; i < argc;) {
354 if (strcasecmp(argv[i], "port") == 0 && (i + 1) < argc)
355 {
356 int index = atoi(argv[++i]);
357 /* read port specs */
358 while (++i < argc) {
359 if (strcasecmp(argv[i], "state") == 0 && ++i < argc) {
360 for (j = 0; j < 4 && strcasecmp(argv[i], rxtx[j]); j++);
361 if (j < 4) {
362 /* change state */
363 robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
364 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(3 << 0)) | (j << 0));
365 } else {
366 fprintf(stderr, "Invalid state '%s'.\n", argv[i]);
367 exit(1);
368 }
369 } else
370 if (strcasecmp(argv[i], "stp") == 0 && ++i < argc) {
371 for (j = 0; j < 8 && strcasecmp(argv[i], stp[j]); j++);
372 if (j < 8) {
373 /* change stp */
374 robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
375 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(7 << 5)) | (j << 5));
376 } else {
377 fprintf(stderr, "Invalid stp '%s'.\n", argv[i]);
378 exit(1);
379 }
380 } else
381 if (strcasecmp(argv[i], "media") == 0 && ++i < argc) {
382 for (j = 0; j < 5 && strcasecmp(argv[i], media[j].name); j++);
383 if (j < 5) {
384 mdio_write(&robo, port[index], MII_BMCR, media[j].bmcr);
385 } else {
386 fprintf(stderr, "Invalid media '%s'.\n", argv[i]);
387 exit(1);
388 }
389 } else
390 if (strcasecmp(argv[i], "mdi-x") == 0 && ++i < argc) {
391 for (j = 0; j < 3 && strcasecmp(argv[i], mdix[j].name); j++);
392 if (j < 3) {
393 mdio_write(&robo, port[index], 0x1c, mdix[j].value |
394 (mdio_read(&robo, port[index], 0x1c) & ~0x1800));
395 } else {
396 fprintf(stderr, "Invalid mdi-x '%s'.\n", argv[i]);
397 exit(1);
398 }
399 } else
400 if (strcasecmp(argv[i], "tag") == 0 && ++i < argc) {
401 j = atoi(argv[i]);
402 /* change vlan tag */
403 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (index << 1), j);
404 } else break;
405 }
406 } else
407 if (strcasecmp(argv[i], "vlan") == 0 && (i + 1) < argc)
408 {
409 int index = atoi(argv[++i]);
410 while (++i < argc) {
411 if (strcasecmp(argv[i], "ports") == 0 && ++i < argc) {
412 char *ports = argv[i];
413 int untag = 0;
414 int member = 0;
415
416 while (*ports >= '0' && *ports <= '9') {
417 j = *ports++ - '0';
418 member |= 1 << j;
419
420 /* untag if needed, CPU port requires special handling */
421 if (*ports == 'u' || (j != 5 && (*ports == ' ' || *ports == 0)))
422 {
423 untag |= 1 << j;
424 if (*ports) ports++;
425 /* change default vlan tag */
426 robo_write16(&robo, ROBO_VLAN_PAGE,
427 ROBO_VLAN_PORT0_DEF_TAG + (j << 1), index);
428 } else
429 if (*ports == '*' || *ports == 't' || *ports == ' ') ports++;
430 else break;
431
432 while (*ports == ' ') ports++;
433 }
434
435 if (*ports) {
436 fprintf(stderr, "Invalid ports '%s'.\n", argv[i]);
437 exit(1);
438 } else {
439 /* write config now */
440 val16 = (index) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
441 if (robo5350) {
442 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350,
443 (1 << 20) /* valid */ | (untag << 6) | member);
444 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
445 } else {
446 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE,
447 (1 << 14) /* valid */ | (untag << 7) | member);
448 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
449 }
450 }
451 } else break;
452 }
453 } else
454 if (strcasecmp(argv[i], "switch") == 0 && (i + 1) < argc)
455 {
456 /* enable/disable switching */
457 robo_write16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE,
458 (robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & ~2) |
459 (*argv[++i] == 'e' ? 2 : 0));
460 i++;
461 } else
462 if (strcasecmp(argv[i], "vlans") == 0 && (i + 1) < argc)
463 {
464 while (++i < argc) {
465 if (strcasecmp(argv[i], "reset") == 0) {
466 /* reset vlan validity bit */
467 for (j = 0; j <= (robo5350 ? VLAN_ID_MAX5350 : VLAN_ID_MAX); j++)
468 {
469 /* write config now */
470 val16 = (j) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
471 if (robo5350) {
472 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, 0);
473 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
474 } else {
475 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 0);
476 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
477 }
478 }
479 } else
480 if (strcasecmp(argv[i], "enable") == 0 || strcasecmp(argv[i], "disable") == 0)
481 {
482 int disable = (*argv[i] == 'd') || (*argv[i] == 'D');
483 /* enable/disable vlans */
484 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 :
485 (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
486
487 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 :
488 (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
489
490 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 :
491 (1 << 6) /* drop invalid VID frames */);
492
493 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 :
494 (1 << 3) /* drop miss V table frames */);
495
496 } else break;
497 }
498 } else
499 if (strcasecmp(argv[i], "show") == 0)
500 {
501 break;
502 } else {
503 fprintf(stderr, "Invalid option %s\n", argv[i]);
504 usage();
505 exit(1);
506 }
507 }
508
509 if (i == argc) {
510 if (argc == 1) usage();
511 return 0;
512 }
513
514 /* show config */
515
516 printf("Switch: %sabled\n", robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & 2 ? "en" : "dis");
517
518 for (i = 0; i < 6; i++) {
519 printf(robo_read16(&robo, ROBO_STAT_PAGE, ROBO_LINK_STAT_SUMMARY) & (1 << port[i]) ?
520 "Port %d(%c): %s%s " : "Port %d(%c): DOWN ", i, ports[i],
521 robo_read16(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) & (1 << port[i]) ? "100" : " 10",
522 robo_read16(&robo, ROBO_STAT_PAGE, ROBO_DUPLEX_STAT_SUMMARY) & (1 << port[i]) ? "FD" : "HD");
523
524 val16 = robo_read16(&robo, ROBO_CTRL_PAGE, port[i]);
525
526 printf("%s stp: %s vlan: %d ", rxtx[val16 & 3], stp[(val16 >> 5) & 7],
527 robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (i << 1)));
528
529 robo_read(&robo, ROBO_STAT_PAGE, ROBO_LSA_PORT0 + port[i] * 6, mac, 3);
530
531 printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
532 mac[2] >> 8, mac[2] & 255, mac[1] >> 8, mac[1] & 255, mac[0] >> 8, mac[0] & 255);
533 }
534
535 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0);
536
537 printf("VLANs: %s %sabled%s%s\n",
538 robo5350 ? "BCM5325/535x" : "BCM536x",
539 (val16 & (1 << 7)) ? "en" : "dis",
540 (val16 & (1 << 6)) ? " mac_check" : "",
541 (val16 & (1 << 5)) ? " mac_hash" : "");
542
543 /* scan VLANs */
544 for (i = 0; i <= (robo5350 ? VLAN_ID_MAX5350 : VLAN_ID_MAX); i++) {
545 /* issue read */
546 val16 = (i) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
547
548 if (robo5350) {
549 u32 val32;
550 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
551 /* actual read */
552 val32 = robo_read32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
553 if ((val32 & (1 << 20)) /* valid */) {
554 printf("vlan%d:", i);
555 for (j = 0; j < 6; j++) {
556 if (val32 & (1 << j)) {
557 printf(" %d%s", j, (val32 & (1 << (j + 6))) ?
558 (j == 5 ? "u" : "") : "t");
559 }
560 }
561 printf("\n");
562 }
563 } else {
564 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
565 /* actual read */
566 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
567 if ((val16 & (1 << 14)) /* valid */) {
568 printf("vlan%d:", i);
569 for (j = 0; j < 6; j++) {
570 if (val16 & (1 << j)) {
571 printf(" %d%s", j, (val16 & (1 << (j + 7))) ?
572 (j == 5 ? "u" : "") : "t");
573 }
574 }
575 printf("\n");
576 }
577 }
578 }
579
580 return (0);
581 }