asix.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * Asix USB ether adapters
  3. * I got no documentation for it, thus the bits
  4. * come from other systems; it's likely this is
  5. * doing more than needed in some places and
  6. * less than required in others.
  7. */
  8. #include <u.h>
  9. #include <libc.h>
  10. #include <fcall.h>
  11. #include <thread.h>
  12. #include "usb.h"
  13. #include "usbfs.h"
  14. #include "ether.h"
  15. enum
  16. {
  17. /* Asix commands */
  18. Cswmii = 0x06, /* set sw mii */
  19. Crmii = 0x07, /* read mii reg */
  20. Cwmii = 0x08, /* write mii reg */
  21. Chwmii = 0x0a, /* set hw mii */
  22. Creeprom = 0x0b, /* read eeprom */
  23. Cwdis = 0x0e, /* write disable */
  24. Cwena = 0x0d, /* write enable */
  25. Crrxctl = 0x0f, /* read rx ctl */
  26. Cwrxctl = 0x10, /* write rx ctl */
  27. Cwipg = 0x12, /* write ipg */
  28. Crmac = 0x13, /* read mac addr */
  29. Crphy = 0x19, /* read phy id */
  30. Cwmedium = 0x1b, /* write medium mode */
  31. Crgpio = 0x1e, /* read gpio */
  32. Cwgpio = 0x1f, /* write gpios */
  33. Creset = 0x20, /* reset */
  34. Cwphy = 0x22, /* select phy */
  35. /* reset codes */
  36. Rclear = 0x00,
  37. Rprte = 0x04,
  38. Rprl = 0x08,
  39. Riprl = 0x20,
  40. Rippd = 0x40,
  41. Gpiogpo1en = 0x04, /* gpio1 enable */,
  42. Gpiogpo1 = 0x08, /* gpio1 value */
  43. Gpiogpo2en = 0x10, /* gpio2 enable */
  44. Gpiogpo2 = 0x20, /* gpio2 value */
  45. Gpiorse = 0x80, /* gpio reload serial eeprom */
  46. Pmask = 0x1F,
  47. Pembed = 0x10, /* embedded phy */
  48. Mfd = 0x002, /* media */
  49. Mac = 0x004,
  50. Mrfc = 0x010,
  51. Mtfc = 0x020,
  52. Mjfe = 0x040,
  53. Mre = 0x100,
  54. Mps = 0x200,
  55. Mall772 = Mfd|Mrfc|Mtfc|Mps|Mac|Mre,
  56. Mall178 = Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre,
  57. Ipgdflt = 0x15|0x0c|0x12, /* default ipg0, 1, 2 */
  58. Rxctlso = 0x80,
  59. Rxctlab = 0x08,
  60. Rxctlsep = 0x04,
  61. Rxctlamall = 0x02, /* all multicast */
  62. Rxctlprom = 0x01, /* promiscuous */
  63. /* MII */
  64. Miibmcr = 0x00, /* basic mode ctrl reg. */
  65. Bmcrreset = 0x8000, /* reset */
  66. Bmcranena = 0x1000, /* auto neg. enable */
  67. Bmcrar = 0x0200, /* announce restart */
  68. Miiad = 0x04, /* advertise reg. */
  69. Adcsma = 0x0001,
  70. Ad1000f = 0x0200,
  71. Ad1000h = 0x0100,
  72. Ad10h = 0x0020,
  73. Ad10f = 0x0040,
  74. Ad100h = 0x0080,
  75. Ad100f = 0x0100,
  76. Adpause = 0x0400,
  77. Adall = Ad10h|Ad10f|Ad100h|Ad100f,
  78. Miimctl = 0x14, /* marvell ctl */
  79. Mtxdly = 0x02,
  80. Mrxdly = 0x80,
  81. Mtxrxdly = 0x82,
  82. Miic1000 = 0x09,
  83. };
  84. static int
  85. asixset(Dev *d, int c, int v)
  86. {
  87. int r;
  88. int ec;
  89. r = Rh2d|Rvendor|Rdev;
  90. ec = usbcmd(d, r, c, v, 0, nil, 0);
  91. if(ec < 0)
  92. deprint(2, "%s: asixset %x %x: %r\n", argv0, c, v);
  93. return ec;
  94. }
  95. static int
  96. asixget(Dev *d, int c, uchar *buf, int l)
  97. {
  98. int r;
  99. int ec;
  100. r = Rd2h|Rvendor|Rdev;
  101. ec = usbcmd(d, r, c, 0, 0, buf, l);
  102. if(ec < 0)
  103. deprint(2, "%s: asixget %x: %r\n", argv0, c);
  104. return ec;
  105. }
  106. static int
  107. getgpio(Dev *d)
  108. {
  109. uchar c;
  110. if(asixget(d, Crgpio, &c, 1) < 0)
  111. return -1;
  112. return c;
  113. }
  114. static int
  115. getphy(Dev *d)
  116. {
  117. uchar buf[2];
  118. if(asixget(d, Crphy, buf, sizeof(buf)) < 0)
  119. return -1;
  120. deprint(2, "%s: phy addr %#ux\n", argv0, buf[1]);
  121. return buf[1];
  122. }
  123. static int
  124. getrxctl(Dev *d)
  125. {
  126. uchar buf[2];
  127. int r;
  128. memset(buf, 0, sizeof(buf));
  129. if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0)
  130. return -1;
  131. r = GET2(buf);
  132. deprint(2, "%s: rxctl %#x\n", argv0, r);
  133. return r;
  134. }
  135. static int
  136. getmac(Dev *d, uchar buf[])
  137. {
  138. if(asixget(d, Crmac, buf, Eaddrlen) < 0)
  139. return -1;
  140. return Eaddrlen;
  141. }
  142. static int
  143. miiread(Dev *d, int phy, int reg)
  144. {
  145. int r;
  146. uchar v[2];
  147. r = Rd2h|Rvendor|Rdev;
  148. if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){
  149. dprint(2, "%s: miiwrite: %r\n", argv0);
  150. return -1;
  151. }
  152. r = GET2(v);
  153. if(r == 0xFFFF)
  154. return -1;
  155. return r;
  156. }
  157. static int
  158. miiwrite(Dev *d, int phy, int reg, int val)
  159. {
  160. int r;
  161. uchar v[2];
  162. if(asixset(d, Cswmii, 0) < 0)
  163. return -1;
  164. r = Rh2d|Rvendor|Rdev;
  165. PUT2(v, val);
  166. if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){
  167. deprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val);
  168. return -1;
  169. }
  170. if(asixset(d, Chwmii, 0) < 0)
  171. return -1;
  172. return 0;
  173. }
  174. static int
  175. eepromread(Dev *d, int i)
  176. {
  177. int r;
  178. int ec;
  179. uchar buf[2];
  180. r = Rd2h|Rvendor|Rdev;
  181. ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf));
  182. if(ec < 0)
  183. deprint(2, "%s: eepromread %d: %r\n", argv0, i);
  184. ec = GET2(buf);
  185. deprint(2, "%s: eeprom %#x = %#x\n", argv0, i, ec);
  186. if(ec == 0xFFFF)
  187. ec = -1;
  188. return ec;
  189. }
  190. /*
  191. * No doc. we are doing what Linux does as closely
  192. * as we can.
  193. */
  194. static int
  195. ctlrinit(Ether *ether)
  196. {
  197. Dev *d;
  198. int i;
  199. int bmcr;
  200. int gpio;
  201. int ee17;
  202. int rc;
  203. d = ether->dev;
  204. switch(ether->cid){
  205. case A8817x:
  206. case A88179:
  207. fprint(2, "%s: card known but not implemented\n", argv0);
  208. /* fall through */
  209. default:
  210. return -1;
  211. case A88178:
  212. deprint(2, "%s: setting up A88178\n", argv0);
  213. gpio = getgpio(d);
  214. if(gpio < 0)
  215. return -1;
  216. deprint(2, "%s: gpio sts %#x\n", argv0, gpio);
  217. asixset(d, Cwena, 0);
  218. ee17 = eepromread(d, 0x0017);
  219. asixset(d, Cwdis, 0);
  220. asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en);
  221. if((ee17 >> 8) != 1){
  222. asixset(d, Cwgpio, 0x003c);
  223. asixset(d, Cwgpio, 0x001c);
  224. asixset(d, Cwgpio, 0x003c);
  225. }else{
  226. asixset(d, Cwgpio, Gpiogpo1en);
  227. asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en);
  228. }
  229. asixset(d, Creset, Rclear);
  230. sleep(150);
  231. asixset(d, Creset, Rippd|Rprl);
  232. sleep(150);
  233. asixset(d, Cwrxctl, 0);
  234. if(getmac(d, ether->addr) < 0)
  235. return -1;
  236. ether->phy = getphy(d);
  237. if(ee17 < 0 || (ee17 & 0x7) == 0){
  238. miiwrite(d, ether->phy, Miimctl, Mtxrxdly);
  239. sleep(60);
  240. }
  241. miiwrite(d, ether->phy, Miibmcr, Bmcrreset|Bmcranena);
  242. miiwrite(d, ether->phy, Miiad, Adall|Adcsma|Adpause);
  243. miiwrite(d, ether->phy, Miic1000, Ad1000f);
  244. bmcr = miiread(d, ether->phy, Miibmcr);
  245. if((bmcr & Bmcranena) != 0){
  246. bmcr |= Bmcrar;
  247. miiwrite(d, ether->phy, Miibmcr, bmcr);
  248. }
  249. asixset(d, Cwmedium, Mall178);
  250. asixset(d, Cwrxctl, Rxctlso|Rxctlab);
  251. break;
  252. case A88772:
  253. deprint(2, "%s: setting up A88772\n", argv0);
  254. if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0)
  255. return -1;
  256. ether->phy = getphy(d);
  257. dprint(2, "%s: phy %#x\n", argv0, ether->phy);
  258. if((ether->phy & Pmask) == Pembed){
  259. /* embedded 10/100 ethernet */
  260. rc = asixset(d, Cwphy, 1);
  261. }else
  262. rc = asixset(d, Cwphy, 0);
  263. if(rc < 0)
  264. return -1;
  265. if(asixset(d, Creset, Rippd|Rprl) < 0)
  266. return -1;
  267. sleep(150);
  268. if((ether->phy & Pmask) == Pembed)
  269. rc = asixset(d, Creset, Riprl);
  270. else
  271. rc = asixset(d, Creset, Rprte);
  272. if(rc < 0)
  273. return -1;
  274. sleep(150);
  275. rc = getrxctl(d);
  276. deprint(2, "%s: rxctl is %#x\n", argv0, rc);
  277. if(asixset(d, Cwrxctl, 0) < 0)
  278. return -1;
  279. if(getmac(d, ether->addr) < 0)
  280. return -1;
  281. if(asixset(d, Creset, Rprl) < 0)
  282. return -1;
  283. sleep(150);
  284. if(asixset(d, Creset, Riprl|Rprl) < 0)
  285. return -1;
  286. sleep(150);
  287. miiwrite(d, ether->phy, Miibmcr, Bmcrreset);
  288. miiwrite(d, ether->phy, Miiad, Adall|Adcsma);
  289. bmcr = miiread(d, ether->phy, Miibmcr);
  290. if((bmcr & Bmcranena) != 0){
  291. bmcr |= Bmcrar;
  292. miiwrite(d, ether->phy, Miibmcr, bmcr);
  293. }
  294. if(asixset(d, Cwmedium, Mall772) < 0)
  295. return -1;
  296. if(asixset(d, Cwipg, Ipgdflt) < 0)
  297. return -1;
  298. if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0)
  299. return -1;
  300. deprint(2, "%s: final rxctl: %#x\n", argv0, getrxctl(d));
  301. break;
  302. }
  303. if(etherdebug){
  304. fprint(2, "%s: ether: phy %#x addr ", argv0, ether->phy);
  305. for(i = 0; i < sizeof(ether->addr); i++)
  306. fprint(2, "%02x", ether->addr[i]);
  307. fprint(2, "\n");
  308. }
  309. return 0;
  310. }
  311. static long
  312. asixbread(Ether *e, Buf *bp)
  313. {
  314. ulong nr;
  315. ulong hd;
  316. Buf *rbp;
  317. rbp = e->aux;
  318. if(rbp == nil || rbp->ndata < 4){
  319. rbp->rp = rbp->data;
  320. rbp->ndata = read(e->epin->dfd, rbp->rp, sizeof(bp->data));
  321. if(rbp->ndata < 0)
  322. return -1;
  323. }
  324. if(rbp->ndata < 4){
  325. werrstr("short frame");
  326. deprint(2, "%s: asixbread got %d bytes\n", argv0, rbp->ndata);
  327. rbp->ndata = 0;
  328. return 0;
  329. }
  330. hd = GET4(rbp->rp);
  331. nr = hd & 0xFFFF;
  332. hd = (hd>>16) & 0xFFFF;
  333. if(nr != (~hd & 0xFFFF)){
  334. if(0)deprint(2, "%s: asixread: bad header %#ulx %#ulx\n",
  335. argv0, nr, (~hd & 0xFFFF));
  336. werrstr("bad usb packet header");
  337. rbp->ndata = 0;
  338. return 0;
  339. }
  340. rbp->rp += 4;
  341. if(nr < 6 || nr > Epktlen){
  342. if(nr < 6)
  343. werrstr("short frame");
  344. else
  345. werrstr("long frame");
  346. deprint(2, "%s: asixbread %r (%ld)\n", argv0, nr);
  347. rbp->ndata = 0;
  348. return 0;
  349. }
  350. bp->rp = bp->data + Hdrsize;
  351. memmove(bp->rp, rbp->rp, nr);
  352. bp->ndata = nr;
  353. rbp->rp += 4 + nr;
  354. rbp->ndata -= (4 + nr);
  355. return bp->ndata;
  356. }
  357. static long
  358. asixbwrite(Ether *e, Buf *bp)
  359. {
  360. ulong len;
  361. long n;
  362. deprint(2, "%s: asixbwrite %d bytes\n", argv0, bp->ndata);
  363. assert(bp->rp - bp->data >= Hdrsize);
  364. bp->ndata &= 0xFFFF;
  365. len = (0xFFFF0000 & ~(bp->ndata<<16)) | bp->ndata;
  366. bp->rp -= 4;
  367. PUT4(bp->rp, len);
  368. bp->ndata += 4;
  369. if((bp->ndata % e->epout->maxpkt) == 0){
  370. PUT4(bp->rp+bp->ndata, 0xFFFF0000);
  371. bp->ndata += 4;
  372. }
  373. n = write(e->epout->dfd, bp->rp, bp->ndata);
  374. deprint(2, "%s: asixbwrite wrote %ld bytes\n", argv0, n);
  375. if(n <= 0)
  376. return n;
  377. return n;
  378. }
  379. static int
  380. asixpromiscuous(Ether *e, int on)
  381. {
  382. int rxctl;
  383. deprint(2, "%s: asixpromiscuous %d\n", argv0, on);
  384. rxctl = getrxctl(e->dev);
  385. if(on != 0)
  386. rxctl |= Rxctlprom;
  387. else
  388. rxctl &= ~Rxctlprom;
  389. return asixset(e->dev, Cwrxctl, rxctl);
  390. }
  391. static int
  392. asixmulticast(Ether *e, uchar *addr, int on)
  393. {
  394. int rxctl;
  395. USED(addr);
  396. USED(on);
  397. /* BUG: should write multicast filter */
  398. rxctl = getrxctl(e->dev);
  399. if(e->nmcasts != 0)
  400. rxctl |= Rxctlamall;
  401. else
  402. rxctl &= ~Rxctlamall;
  403. deprint(2, "%s: asixmulticast %d\n", argv0, e->nmcasts);
  404. return asixset(e->dev, Cwrxctl, rxctl);
  405. }
  406. static void
  407. asixfree(Ether *ether)
  408. {
  409. deprint(2, "%s: aixfree %#p\n", argv0, ether);
  410. free(ether->aux);
  411. ether->aux = nil;
  412. }
  413. int
  414. asixreset(Ether *ether)
  415. {
  416. Cinfo *ip;
  417. Dev *dev;
  418. dev = ether->dev;
  419. for(ip = cinfo; ip->vid != 0; ip++)
  420. if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
  421. ether->cid = ip->cid;
  422. if(ctlrinit(ether) < 0){
  423. deprint(2, "%s: asix init failed: %r\n", argv0);
  424. return -1;
  425. }
  426. deprint(2, "%s: asix reset done\n", argv0);
  427. ether->name = "asix";
  428. ether->aux = emallocz(sizeof(Buf), 1);
  429. ether->bufsize = Hdrsize+Maxpkt;
  430. ether->bread = asixbread;
  431. ether->bwrite = asixbwrite;
  432. ether->free = asixfree;
  433. ether->promiscuous = asixpromiscuous;
  434. ether->multicast = asixmulticast;
  435. ether->mbps = 100; /* BUG */
  436. return 0;
  437. }
  438. return -1;
  439. }