switch-robo.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * Broadcom BCM5325E/536x switch configuration module
  3. *
  4. * Copyright (C) 2005 Felix Fietkau <[email protected]>
  5. * Copyright (C) 2008 Michael Buesch <[email protected]>
  6. * Based on 'robocfg' by Oleg I. Vdovikin
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21. * 02110-1301, USA.
  22. */
  23. #include <linux/autoconf.h>
  24. #include <linux/module.h>
  25. #include <linux/init.h>
  26. #include <linux/if.h>
  27. #include <linux/if_arp.h>
  28. #include <linux/sockios.h>
  29. #include <linux/ethtool.h>
  30. #include <linux/mii.h>
  31. #include <linux/delay.h>
  32. #include <asm/uaccess.h>
  33. #include "switch-core.h"
  34. #include "etc53xx.h"
  35. #define DRIVER_NAME "bcm53xx"
  36. #define DRIVER_VERSION "0.02"
  37. #define PFX "roboswitch: "
  38. #define ROBO_PHY_ADDR 0x1E /* robo switch phy address */
  39. #define ROBO_PHY_ADDR_TG3 0x01 /* Tigon3 PHY address */
  40. #define ROBO_PHY_ADDR_BCM63XX 0x00 /* BCM63XX PHY address */
  41. /* MII registers */
  42. #define REG_MII_PAGE 0x10 /* MII Page register */
  43. #define REG_MII_ADDR 0x11 /* MII Address register */
  44. #define REG_MII_DATA0 0x18 /* MII Data register 0 */
  45. #define REG_MII_PAGE_ENABLE 1
  46. #define REG_MII_ADDR_WRITE 1
  47. #define REG_MII_ADDR_READ 2
  48. /* Robo device ID register (in ROBO_MGMT_PAGE) */
  49. #define ROBO_DEVICE_ID 0x30
  50. #define ROBO_DEVICE_ID_5325 0x25 /* Faked */
  51. #define ROBO_DEVICE_ID_5395 0x95
  52. #define ROBO_DEVICE_ID_5397 0x97
  53. #define ROBO_DEVICE_ID_5398 0x98
  54. /* Private et.o ioctls */
  55. #define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9)
  56. #define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10)
  57. /* linux 2.4 does not have 'bool' */
  58. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
  59. #define bool int
  60. #endif
  61. /* Only available on brcm-2.4/brcm47xx */
  62. #ifdef BROADCOM
  63. extern char *nvram_get(const char *name);
  64. #define getvar(str) (nvram_get(str)?:"")
  65. #else
  66. #define getvar(str) ""
  67. #endif
  68. /* Data structure for a Roboswitch device. */
  69. struct robo_switch {
  70. char *device; /* The device name string (ethX) */
  71. u16 devid; /* ROBO_DEVICE_ID_53xx */
  72. bool use_et;
  73. bool is_5350;
  74. u8 phy_addr; /* PHY address of the device */
  75. struct ifreq ifr;
  76. struct net_device *dev;
  77. unsigned char port[6];
  78. };
  79. /* Currently we can only have one device in the system. */
  80. static struct robo_switch robo;
  81. static int do_ioctl(int cmd, void *buf)
  82. {
  83. mm_segment_t old_fs = get_fs();
  84. int ret;
  85. if (buf != NULL)
  86. robo.ifr.ifr_data = (caddr_t) buf;
  87. set_fs(KERNEL_DS);
  88. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
  89. ret = robo.dev->netdev_ops->ndo_do_ioctl(robo.dev, &robo.ifr, cmd);
  90. #else
  91. ret = robo.dev->do_ioctl(robo.dev, &robo.ifr, cmd);
  92. #endif
  93. set_fs(old_fs);
  94. return ret;
  95. }
  96. static u16 mdio_read(__u16 phy_id, __u8 reg)
  97. {
  98. if (robo.use_et) {
  99. int args[2] = { reg };
  100. if (phy_id != robo.phy_addr) {
  101. printk(KERN_ERR PFX
  102. "Access to real 'phy' registers unavaliable.\n"
  103. "Upgrade kernel driver.\n");
  104. return 0xffff;
  105. }
  106. if (do_ioctl(SIOCGETCPHYRD, &args) < 0) {
  107. printk(KERN_ERR PFX
  108. "[%s:%d] SIOCGETCPHYRD failed!\n", __FILE__, __LINE__);
  109. return 0xffff;
  110. }
  111. return args[1];
  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. if (do_ioctl(SIOCGMIIREG, NULL) < 0) {
  117. printk(KERN_ERR PFX
  118. "[%s:%d] SIOCGMIIREG failed!\n", __FILE__, __LINE__);
  119. return 0xffff;
  120. }
  121. return mii->val_out;
  122. }
  123. }
  124. static void mdio_write(__u16 phy_id, __u8 reg, __u16 val)
  125. {
  126. if (robo.use_et) {
  127. int args[2] = { reg, val };
  128. if (phy_id != robo.phy_addr) {
  129. printk(KERN_ERR PFX
  130. "Access to real 'phy' registers unavaliable.\n"
  131. "Upgrade kernel driver.\n");
  132. return;
  133. }
  134. if (do_ioctl(SIOCSETCPHYWR, args) < 0) {
  135. printk(KERN_ERR PFX
  136. "[%s:%d] SIOCGETCPHYWR failed!\n", __FILE__, __LINE__);
  137. return;
  138. }
  139. } else {
  140. struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo.ifr.ifr_data;
  141. mii->phy_id = phy_id;
  142. mii->reg_num = reg;
  143. mii->val_in = val;
  144. if (do_ioctl(SIOCSMIIREG, NULL) < 0) {
  145. printk(KERN_ERR PFX
  146. "[%s:%d] SIOCSMIIREG failed!\n", __FILE__, __LINE__);
  147. return;
  148. }
  149. }
  150. }
  151. static int robo_reg(__u8 page, __u8 reg, __u8 op)
  152. {
  153. int i = 3;
  154. /* set page number */
  155. mdio_write(robo.phy_addr, REG_MII_PAGE,
  156. (page << 8) | REG_MII_PAGE_ENABLE);
  157. /* set register address */
  158. mdio_write(robo.phy_addr, REG_MII_ADDR,
  159. (reg << 8) | op);
  160. /* check if operation completed */
  161. while (i--) {
  162. if ((mdio_read(robo.phy_addr, REG_MII_ADDR) & 3) == 0)
  163. return 0;
  164. }
  165. printk(KERN_ERR PFX "[%s:%d] timeout in robo_reg!\n", __FILE__, __LINE__);
  166. return 0;
  167. }
  168. /*
  169. static void robo_read(__u8 page, __u8 reg, __u16 *val, int count)
  170. {
  171. int i;
  172. robo_reg(page, reg, REG_MII_ADDR_READ);
  173. for (i = 0; i < count; i++)
  174. val[i] = mdio_read(robo.phy_addr, REG_MII_DATA0 + i);
  175. }
  176. */
  177. static __u16 robo_read16(__u8 page, __u8 reg)
  178. {
  179. robo_reg(page, reg, REG_MII_ADDR_READ);
  180. return mdio_read(robo.phy_addr, REG_MII_DATA0);
  181. }
  182. static __u32 robo_read32(__u8 page, __u8 reg)
  183. {
  184. robo_reg(page, reg, REG_MII_ADDR_READ);
  185. return mdio_read(robo.phy_addr, REG_MII_DATA0) +
  186. (mdio_read(robo.phy_addr, REG_MII_DATA0 + 1) << 16);
  187. }
  188. static void robo_write16(__u8 page, __u8 reg, __u16 val16)
  189. {
  190. /* write data */
  191. mdio_write(robo.phy_addr, REG_MII_DATA0, val16);
  192. robo_reg(page, reg, REG_MII_ADDR_WRITE);
  193. }
  194. static void robo_write32(__u8 page, __u8 reg, __u32 val32)
  195. {
  196. /* write data */
  197. mdio_write(robo.phy_addr, REG_MII_DATA0, val32 & 65535);
  198. mdio_write(robo.phy_addr, REG_MII_DATA0 + 1, val32 >> 16);
  199. robo_reg(page, reg, REG_MII_ADDR_WRITE);
  200. }
  201. /* checks that attached switch is 5325E/5350 */
  202. static int robo_vlan5350(void)
  203. {
  204. /* set vlan access id to 15 and read it back */
  205. __u16 val16 = 15;
  206. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
  207. /* 5365 will refuse this as it does not have this reg */
  208. return (robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) == val16);
  209. }
  210. static int robo_switch_enable(void)
  211. {
  212. unsigned int i, last_port;
  213. u16 val;
  214. val = robo_read16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE);
  215. if (!(val & (1 << 1))) {
  216. /* Unmanaged mode */
  217. val &= ~(1 << 0);
  218. /* With forwarding */
  219. val |= (1 << 1);
  220. robo_write16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE, val);
  221. val = robo_read16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE);
  222. if (!(val & (1 << 1))) {
  223. printk("Failed to enable switch\n");
  224. return -EBUSY;
  225. }
  226. last_port = (robo.devid == ROBO_DEVICE_ID_5398) ?
  227. ROBO_PORT6_CTRL : ROBO_PORT3_CTRL;
  228. for (i = ROBO_PORT0_CTRL; i < last_port + 1; i++)
  229. robo_write16(ROBO_CTRL_PAGE, i, 0);
  230. }
  231. /* WAN port LED, except for Netgear WGT634U */
  232. if (strcmp(getvar("nvram_type"), "cfe") != 0)
  233. robo_write16(ROBO_CTRL_PAGE, 0x16, 0x1F);
  234. return 0;
  235. }
  236. static void robo_switch_reset(void)
  237. {
  238. if ((robo.devid == ROBO_DEVICE_ID_5395) ||
  239. (robo.devid == ROBO_DEVICE_ID_5397) ||
  240. (robo.devid == ROBO_DEVICE_ID_5398)) {
  241. /* Trigger a software reset. */
  242. robo_write16(ROBO_CTRL_PAGE, 0x79, 0x83);
  243. robo_write16(ROBO_CTRL_PAGE, 0x79, 0);
  244. }
  245. }
  246. static int robo_probe(char *devname)
  247. {
  248. __u32 phyid;
  249. unsigned int i;
  250. int err;
  251. printk(KERN_INFO PFX "Probing device %s: ", devname);
  252. strcpy(robo.ifr.ifr_name, devname);
  253. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
  254. if ((robo.dev = dev_get_by_name(devname)) == NULL) {
  255. #else
  256. if ((robo.dev = dev_get_by_name(&init_net, devname)) == NULL) {
  257. #endif
  258. printk("No such device\n");
  259. return 1;
  260. }
  261. robo.device = devname;
  262. for (i = 0; i < 5; i++)
  263. robo.port[i] = i;
  264. robo.port[5] = 8;
  265. /* try access using MII ioctls - get phy address */
  266. if (do_ioctl(SIOCGMIIPHY, NULL) < 0) {
  267. robo.use_et = 1;
  268. robo.phy_addr = ROBO_PHY_ADDR;
  269. } else {
  270. /* got phy address check for robo address */
  271. struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &robo.ifr.ifr_data;
  272. if ((mii->phy_id != ROBO_PHY_ADDR) &&
  273. (mii->phy_id != ROBO_PHY_ADDR_BCM63XX) &&
  274. (mii->phy_id != ROBO_PHY_ADDR_TG3)) {
  275. printk("Invalid phy address (%d)\n", mii->phy_id);
  276. return 1;
  277. }
  278. robo.use_et = 0;
  279. /* The robo has a fixed PHY address that is different from the
  280. * Tigon3 and BCM63xx PHY address. */
  281. robo.phy_addr = ROBO_PHY_ADDR;
  282. }
  283. phyid = mdio_read(robo.phy_addr, 0x2) |
  284. (mdio_read(robo.phy_addr, 0x3) << 16);
  285. if (phyid == 0xffffffff || phyid == 0x55210022) {
  286. printk("No Robo switch in managed mode found, phy_id = 0x%08x\n", phyid);
  287. return 1;
  288. }
  289. /* Get the device ID */
  290. for (i = 0; i < 10; i++) {
  291. robo.devid = robo_read16(ROBO_MGMT_PAGE, ROBO_DEVICE_ID);
  292. if (robo.devid)
  293. break;
  294. udelay(10);
  295. }
  296. if (!robo.devid)
  297. robo.devid = ROBO_DEVICE_ID_5325; /* Fake it */
  298. robo.is_5350 = robo_vlan5350();
  299. robo_switch_reset();
  300. err = robo_switch_enable();
  301. if (err)
  302. return err;
  303. printk("found!\n");
  304. return 0;
  305. }
  306. static int handle_vlan_port_read(void *driver, char *buf, int nr)
  307. {
  308. __u16 val16;
  309. int len = 0;
  310. int j;
  311. val16 = (nr) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
  312. if (robo.is_5350) {
  313. u32 val32;
  314. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
  315. /* actual read */
  316. val32 = robo_read32(ROBO_VLAN_PAGE, ROBO_VLAN_READ);
  317. if ((val32 & (1 << 20)) /* valid */) {
  318. for (j = 0; j < 6; j++) {
  319. if (val32 & (1 << j)) {
  320. len += sprintf(buf + len, "%d", j);
  321. if (val32 & (1 << (j + 6))) {
  322. if (j == 5) buf[len++] = 'u';
  323. } else {
  324. buf[len++] = 't';
  325. if (robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (j << 1)) == nr)
  326. buf[len++] = '*';
  327. }
  328. buf[len++] = '\t';
  329. }
  330. }
  331. len += sprintf(buf + len, "\n");
  332. }
  333. } else {
  334. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
  335. /* actual read */
  336. val16 = robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_READ);
  337. if ((val16 & (1 << 14)) /* valid */) {
  338. for (j = 0; j < 6; j++) {
  339. if (val16 & (1 << j)) {
  340. len += sprintf(buf + len, "%d", j);
  341. if (val16 & (1 << (j + 7))) {
  342. if (j == 5) buf[len++] = 'u';
  343. } else {
  344. buf[len++] = 't';
  345. if (robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (j << 1)) == nr)
  346. buf[len++] = '*';
  347. }
  348. buf[len++] = '\t';
  349. }
  350. }
  351. len += sprintf(buf + len, "\n");
  352. }
  353. }
  354. buf[len] = '\0';
  355. return len;
  356. }
  357. static int handle_vlan_port_write(void *driver, char *buf, int nr)
  358. {
  359. switch_driver *d = (switch_driver *) driver;
  360. switch_vlan_config *c = switch_parse_vlan(d, buf);
  361. int j;
  362. __u16 val16;
  363. if (c == NULL)
  364. return -EINVAL;
  365. for (j = 0; j < d->ports; j++) {
  366. if ((c->untag | c->pvid) & (1 << j))
  367. /* change default vlan tag */
  368. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (j << 1), nr);
  369. }
  370. /* write config now */
  371. val16 = (nr) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
  372. if (robo.is_5350) {
  373. robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350,
  374. (1 << 20) /* valid */ | (c->untag << 6) | c->port);
  375. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
  376. } else {
  377. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE,
  378. (1 << 14) /* valid */ | (c->untag << 7) | c->port);
  379. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
  380. }
  381. return 0;
  382. }
  383. #define set_switch(state) \
  384. robo_write16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE, (robo_read16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & ~2) | (state ? 2 : 0));
  385. static int handle_enable_read(void *driver, char *buf, int nr)
  386. {
  387. return sprintf(buf, "%d\n", (((robo_read16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & 2) == 2) ? 1 : 0));
  388. }
  389. static int handle_enable_write(void *driver, char *buf, int nr)
  390. {
  391. set_switch(buf[0] == '1');
  392. return 0;
  393. }
  394. static int handle_enable_vlan_read(void *driver, char *buf, int nr)
  395. {
  396. return sprintf(buf, "%d\n", (((robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0) & (1 << 7)) == (1 << 7)) ? 1 : 0));
  397. }
  398. static int handle_enable_vlan_write(void *driver, char *buf, int nr)
  399. {
  400. int disable = ((buf[0] != '1') ? 1 : 0);
  401. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 :
  402. (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
  403. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 :
  404. (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
  405. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 :
  406. (1 << 6) /* drop invalid VID frames */);
  407. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 :
  408. (1 << 3) /* drop miss V table frames */);
  409. return 0;
  410. }
  411. static int handle_reset(void *driver, char *buf, int nr)
  412. {
  413. switch_driver *d = (switch_driver *) driver;
  414. switch_vlan_config *c = switch_parse_vlan(d, buf);
  415. int j;
  416. __u16 val16;
  417. if (c == NULL)
  418. return -EINVAL;
  419. /* disable switching */
  420. set_switch(0);
  421. /* reset vlans */
  422. for (j = 0; j <= ((robo.is_5350) ? VLAN_ID_MAX5350 : VLAN_ID_MAX); j++) {
  423. /* write config now */
  424. val16 = (j) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
  425. if (robo.is_5350)
  426. robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, 0);
  427. else
  428. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 0);
  429. robo_write16(ROBO_VLAN_PAGE, robo.is_5350 ? ROBO_VLAN_TABLE_ACCESS_5350 :
  430. ROBO_VLAN_TABLE_ACCESS,
  431. val16);
  432. }
  433. /* reset ports to a known good state */
  434. for (j = 0; j < d->ports; j++) {
  435. robo_write16(ROBO_CTRL_PAGE, robo.port[j], 0x0000);
  436. robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (j << 1), 0);
  437. }
  438. /* enable switching */
  439. set_switch(1);
  440. /* enable vlans */
  441. handle_enable_vlan_write(driver, "1", 0);
  442. return 0;
  443. }
  444. static int __init robo_init(void)
  445. {
  446. int notfound = 1;
  447. char *device;
  448. device = strdup("ethX");
  449. for (device[3] = '0'; (device[3] <= '3') && notfound; device[3]++) {
  450. if (! switch_device_registered (device))
  451. notfound = robo_probe(device);
  452. }
  453. device[3]--;
  454. if (notfound) {
  455. kfree(device);
  456. return -ENODEV;
  457. } else {
  458. static const switch_config cfg[] = {
  459. {
  460. .name = "enable",
  461. .read = handle_enable_read,
  462. .write = handle_enable_write
  463. }, {
  464. .name = "enable_vlan",
  465. .read = handle_enable_vlan_read,
  466. .write = handle_enable_vlan_write
  467. }, {
  468. .name = "reset",
  469. .read = NULL,
  470. .write = handle_reset
  471. }, { NULL, },
  472. };
  473. static const switch_config vlan[] = {
  474. {
  475. .name = "ports",
  476. .read = handle_vlan_port_read,
  477. .write = handle_vlan_port_write
  478. }, { NULL, },
  479. };
  480. switch_driver driver = {
  481. .name = DRIVER_NAME,
  482. .version = DRIVER_VERSION,
  483. .interface = device,
  484. .cpuport = 5,
  485. .ports = 6,
  486. .vlans = 16,
  487. .driver_handlers = cfg,
  488. .port_handlers = NULL,
  489. .vlan_handlers = vlan,
  490. };
  491. return switch_register_driver(&driver);
  492. }
  493. }
  494. static void __exit robo_exit(void)
  495. {
  496. switch_unregister_driver(DRIVER_NAME);
  497. kfree(robo.device);
  498. }
  499. MODULE_AUTHOR("Felix Fietkau <[email protected]>");
  500. MODULE_LICENSE("GPL");
  501. module_init(robo_init);
  502. module_exit(robo_exit);