ethersmc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. /*
  2. * SMC EtherEZ (SMC91cXX chip) PCMCIA card support.
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "io.h"
  10. #include "../port/error.h"
  11. #include "../port/netif.h"
  12. #include "etherif.h"
  13. enum {
  14. IoSize = 0x10, /* port pool size */
  15. TxTimeout = 150,
  16. };
  17. enum { /* PCMCIA related */
  18. TupleFunce = 0x22,
  19. TfNodeId = 0x04,
  20. };
  21. enum { /* bank 0 registers */
  22. Tcr = 0x0000, /* transmit control */
  23. Eph = 0x0002, /* ethernet protocol handler */
  24. Rcr = 0x0004, /* receiver control */
  25. Counter = 0x0006, /* statistics counter */
  26. MemInfo = 0x0008,
  27. MemCfg = 0x000A,
  28. };
  29. enum { /* bank 1 registers */
  30. Config = 0x0000,
  31. BaseAddr = 0x0002,
  32. Addr0 = 0x0004, /* ethernet address */
  33. Addr1 = 0x0006,
  34. Addr2 = 0x0008,
  35. General = 0x000A,
  36. Control = 0x000C,
  37. };
  38. enum { /* bank 2 registers */
  39. MmuCmd = 0x0000,
  40. PktNo = 0x0002,
  41. AllocRes = 0x0003,
  42. FifoPorts = 0x0004,
  43. Pointer = 0x0006,
  44. Data1 = 0x0008,
  45. Interrupt = 0x000C,
  46. IntrMask = 0x000D,
  47. };
  48. enum { /* bank 3 registers */
  49. Mcast0 = 0x0000,
  50. Mcast2 = 0x0002,
  51. Mcast4 = 0x0004,
  52. Mcast6 = 0x0006,
  53. Revision = 0x000A,
  54. };
  55. enum {
  56. BankSelect = 0x000E /* bank select register */
  57. };
  58. enum {
  59. BsrMask = 0xFF00, /* mask for chip identification */
  60. BsrId = 0x3300,
  61. };
  62. enum { /* Tcr values */
  63. TcrClear = 0x0000,
  64. TcrEnable = 0x0001, /* enable transmit */
  65. TcrLoop = 0x0002, /* enable internal analogue loopback */
  66. TcrForceCol = 0x0004, /* force collision on next tx */
  67. TcrPadEn = 0x0080, /* pad short packets to 64 bytes */
  68. TcrNoCrc = 0x0100, /* do not append CRC */
  69. TcrMonCns = 0x0400, /* monitor carrier status */
  70. TcrFduplx = 0x0800,
  71. TcrStpSqet = 0x1000,
  72. TcrEphLoop = 0x2000,
  73. TcrNormal = TcrEnable,
  74. };
  75. enum { /* Eph values */
  76. EphTxOk = 0x0001,
  77. Eph1Col = 0x0002, /* single collision */
  78. EphMCol = 0x0004, /* multiple collisions */
  79. EphTxMcast = 0x0008, /* multicast transmit */
  80. Eph16Col = 0x0010, /* 16 collisions, tx disabled */
  81. EphSqet = 0x0020, /* SQE test failed, tx disabled */
  82. EphTxBcast = 0x0040, /* broadcast tx */
  83. EphDefr = 0x0080, /* deffered tx */
  84. EphLatCol = 0x0200, /* late collision, tx disabled */
  85. EphLostCarr = 0x0400, /* lost carrier, tx disabled */
  86. EphExcDefr = 0x0800, /* excessive defferals */
  87. EphCntRol = 0x1000, /* ECR counter(s) rolled over */
  88. EphRxOvrn = 0x2000, /* receiver overrun, packets dropped */
  89. EphLinkOk = 0x4000,
  90. EphTxUnrn = 0x8000, /* tx underrun */
  91. };
  92. enum { /* Rcr values */
  93. RcrClear = 0x0000,
  94. RcrPromisc = 0x0002,
  95. RcrAllMcast = 0x0004,
  96. RcrEnable = 0x0100,
  97. RcrStripCrc = 0x0200,
  98. RcrSoftReset = 0x8000,
  99. RcrNormal = RcrStripCrc | RcrEnable,
  100. };
  101. enum { /* Counter value masks */
  102. CntColMask = 0x000F, /* collisions */
  103. CntMColMask = 0x00F0, /* multiple collisions */
  104. CntDtxMask = 0x0F00, /* deferred transmits */
  105. CntExDtxMask = 0xF000, /* excessively deferred transmits */
  106. CntColShr = 1,
  107. CntMColShr = 4,
  108. CntDtxShr = 8,
  109. };
  110. enum { /* MemInfo value masks */
  111. MirTotalMask = 0x00FF,
  112. MirFreeMask = 0xFF00,
  113. };
  114. enum { /* Config values */
  115. CfgIrqSel0 = 0x0002,
  116. CfgIrqSel1 = 0x0004,
  117. CfgDisLink = 0x0040, /* disable 10BaseT link test */
  118. Cfg16Bit = 0x0080,
  119. CfgAuiSelect = 0x0100,
  120. CfgSetSqlch = 0x0200,
  121. CfgFullStep = 0x0400,
  122. CfgNoWait = 0x1000,
  123. CfgMiiSelect = 0x8000,
  124. };
  125. enum { /* Control values */
  126. CtlStore = 0x0001, /* store to EEPROM */
  127. CtlReload = 0x0002, /* reload EEPROM into registers */
  128. CtlEeSelect = 0x0004, /* select registers for reload/store */
  129. CtlTeEnable = 0x0020, /* tx error detection via eph irq */
  130. CtlCrEnable = 0x0040, /* counter rollover via eph irq */
  131. CtlLeEnable = 0x0080, /* link error detection via eph irq*/
  132. CtlAutoRls = 0x0800, /* auto release mode */
  133. CtlPowerDn = 0x2000,
  134. };
  135. enum { /* MmuCmd values */
  136. McBusy = 0x0001,
  137. McAlloc = 0x0020, /* | with number of 256 byte packets - 1 */
  138. McReset = 0x0040,
  139. McRelease = 0x0080, /* dequeue (but not free) current rx packet */
  140. McFreePkt = 0x00A0, /* dequeue and free current rx packet */
  141. McEnqueue = 0x00C0, /* enqueue the packet for tx */
  142. McTxReset = 0x00E0, /* reset transmit queues */
  143. };
  144. enum { /* AllocRes values */
  145. ArFailed = 0x80,
  146. };
  147. enum { /* FifoPorts values */
  148. FpTxEmpty = 0x0080,
  149. FpRxEmpty = 0x8000,
  150. FpTxMask = 0x007F,
  151. FpRxMask = 0x7F00,
  152. };
  153. enum { /* Pointer values */
  154. PtrRead = 0x2000,
  155. PtrAutoInc = 0x4000,
  156. PtrRcv = 0x8000,
  157. };
  158. enum { /* Interrupt values */
  159. IntRcv = 0x0001,
  160. IntTxError = 0x0002,
  161. IntTxEmpty = 0x0004,
  162. IntAlloc = 0x0008,
  163. IntRxOvrn = 0x0010,
  164. IntEph = 0x0020,
  165. };
  166. enum { /* transmit status bits */
  167. TsSuccess = 0x0001,
  168. Ts16Col = 0x00A0,
  169. TsLatCol = 0x0200,
  170. TsLostCar = 0x0400,
  171. };
  172. enum { /* receive status bits */
  173. RsMcast = 0x0001,
  174. RsTooShort = 0x0400,
  175. RsTooLong = 0x0800,
  176. RsOddFrame = 0x1000,
  177. RsBadCrc = 0x2000,
  178. RsAlgnErr = 0x8000,
  179. RsError = RsAlgnErr | RsBadCrc | RsTooLong | RsTooShort,
  180. };
  181. enum {
  182. RxLenMask = 0x07FF, /* significant rx len bits */
  183. HdrSize = 6, /* packet header length */
  184. PageSize = 256, /* page length */
  185. };
  186. typedef struct Smc91xx Smc91xx;
  187. struct Smc91xx {
  188. Lock;
  189. ushort rev;
  190. int attached;
  191. Block *txbp;
  192. ulong txtime;
  193. ulong rovrn;
  194. ulong lcar;
  195. ulong col;
  196. ulong scol;
  197. ulong mcol;
  198. ulong lcol;
  199. ulong dfr;
  200. };
  201. #define SELECT_BANK(x) outs(port + BankSelect, x)
  202. static int
  203. readnodeid(int slot, Ether* ether)
  204. {
  205. uchar data[Eaddrlen + 1];
  206. int len;
  207. len = sizeof(data);
  208. if (pcmcistuple(slot, TupleFunce, TfNodeId, data, len) != len)
  209. return -1;
  210. if (data[0] != Eaddrlen)
  211. return -1;
  212. memmove(ether->ea, &data[1], Eaddrlen);
  213. return 0;
  214. }
  215. static void
  216. chipreset(Ether* ether)
  217. {
  218. int port;
  219. int i;
  220. port = ether->port;
  221. /* reset the chip */
  222. SELECT_BANK(0);
  223. outs(port + Rcr, RcrSoftReset);
  224. delay(1);
  225. outs(port + Rcr, RcrClear);
  226. outs(port + Tcr, TcrClear);
  227. SELECT_BANK(1);
  228. outs(port + Control, CtlAutoRls | CtlTeEnable |
  229. CtlCrEnable);
  230. for(i = 0; i < 6; i++) {
  231. outb(port + Addr0 + i, ether->ea[i]);
  232. }
  233. SELECT_BANK(2);
  234. outs(port + MmuCmd, McReset);
  235. }
  236. static void
  237. chipenable(Ether* ether)
  238. {
  239. int port;
  240. port = ether->port;
  241. SELECT_BANK(0);
  242. outs(port + Tcr, TcrNormal);
  243. outs(port + Rcr, RcrNormal);
  244. SELECT_BANK(2);
  245. outb(port + IntrMask, IntEph | IntRxOvrn | IntRcv);
  246. }
  247. static void
  248. attach(Ether *ether)
  249. {
  250. Smc91xx* ctlr;
  251. ctlr = ether->ctlr;
  252. ilock(ctlr);
  253. if (ctlr->attached) {
  254. iunlock(ctlr);
  255. return;
  256. }
  257. chipenable(ether);
  258. ctlr->attached = 1;
  259. iunlock(ctlr);
  260. }
  261. static void
  262. txstart(Ether* ether)
  263. {
  264. int port;
  265. Smc91xx* ctlr;
  266. Block* bp;
  267. int len, npages;
  268. int pno;
  269. /* assumes ctlr is locked and bank 2 is selected */
  270. /* leaves bank 2 selected on return */
  271. port = ether->port;
  272. ctlr = ether->ctlr;
  273. if (ctlr->txbp) {
  274. bp = ctlr->txbp;
  275. ctlr->txbp = 0;
  276. } else {
  277. bp = qget(ether->oq);
  278. if (bp == 0)
  279. return;
  280. len = BLEN(bp);
  281. npages = (len + HdrSize) / PageSize;
  282. outs(port + MmuCmd, McAlloc | npages);
  283. }
  284. pno = inb(port + AllocRes);
  285. if (pno & ArFailed) {
  286. outb(port + IntrMask, inb(port + IntrMask) | IntAlloc);
  287. ctlr->txbp = bp;
  288. ctlr->txtime = MACHP(0)->ticks;
  289. return;
  290. }
  291. outb(port + PktNo, pno);
  292. outs(port + Pointer, PtrAutoInc);
  293. len = BLEN(bp);
  294. outs(port + Data1, 0);
  295. outb(port + Data1, (len + HdrSize) & 0xFF);
  296. outb(port + Data1, (len + HdrSize) >> 8);
  297. outss(port + Data1, bp->rp, len / 2);
  298. if ((len & 1) == 0) {
  299. outs(port + Data1, 0);
  300. } else {
  301. outb(port + Data1, bp->rp[len - 1]);
  302. outb(port + Data1, 0x20); /* no info what 0x20 means */
  303. }
  304. outb(port + IntrMask, inb(port + IntrMask) |
  305. IntTxError | IntTxEmpty);
  306. outs(port + MmuCmd, McEnqueue);
  307. freeb(bp);
  308. }
  309. static void
  310. receive(Ether* ether)
  311. {
  312. int port;
  313. Block* bp;
  314. int pktno, status, len;
  315. /* assumes ctlr is locked and bank 2 is selected */
  316. /* leaves bank 2 selected on return */
  317. port = ether->port;
  318. pktno = ins(port + FifoPorts);
  319. if (pktno & FpRxEmpty) {
  320. return;
  321. }
  322. outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc);
  323. status = ins(port + Data1);
  324. len = ins(port + Data1) & RxLenMask - HdrSize;
  325. if (status & RsOddFrame)
  326. len++;
  327. if ((status & RsError) || (bp = iallocb(len)) == 0) {
  328. if (status & RsAlgnErr)
  329. ether->frames++;
  330. if (status & (RsTooShort | RsTooLong))
  331. ether->buffs++;
  332. if (status & RsBadCrc)
  333. ether->crcs++;
  334. outs(port + MmuCmd, McRelease);
  335. return;
  336. }
  337. /* packet length is padded to word */
  338. inss(port + Data1, bp->rp, len / 2);
  339. bp->wp = bp->rp + (len & ~1);
  340. if (len & 1) {
  341. *bp->wp = inb(port + Data1);
  342. bp->wp++;
  343. }
  344. etheriq(ether, bp, 1);
  345. ether->inpackets++;
  346. outs(port + MmuCmd, McRelease);
  347. }
  348. static void
  349. txerror(Ether* ether)
  350. {
  351. int port;
  352. Smc91xx* ctlr;
  353. int save_pkt;
  354. int pktno, status;
  355. /* assumes ctlr is locked and bank 2 is selected */
  356. /* leaves bank 2 selected on return */
  357. port = ether->port;
  358. ctlr = ether->ctlr;
  359. save_pkt = inb(port + PktNo);
  360. pktno = ins(port + FifoPorts) & FpTxMask;
  361. outb(port + PktNo, pktno);
  362. outs(port + Pointer, PtrAutoInc | PtrRead);
  363. status = ins(port + Data1);
  364. if (status & TsLostCar)
  365. ctlr->lcar++;
  366. if (status & TsLatCol)
  367. ctlr->lcol++;
  368. if (status & Ts16Col)
  369. ctlr->scol++;
  370. ether->oerrs++;
  371. SELECT_BANK(0);
  372. outs(port + Tcr, ins(port + Tcr) | TcrEnable);
  373. SELECT_BANK(2);
  374. outs(port + MmuCmd, McFreePkt);
  375. outb(port + PktNo, save_pkt);
  376. }
  377. static void
  378. eph_irq(Ether* ether)
  379. {
  380. int port;
  381. Smc91xx* ctlr;
  382. ushort status;
  383. int n;
  384. /* assumes ctlr is locked and bank 2 is selected */
  385. /* leaves bank 2 selected on return */
  386. port = ether->port;
  387. ctlr = ether->ctlr;
  388. SELECT_BANK(0);
  389. status = ins(port + Eph);
  390. if (status & EphCntRol) {
  391. /* read the counter register even if we don't need it */
  392. /* otherwise we will keep getting this interrupt */
  393. n = ins(port + Counter);
  394. ctlr->col += (n & CntColMask) >> CntColShr;
  395. ctlr->mcol += (n & CntMColMask) >> CntMColShr;
  396. ctlr->dfr += (n & CntDtxMask) >> CntDtxShr;
  397. }
  398. /* if there was a transmit error, Tcr is disabled */
  399. outs(port + Tcr, ins(port + Tcr) | TcrEnable);
  400. /* clear a link error interrupt */
  401. SELECT_BANK(1);
  402. outs(port + Control, CtlAutoRls);
  403. outs(port + Control, CtlAutoRls | CtlTeEnable | CtlCrEnable);
  404. SELECT_BANK(2);
  405. }
  406. static void
  407. transmit(Ether* ether)
  408. {
  409. Smc91xx* ctlr;
  410. int port, n;
  411. ctlr = ether->ctlr;
  412. port = ether->port;
  413. ilock(ctlr);
  414. if (ctlr->txbp) {
  415. n = TK2MS(MACHP(0)->ticks - ctlr->txtime);
  416. if (n > TxTimeout) {
  417. chipreset(ether);
  418. chipenable(ether);
  419. freeb(ctlr->txbp);
  420. ctlr->txbp = 0;
  421. }
  422. iunlock(ctlr);
  423. return;
  424. }
  425. SELECT_BANK(2);
  426. txstart(ether);
  427. iunlock(ctlr);
  428. }
  429. static void
  430. interrupt(Ureg*, void *arg)
  431. {
  432. int port;
  433. Smc91xx* ctlr;
  434. Ether* ether;
  435. int save_bank;
  436. int save_pointer;
  437. int mask, status;
  438. ether = arg;
  439. port = ether->port;
  440. ctlr = ether->ctlr;
  441. ilock(ctlr);
  442. save_bank = ins(port + BankSelect);
  443. SELECT_BANK(2);
  444. save_pointer = ins(port + Pointer);
  445. mask = inb(port + IntrMask);
  446. outb(port + IntrMask, 0);
  447. while ((status = inb(port + Interrupt) & mask) != 0) {
  448. if (status & IntRcv) {
  449. receive(ether);
  450. }
  451. if (status & IntTxError) {
  452. txerror(ether);
  453. }
  454. if (status & IntTxEmpty) {
  455. outb(port + Interrupt, IntTxEmpty);
  456. outb(port + IntrMask, mask & ~IntTxEmpty);
  457. txstart(ether);
  458. mask = inb(port + IntrMask);
  459. }
  460. if (status & IntAlloc) {
  461. outb(port + IntrMask, mask & ~IntAlloc);
  462. txstart(ether);;
  463. mask = inb(port + IntrMask);
  464. }
  465. if (status & IntRxOvrn) {
  466. ctlr->rovrn++;
  467. ether->misses++;
  468. outb(port + Interrupt,IntRxOvrn);
  469. }
  470. if (status & IntEph)
  471. eph_irq(ether);
  472. }
  473. outb(port + IntrMask, mask);
  474. outs(port + Pointer, save_pointer);
  475. outs(port + BankSelect, save_bank);
  476. iunlock(ctlr);
  477. }
  478. static void
  479. promiscuous(void* arg, int on)
  480. {
  481. int port;
  482. Smc91xx *ctlr;
  483. Ether* ether;
  484. ushort x;
  485. ether = arg;
  486. port = ether->port;
  487. ctlr = ether->ctlr;
  488. ilock(ctlr);
  489. SELECT_BANK(0);
  490. x = ins(port + Rcr);
  491. if (on)
  492. x |= RcrPromisc;
  493. else
  494. x &= ~RcrPromisc;
  495. outs(port + Rcr, x);
  496. iunlock(ctlr);
  497. }
  498. static void
  499. multicast(void* arg, uchar *addr, int on)
  500. {
  501. int port;
  502. Smc91xx*ctlr;
  503. Ether *ether;
  504. ushort x;
  505. USED(addr, on);
  506. ether = arg;
  507. port = ether->port;
  508. ctlr = ether->ctlr;
  509. ilock(ctlr);
  510. SELECT_BANK(0);
  511. x = ins(port + Rcr);
  512. if (ether->nmaddr)
  513. x |= RcrAllMcast;
  514. else
  515. x &= ~RcrAllMcast;
  516. outs(port + Rcr, x);
  517. iunlock(ctlr);
  518. }
  519. static long
  520. ifstat(Ether* ether, void* a, long n, ulong offset)
  521. {
  522. static char *chiprev[] = {
  523. [3] "92",
  524. [5] "95",
  525. [7] "100",
  526. [8] "100-FD",
  527. [9] "110",
  528. };
  529. Smc91xx* ctlr;
  530. char* p;
  531. int r, len;
  532. char* s;
  533. if (n == 0)
  534. return 0;
  535. ctlr = ether->ctlr;
  536. p = malloc(READSTR);
  537. s = 0;
  538. if (ctlr->rev > 0) {
  539. r = ctlr->rev >> 4;
  540. if (r < nelem(chiprev))
  541. s = chiprev[r];
  542. if (r == 4) {
  543. if ((ctlr->rev & 0x0F) >= 6)
  544. s = "96";
  545. else
  546. s = "94";
  547. }
  548. }
  549. len = snprint(p, READSTR, "rev: 91c%s\n", (s) ? s : "???");
  550. len += snprint(p + len, READSTR - len, "rxovrn: %uld\n", ctlr->rovrn);
  551. len += snprint(p + len, READSTR - len, "lcar: %uld\n", ctlr->lcar);
  552. len += snprint(p + len, READSTR - len, "col: %uld\n", ctlr->col);
  553. len += snprint(p + len, READSTR - len, "16col: %uld\n", ctlr->scol);
  554. len += snprint(p + len, READSTR - len, "mcol: %uld\n", ctlr->mcol);
  555. len += snprint(p + len, READSTR - len, "lcol: %uld\n", ctlr->lcol);
  556. len += snprint(p + len, READSTR - len, "dfr: %uld\n", ctlr->dfr);
  557. USED(len);
  558. n = readstr(offset, a, n, p);
  559. free(p);
  560. return n;
  561. }
  562. static int
  563. reset(Ether* ether)
  564. {
  565. int port;
  566. int i, x;
  567. char* type;
  568. Smc91xx* ctlr;
  569. int slot;
  570. uchar ea[Eaddrlen];
  571. if (ether->irq == 0)
  572. ether->irq = 9;
  573. if (ether->port == 0)
  574. ether->port = 0x100;
  575. type = "8020";
  576. for(i = 0; i < ether->nopt; i++) {
  577. if (cistrncmp(ether->opt[i], "id=", 3))
  578. continue;
  579. type = &ether->opt[i][3];
  580. break;
  581. }
  582. if ((slot = pcmspecial(type, ether)) < 0)
  583. return -1;
  584. if (ioalloc(ether->port, IoSize, 0, "smc91cXX") < 0) {
  585. pcmspecialclose(slot);
  586. return -1;
  587. }
  588. ether->ctlr = malloc(sizeof(Smc91xx));
  589. ctlr = ether->ctlr;
  590. if (ctlr == 0) {
  591. iofree(ether->port);
  592. pcmspecialclose(slot);
  593. return -1;
  594. }
  595. ilock(ctlr);
  596. ctlr->rev = 0;
  597. ctlr->txbp = nil;
  598. ctlr->attached = 0;
  599. ctlr->rovrn = 0;
  600. ctlr->lcar = 0;
  601. ctlr->col = 0;
  602. ctlr->scol = 0;
  603. ctlr->mcol = 0;
  604. ctlr->lcol = 0;
  605. ctlr->dfr = 0;
  606. port = ether->port;
  607. SELECT_BANK(1);
  608. if ((ins(port + BankSelect) & BsrMask) != BsrId) {
  609. outs(port + Control, 0); /* try powering up the chip */
  610. delay(55);
  611. }
  612. outs(port + Config, ins(port + Config) | Cfg16Bit);
  613. x = ins(port + BaseAddr);
  614. if (((ins(port + BankSelect) & BsrMask) != BsrId) ||
  615. ((x >> 8) == (x & 0xFF))) {
  616. iunlock(ctlr);
  617. iofree(port);
  618. pcmspecialclose(slot);
  619. return -1;
  620. }
  621. SELECT_BANK(3);
  622. ctlr->rev = ins(port + Revision) & 0xFF;
  623. memset(ea, 0, Eaddrlen);
  624. if (memcmp(ea, ether->ea, Eaddrlen) == 0) {
  625. if (readnodeid(slot, ether) < 0) {
  626. print("Smc91cXX: cannot find ethernet address\n");
  627. iunlock(ctlr);
  628. iofree(port);
  629. pcmspecialclose(slot);
  630. return -1;
  631. }
  632. }
  633. chipreset(ether);
  634. ether->attach = attach;
  635. ether->transmit = transmit;
  636. ether->interrupt = interrupt;
  637. ether->ifstat = ifstat;
  638. ether->promiscuous = promiscuous;
  639. ether->multicast = multicast;
  640. ether->arg = ether;
  641. iunlock(ctlr);
  642. return 0;
  643. }
  644. void
  645. ethersmclink(void)
  646. {
  647. addethercard("smc91cXX", reset);
  648. }