ethersmc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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 {
  187. Lock;
  188. ushort rev;
  189. int attached;
  190. Block *txbp;
  191. ulong txtime;
  192. ulong rovrn;
  193. ulong lcar;
  194. ulong col;
  195. ulong scol;
  196. ulong mcol;
  197. ulong lcol;
  198. ulong dfr;
  199. } Smc91xx;
  200. #define SELECT_BANK(x) outs(port + BankSelect, x)
  201. static int
  202. readnodeid(int slot, Ether* ether)
  203. {
  204. uchar data[Eaddrlen + 1];
  205. int len;
  206. len = sizeof(data);
  207. if (pcmcistuple(slot, TupleFunce, TfNodeId, data, len) != len)
  208. return -1;
  209. if (data[0] != Eaddrlen)
  210. return -1;
  211. memmove(ether->ea, &data[1], Eaddrlen);
  212. return 0;
  213. }
  214. static void
  215. chipreset(Ether* ether)
  216. {
  217. int port;
  218. int i;
  219. port = ether->port;
  220. /* reset the chip */
  221. SELECT_BANK(0);
  222. outs(port + Rcr, RcrSoftReset);
  223. delay(1);
  224. outs(port + Rcr, RcrClear);
  225. outs(port + Tcr, TcrClear);
  226. SELECT_BANK(1);
  227. outs(port + Control, CtlAutoRls | CtlTeEnable |
  228. CtlCrEnable);
  229. for(i = 0; i < 6; i++) {
  230. outb(port + Addr0 + i, ether->ea[i]);
  231. }
  232. SELECT_BANK(2);
  233. outs(port + MmuCmd, McReset);
  234. }
  235. static void
  236. chipenable(Ether* ether)
  237. {
  238. int port;
  239. port = ether->port;
  240. SELECT_BANK(0);
  241. outs(port + Tcr, TcrNormal);
  242. outs(port + Rcr, RcrNormal);
  243. SELECT_BANK(2);
  244. outb(port + IntrMask, IntEph | IntRxOvrn | IntRcv);
  245. }
  246. static void
  247. attach(Ether *ether)
  248. {
  249. Smc91xx* ctlr;
  250. ctlr = ether->ctlr;
  251. ilock(ctlr);
  252. if (ctlr->attached) {
  253. iunlock(ctlr);
  254. return;
  255. }
  256. chipenable(ether);
  257. ctlr->attached = 1;
  258. iunlock(ctlr);
  259. }
  260. static void
  261. txstart(Ether* ether)
  262. {
  263. int port;
  264. Smc91xx* ctlr;
  265. Block* bp;
  266. int len, npages;
  267. int pno;
  268. /* assumes ctlr is locked and bank 2 is selected */
  269. /* leaves bank 2 selected on return */
  270. port = ether->port;
  271. ctlr = ether->ctlr;
  272. if (ctlr->txbp) {
  273. bp = ctlr->txbp;
  274. ctlr->txbp = 0;
  275. } else {
  276. bp = qget(ether->oq);
  277. if (bp == 0)
  278. return;
  279. len = BLEN(bp);
  280. npages = (len + HdrSize) / PageSize;
  281. outs(port + MmuCmd, McAlloc | npages);
  282. }
  283. pno = inb(port + AllocRes);
  284. if (pno & ArFailed) {
  285. outb(port + IntrMask, inb(port + IntrMask) | IntAlloc);
  286. ctlr->txbp = bp;
  287. ctlr->txtime = MACHP(0)->ticks;
  288. return;
  289. }
  290. outb(port + PktNo, pno);
  291. outs(port + Pointer, PtrAutoInc);
  292. len = BLEN(bp);
  293. outs(port + Data1, 0);
  294. outb(port + Data1, (len + HdrSize) & 0xFF);
  295. outb(port + Data1, (len + HdrSize) >> 8);
  296. outss(port + Data1, bp->rp, len / 2);
  297. if ((len & 1) == 0) {
  298. outs(port + Data1, 0);
  299. } else {
  300. outb(port + Data1, bp->rp[len - 1]);
  301. outb(port + Data1, 0x20); /* no info what 0x20 means */
  302. }
  303. outb(port + IntrMask, inb(port + IntrMask) |
  304. IntTxError | IntTxEmpty);
  305. outs(port + MmuCmd, McEnqueue);
  306. freeb(bp);
  307. }
  308. static void
  309. receive(Ether* ether)
  310. {
  311. int port;
  312. Block* bp;
  313. int pktno, status, len;
  314. /* assumes ctlr is locked and bank 2 is selected */
  315. /* leaves bank 2 selected on return */
  316. port = ether->port;
  317. pktno = ins(port + FifoPorts);
  318. if (pktno & FpRxEmpty) {
  319. return;
  320. }
  321. outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc);
  322. status = ins(port + Data1);
  323. len = ins(port + Data1) & RxLenMask - HdrSize;
  324. if (status & RsOddFrame)
  325. len++;
  326. if ((status & RsError) || (bp = iallocb(len)) == 0) {
  327. if (status & RsAlgnErr)
  328. ether->frames++;
  329. if (status & (RsTooShort | RsTooLong))
  330. ether->buffs++;
  331. if (status & RsBadCrc)
  332. ether->crcs++;
  333. outs(port + MmuCmd, McRelease);
  334. return;
  335. }
  336. /* packet length is padded to word */
  337. inss(port + Data1, bp->rp, len / 2);
  338. bp->wp = bp->rp + (len & ~1);
  339. if (len & 1) {
  340. *bp->wp = inb(port + Data1);
  341. bp->wp++;
  342. }
  343. etheriq(ether, bp, 1);
  344. ether->inpackets++;
  345. outs(port + MmuCmd, McRelease);
  346. }
  347. static void
  348. txerror(Ether* ether)
  349. {
  350. int port;
  351. Smc91xx* ctlr;
  352. int save_pkt;
  353. int pktno, status;
  354. /* assumes ctlr is locked and bank 2 is selected */
  355. /* leaves bank 2 selected on return */
  356. port = ether->port;
  357. ctlr = ether->ctlr;
  358. save_pkt = inb(port + PktNo);
  359. pktno = ins(port + FifoPorts) & FpTxMask;
  360. outb(port + PktNo, pktno);
  361. outs(port + Pointer, PtrAutoInc | PtrRead);
  362. status = ins(port + Data1);
  363. if (status & TsLostCar)
  364. ctlr->lcar++;
  365. if (status & TsLatCol)
  366. ctlr->lcol++;
  367. if (status & Ts16Col)
  368. ctlr->scol++;
  369. ether->oerrs++;
  370. SELECT_BANK(0);
  371. outs(port + Tcr, ins(port + Tcr) | TcrEnable);
  372. SELECT_BANK(2);
  373. outs(port + MmuCmd, McFreePkt);
  374. outb(port + PktNo, save_pkt);
  375. }
  376. static void
  377. eph_irq(Ether* ether)
  378. {
  379. int port;
  380. Smc91xx* ctlr;
  381. ushort status;
  382. int n;
  383. /* assumes ctlr is locked and bank 2 is selected */
  384. /* leaves bank 2 selected on return */
  385. port = ether->port;
  386. ctlr = ether->ctlr;
  387. SELECT_BANK(0);
  388. status = ins(port + Eph);
  389. if (status & EphCntRol) {
  390. /* read the counter register even if we don't need it */
  391. /* otherwise we will keep getting this interrupt */
  392. n = ins(port + Counter);
  393. ctlr->col += (n & CntColMask) >> CntColShr;
  394. ctlr->mcol += (n & CntMColMask) >> CntMColShr;
  395. ctlr->dfr += (n & CntDtxMask) >> CntDtxShr;
  396. }
  397. /* if there was a transmit error, Tcr is disabled */
  398. outs(port + Tcr, ins(port + Tcr) | TcrEnable);
  399. /* clear a link error interrupt */
  400. SELECT_BANK(1);
  401. outs(port + Control, CtlAutoRls);
  402. outs(port + Control, CtlAutoRls | CtlTeEnable | CtlCrEnable);
  403. SELECT_BANK(2);
  404. }
  405. static void
  406. transmit(Ether* ether)
  407. {
  408. Smc91xx* ctlr;
  409. int port, n;
  410. ctlr = ether->ctlr;
  411. port = ether->port;
  412. ilock(ctlr);
  413. if (ctlr->txbp) {
  414. n = TK2MS(MACHP(0)->ticks - ctlr->txtime);
  415. if (n > TxTimeout) {
  416. chipreset(ether);
  417. chipenable(ether);
  418. freeb(ctlr->txbp);
  419. ctlr->txbp = 0;
  420. }
  421. iunlock(ctlr);
  422. return;
  423. }
  424. SELECT_BANK(2);
  425. txstart(ether);
  426. iunlock(ctlr);
  427. }
  428. static void
  429. interrupt(Ureg*, void *arg)
  430. {
  431. int port;
  432. Smc91xx* ctlr;
  433. Ether* ether;
  434. int save_bank;
  435. int save_pointer;
  436. int mask, status;
  437. ether = arg;
  438. port = ether->port;
  439. ctlr = ether->ctlr;
  440. ilock(ctlr);
  441. save_bank = ins(port + BankSelect);
  442. SELECT_BANK(2);
  443. save_pointer = ins(port + Pointer);
  444. mask = inb(port + IntrMask);
  445. outb(port + IntrMask, 0);
  446. while ((status = inb(port + Interrupt) & mask) != 0) {
  447. if (status & IntRcv) {
  448. receive(ether);
  449. }
  450. if (status & IntTxError) {
  451. txerror(ether);
  452. }
  453. if (status & IntTxEmpty) {
  454. outb(port + Interrupt, IntTxEmpty);
  455. outb(port + IntrMask, mask & ~IntTxEmpty);
  456. txstart(ether);
  457. mask = inb(port + IntrMask);
  458. }
  459. if (status & IntAlloc) {
  460. outb(port + IntrMask, mask & ~IntAlloc);
  461. txstart(ether);;
  462. mask = inb(port + IntrMask);
  463. }
  464. if (status & IntRxOvrn) {
  465. ctlr->rovrn++;
  466. ether->misses++;
  467. outb(port + Interrupt,IntRxOvrn);
  468. }
  469. if (status & IntEph)
  470. eph_irq(ether);
  471. }
  472. outb(port + IntrMask, mask);
  473. outs(port + Pointer, save_pointer);
  474. outs(port + BankSelect, save_bank);
  475. iunlock(ctlr);
  476. }
  477. static void
  478. promiscuous(void* arg, int on)
  479. {
  480. int port;
  481. Smc91xx *ctlr;
  482. Ether* ether;
  483. ushort x;
  484. ether = arg;
  485. port = ether->port;
  486. ctlr = ether->ctlr;
  487. ilock(ctlr);
  488. SELECT_BANK(0);
  489. x = ins(port + Rcr);
  490. if (on)
  491. x |= RcrPromisc;
  492. else
  493. x &= ~RcrPromisc;
  494. outs(port + Rcr, x);
  495. iunlock(ctlr);
  496. }
  497. static void
  498. multicast(void* arg, uchar *addr, int on)
  499. {
  500. int port;
  501. Smc91xx*ctlr;
  502. Ether *ether;
  503. ushort x;
  504. USED(addr, on);
  505. ether = arg;
  506. port = ether->port;
  507. ctlr = ether->ctlr;
  508. ilock(ctlr);
  509. SELECT_BANK(0);
  510. x = ins(port + Rcr);
  511. if (ether->nmaddr)
  512. x |= RcrAllMcast;
  513. else
  514. x &= ~RcrAllMcast;
  515. outs(port + Rcr, x);
  516. iunlock(ctlr);
  517. }
  518. static long
  519. ifstat(Ether* ether, void* a, long n, ulong offset)
  520. {
  521. static char *chiprev[] = {
  522. [3] "92",
  523. [5] "95",
  524. [7] "100",
  525. [8] "100-FD",
  526. [9] "110",
  527. };
  528. Smc91xx* ctlr;
  529. char* p;
  530. int r, len;
  531. char* s;
  532. if (n == 0)
  533. return 0;
  534. ctlr = ether->ctlr;
  535. p = malloc(READSTR);
  536. s = 0;
  537. if (ctlr->rev > 0) {
  538. r = ctlr->rev >> 4;
  539. if (r < nelem(chiprev))
  540. s = chiprev[r];
  541. if (r == 4) {
  542. if ((ctlr->rev & 0x0F) >= 6)
  543. s = "96";
  544. else
  545. s = "94";
  546. }
  547. }
  548. len = snprint(p, READSTR, "rev: 91c%s\n", (s) ? s : "???");
  549. len += snprint(p + len, READSTR - len, "rxovrn: %uld\n", ctlr->rovrn);
  550. len += snprint(p + len, READSTR - len, "lcar: %uld\n", ctlr->lcar);
  551. len += snprint(p + len, READSTR - len, "col: %uld\n", ctlr->col);
  552. len += snprint(p + len, READSTR - len, "16col: %uld\n", ctlr->scol);
  553. len += snprint(p + len, READSTR - len, "mcol: %uld\n", ctlr->mcol);
  554. len += snprint(p + len, READSTR - len, "lcol: %uld\n", ctlr->lcol);
  555. len += snprint(p + len, READSTR - len, "dfr: %uld\n", ctlr->dfr);
  556. USED(len);
  557. n = readstr(offset, a, n, p);
  558. free(p);
  559. return n;
  560. }
  561. static int
  562. reset(Ether* ether)
  563. {
  564. int port;
  565. int i, x;
  566. char* type;
  567. Smc91xx* ctlr;
  568. int slot;
  569. uchar ea[Eaddrlen];
  570. if (ether->irq == 0)
  571. ether->irq = 9;
  572. if (ether->port == 0)
  573. ether->port = 0x100;
  574. type = "8020";
  575. for(i = 0; i < ether->nopt; i++) {
  576. if (cistrncmp(ether->opt[i], "id=", 3))
  577. continue;
  578. type = &ether->opt[i][3];
  579. break;
  580. }
  581. if ((slot = pcmspecial(type, ether)) < 0)
  582. return -1;
  583. if (ioalloc(ether->port, IoSize, 0, "smc91cXX") < 0) {
  584. pcmspecialclose(slot);
  585. return -1;
  586. }
  587. ether->ctlr = malloc(sizeof(Smc91xx));
  588. ctlr = ether->ctlr;
  589. if (ctlr == 0) {
  590. iofree(ether->port);
  591. pcmspecialclose(slot);
  592. }
  593. ilock(ctlr);
  594. ctlr->rev = 0;
  595. ctlr->txbp = nil;
  596. ctlr->attached = 0;
  597. ctlr->rovrn = 0;
  598. ctlr->lcar = 0;
  599. ctlr->col = 0;
  600. ctlr->scol = 0;
  601. ctlr->mcol = 0;
  602. ctlr->lcol = 0;
  603. ctlr->dfr = 0;
  604. port = ether->port;
  605. SELECT_BANK(1);
  606. if ((ins(port + BankSelect) & BsrMask) != BsrId) {
  607. outs(port + Control, 0); /* try powering up the chip */
  608. delay(55);
  609. }
  610. outs(port + Config, ins(port + Config) | Cfg16Bit);
  611. x = ins(port + BaseAddr);
  612. if (((ins(port + BankSelect) & BsrMask) != BsrId) ||
  613. ((x >> 8) == (x & 0xFF))) {
  614. iunlock(ctlr);
  615. iofree(port);
  616. pcmspecialclose(slot);
  617. return -1;
  618. }
  619. SELECT_BANK(3);
  620. ctlr->rev = ins(port + Revision) & 0xFF;
  621. memset(ea, 0, Eaddrlen);
  622. if (memcmp(ea, ether->ea, Eaddrlen) == 0) {
  623. if (readnodeid(slot, ether) < 0) {
  624. print("Smc91cXX: cannot find ethernet address\n");
  625. iunlock(ctlr);
  626. iofree(port);
  627. pcmspecialclose(slot);
  628. return -1;
  629. }
  630. }
  631. chipreset(ether);
  632. ether->attach = attach;
  633. ether->transmit = transmit;
  634. ether->interrupt = interrupt;
  635. ether->ifstat = ifstat;
  636. ether->promiscuous = promiscuous;
  637. ether->multicast = multicast;
  638. ether->arg = ether;
  639. iunlock(ctlr);
  640. return 0;
  641. }
  642. void
  643. ethersmclink(void)
  644. {
  645. addethercard("smc91cXX", reset);
  646. }