if_cnw.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /* $OpenBSD: if_cnw.c,v 1.32 2015/07/08 07:21:50 mpi Exp $ */
  2. /*-
  3. * Copyright (c) 1998 The NetBSD Foundation, Inc.
  4. * All rights reserved.
  5. *
  6. * This code is derived from software contributed to The NetBSD Foundation
  7. * by Michael Eriksson.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  20. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  22. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /*
  31. * This is a driver for the Xircom CreditCard Netwave (also known as
  32. * the Netwave Airsurfer) wireless LAN PCMCIA adapter.
  33. *
  34. * When this driver was developed, the Linux Netwave driver was used
  35. * as a hardware manual. That driver is Copyright (c) 1997 University
  36. * of Tromsø, Norway. It is part of the Linux pcmcia-cs package that
  37. * can be found at http://pcmcia-cs.sourceforge.net/. The most
  38. * recent version of the pcmcia-cs package when this driver was
  39. * written was 3.0.6.
  40. *
  41. * Unfortunately, a lot of explicit numeric constants were used in the
  42. * Linux driver. I have tried to use symbolic names whenever possible,
  43. * but since I don't have any real hardware documentation, there's
  44. * still one or two "magic numbers" :-(.
  45. *
  46. * Driver limitations: This driver doesn't do multicasting or receiver
  47. * promiscuity, because of missing hardware documentation. I couldn't
  48. * get receiver promiscuity to work, and I haven't even tried
  49. * multicast. Volunteers are welcome, of course :-).
  50. */
  51. #include "bpfilter.h"
  52. #include <sys/param.h>
  53. #include <sys/systm.h>
  54. #include <sys/device.h>
  55. #include <sys/socket.h>
  56. #include <sys/mbuf.h>
  57. #include <sys/ioctl.h>
  58. #include <dev/pcmcia/if_cnwreg.h>
  59. #include <dev/pcmcia/pcmciavar.h>
  60. #include <dev/pcmcia/pcmciadevs.h>
  61. #include <net/if.h>
  62. #include <net/if_dl.h>
  63. #include <netinet/in.h>
  64. #include <netinet/if_ether.h>
  65. #if NBPFILTER > 0
  66. #include <net/bpf.h>
  67. #endif
  68. /*
  69. * Let these be patchable variables, initialized from macros that can
  70. * be set in the kernel config file. Someone with lots of spare time
  71. * could probably write a nice Netwave configuration program to do
  72. * this a little bit more elegantly :-).
  73. */
  74. #ifndef CNW_DOMAIN
  75. #define CNW_DOMAIN 0x100
  76. #endif
  77. int cnw_domain = CNW_DOMAIN; /* Domain */
  78. #ifndef CNW_SCRAMBLEKEY
  79. #define CNW_SCRAMBLEKEY 0
  80. #endif
  81. int cnw_skey = CNW_SCRAMBLEKEY; /* Scramble key */
  82. int cnw_match(struct device *, void *, void *);
  83. void cnw_attach(struct device *, struct device *, void *);
  84. int cnw_detach(struct device *, int);
  85. int cnw_activate(struct device *, int);
  86. struct cnw_softc {
  87. struct device sc_dev; /* Device glue (must be first) */
  88. struct arpcom sc_arpcom; /* Ethernet common part */
  89. int sc_domain; /* Netwave domain */
  90. int sc_skey; /* Netwave scramble key */
  91. /* PCMCIA-specific stuff */
  92. struct pcmcia_function *sc_pf; /* PCMCIA function */
  93. struct pcmcia_io_handle sc_pcioh; /* PCMCIA I/O space handle */
  94. int sc_iowin; /* ...window */
  95. bus_space_tag_t sc_iot; /* ...bus_space tag */
  96. bus_space_handle_t sc_ioh; /* ...bus_space handle */
  97. struct pcmcia_mem_handle sc_pcmemh; /* PCMCIA memory handle */
  98. bus_addr_t sc_memoff; /* ...offset */
  99. int sc_memwin; /* ...window */
  100. bus_space_tag_t sc_memt; /* ...bus_space tag */
  101. bus_space_handle_t sc_memh; /* ...bus_space handle */
  102. void *sc_ih; /* Interrupt cookie */
  103. };
  104. struct cfattach cnw_ca = {
  105. sizeof(struct cnw_softc), cnw_match, cnw_attach,
  106. cnw_detach, cnw_activate
  107. };
  108. struct cfdriver cnw_cd = {
  109. NULL, "cnw", DV_IFNET
  110. };
  111. void cnw_reset(struct cnw_softc *);
  112. void cnw_init(struct cnw_softc *);
  113. int cnw_enable(struct cnw_softc *sc);
  114. void cnw_disable(struct cnw_softc *sc);
  115. void cnw_config(struct cnw_softc *sc, u_int8_t *);
  116. void cnw_start(struct ifnet *);
  117. void cnw_transmit(struct cnw_softc *, struct mbuf *);
  118. struct mbuf *cnw_read(struct cnw_softc *);
  119. void cnw_recv(struct cnw_softc *);
  120. int cnw_intr(void *arg);
  121. int cnw_ioctl(struct ifnet *, u_long, caddr_t);
  122. void cnw_watchdog(struct ifnet *);
  123. /* ---------------------------------------------------------------- */
  124. /* Help routines */
  125. static int wait_WOC(struct cnw_softc *, int);
  126. static int read16(struct cnw_softc *, int);
  127. static int cnw_cmd(struct cnw_softc *, int, int, int, int);
  128. /*
  129. * Wait until the WOC (Write Operation Complete) bit in the
  130. * ASR (Adapter Status Register) is asserted.
  131. */
  132. static int
  133. wait_WOC(sc, line)
  134. struct cnw_softc *sc;
  135. int line;
  136. {
  137. int i, asr;
  138. for (i = 0; i < 5000; i++) {
  139. asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
  140. if (asr & CNW_ASR_WOC)
  141. return (0);
  142. DELAY(100);
  143. }
  144. if (line > 0)
  145. printf("%s: wedged at line %d\n", sc->sc_dev.dv_xname, line);
  146. return (1);
  147. }
  148. #define WAIT_WOC(sc) wait_WOC(sc, __LINE__)
  149. /*
  150. * Read a 16 bit value from the card.
  151. */
  152. static int
  153. read16(sc, offset)
  154. struct cnw_softc *sc;
  155. int offset;
  156. {
  157. int hi, lo;
  158. /* This could presumably be done more efficient with
  159. * bus_space_read_2(), but I don't know anything about the
  160. * byte sex guarantees... Besides, this is pretty cheap as
  161. * well :-)
  162. */
  163. lo = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  164. sc->sc_memoff + offset);
  165. hi = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  166. sc->sc_memoff + offset + 1);
  167. return ((hi << 8) | lo);
  168. }
  169. /*
  170. * Send a command to the card by writing it to the command buffer.
  171. */
  172. int
  173. cnw_cmd(sc, cmd, count, arg1, arg2)
  174. struct cnw_softc *sc;
  175. int cmd, count, arg1, arg2;
  176. {
  177. int ptr = sc->sc_memoff + CNW_EREG_CB;
  178. if (wait_WOC(sc, 0)) {
  179. printf("%s: wedged when issuing cmd 0x%x\n",
  180. sc->sc_dev.dv_xname, cmd);
  181. /*
  182. * We'll continue anyway, as that's probably the best
  183. * thing we can do; at least the user knows there's a
  184. * problem, and can reset the interface with ifconfig
  185. * down/up.
  186. */
  187. }
  188. bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr, cmd);
  189. if (count > 0) {
  190. bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr + 1, arg1);
  191. if (count > 1)
  192. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  193. ptr + 2, arg2);
  194. }
  195. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  196. ptr + count + 1, CNW_CMD_EOC);
  197. return (0);
  198. }
  199. #define CNW_CMD0(sc, cmd) \
  200. do { cnw_cmd(sc, cmd, 0, 0, 0); } while (0)
  201. #define CNW_CMD1(sc, cmd, arg1) \
  202. do { cnw_cmd(sc, cmd, 1, arg1 , 0); } while (0)
  203. #define CNW_CMD2(sc, cmd, arg1, arg2) \
  204. do { cnw_cmd(sc, cmd, 2, arg1, arg2); } while (0)
  205. /* ---------------------------------------------------------------- */
  206. /*
  207. * Reset the hardware.
  208. */
  209. void
  210. cnw_reset(sc)
  211. struct cnw_softc *sc;
  212. {
  213. #ifdef CNW_DEBUG
  214. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  215. printf("%s: resetting\n", sc->sc_dev.dv_xname);
  216. #endif
  217. wait_WOC(sc, 0);
  218. bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, CNW_PMR_RESET);
  219. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  220. sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_WOC);
  221. bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, 0);
  222. }
  223. /*
  224. * Initialize the card.
  225. */
  226. void
  227. cnw_init(sc)
  228. struct cnw_softc *sc;
  229. {
  230. /* Reset the card */
  231. cnw_reset(sc);
  232. /* Issue a NOP to check the card */
  233. CNW_CMD0(sc, CNW_CMD_NOP);
  234. /* Set up receive configuration */
  235. CNW_CMD1(sc, CNW_CMD_SRC, CNW_RXCONF_RXENA | CNW_RXCONF_BCAST);
  236. /* Set up transmit configuration */
  237. CNW_CMD1(sc, CNW_CMD_STC, CNW_TXCONF_TXENA);
  238. /* Set domain */
  239. CNW_CMD2(sc, CNW_CMD_SMD, sc->sc_domain, sc->sc_domain >> 8);
  240. /* Set scramble key */
  241. CNW_CMD2(sc, CNW_CMD_SSK, sc->sc_skey, sc->sc_skey >> 8);
  242. /* Enable interrupts */
  243. WAIT_WOC(sc);
  244. bus_space_write_1(sc->sc_iot, sc->sc_ioh,
  245. CNW_REG_IMR, CNW_IMR_IENA | CNW_IMR_RFU1);
  246. /* Enable receiver */
  247. CNW_CMD0(sc, CNW_CMD_ER);
  248. /* "Set the IENA bit in COR" */
  249. WAIT_WOC(sc);
  250. bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_COR,
  251. CNW_COR_IENA | CNW_COR_LVLREQ);
  252. }
  253. /*
  254. * Enable and initialize the card.
  255. */
  256. int
  257. cnw_enable(sc)
  258. struct cnw_softc *sc;
  259. {
  260. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  261. sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
  262. cnw_intr, sc, sc->sc_dev.dv_xname);
  263. if (sc->sc_ih == NULL) {
  264. printf("%s: couldn't establish interrupt handler\n",
  265. sc->sc_dev.dv_xname);
  266. return (EIO);
  267. }
  268. if (pcmcia_function_enable(sc->sc_pf) != 0) {
  269. printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
  270. return (EIO);
  271. }
  272. cnw_init(sc);
  273. ifp->if_flags |= IFF_RUNNING;
  274. return (0);
  275. }
  276. /*
  277. * Stop and disable the card.
  278. */
  279. void
  280. cnw_disable(sc)
  281. struct cnw_softc *sc;
  282. {
  283. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  284. pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  285. pcmcia_function_disable(sc->sc_pf);
  286. ifp->if_flags &= ~IFF_RUNNING;
  287. ifp->if_timer = 0;
  288. }
  289. /*
  290. * Match the hardware we handle.
  291. */
  292. int
  293. cnw_match(parent, match, aux)
  294. struct device *parent;
  295. void *match, *aux;
  296. {
  297. struct pcmcia_attach_args *pa = aux;
  298. if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
  299. pa->product == PCMCIA_PRODUCT_XIRCOM_XIR_CNW_801)
  300. return (1);
  301. if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
  302. pa->product == PCMCIA_PRODUCT_XIRCOM_XIR_CNW_802)
  303. return (1);
  304. return (0);
  305. }
  306. /*
  307. * Attach the card.
  308. */
  309. void
  310. cnw_attach(parent, self, aux)
  311. struct device *parent, *self;
  312. void *aux;
  313. {
  314. struct cnw_softc *sc = (void *) self;
  315. struct pcmcia_attach_args *pa = aux;
  316. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  317. int i;
  318. /* Enable the card */
  319. sc->sc_pf = pa->pf;
  320. pcmcia_function_init(sc->sc_pf, SIMPLEQ_FIRST(&sc->sc_pf->cfe_head));
  321. if (pcmcia_function_enable(sc->sc_pf)) {
  322. printf(": function enable failed\n");
  323. return;
  324. }
  325. /* Map I/O register and "memory" */
  326. if (pcmcia_io_alloc(sc->sc_pf, 0, CNW_IO_SIZE, CNW_IO_SIZE,
  327. &sc->sc_pcioh) != 0) {
  328. printf(": can't allocate i/o space\n");
  329. return;
  330. }
  331. if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, 0,
  332. CNW_IO_SIZE, &sc->sc_pcioh, &sc->sc_iowin) != 0) {
  333. printf(": can't map i/o space\n");
  334. return;
  335. }
  336. sc->sc_iot = sc->sc_pcioh.iot;
  337. sc->sc_ioh = sc->sc_pcioh.ioh;
  338. if (pcmcia_mem_alloc(sc->sc_pf, CNW_MEM_SIZE, &sc->sc_pcmemh) != 0) {
  339. printf(": can't allocate memory\n");
  340. return;
  341. }
  342. if (pcmcia_mem_map(sc->sc_pf, PCMCIA_MEM_COMMON, CNW_MEM_ADDR,
  343. CNW_MEM_SIZE, &sc->sc_pcmemh, &sc->sc_memoff,
  344. &sc->sc_memwin) != 0) {
  345. printf(": can't map mem space\n");
  346. return;
  347. }
  348. sc->sc_memt = sc->sc_pcmemh.memt;
  349. sc->sc_memh = sc->sc_pcmemh.memh;
  350. /* Finish setup of softc */
  351. sc->sc_domain = cnw_domain;
  352. sc->sc_skey = cnw_skey;
  353. /* Get MAC address */
  354. cnw_reset(sc);
  355. for (i = 0; i < ETHER_ADDR_LEN; i++)
  356. sc->sc_arpcom.ac_enaddr[i] = bus_space_read_1(sc->sc_memt,
  357. sc->sc_memh, sc->sc_memoff + CNW_EREG_PA + i);
  358. printf("%s: address %s\n", sc->sc_dev.dv_xname,
  359. ether_sprintf(sc->sc_arpcom.ac_enaddr));
  360. /* Set up ifnet structure */
  361. bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  362. ifp->if_softc = sc;
  363. ifp->if_start = cnw_start;
  364. ifp->if_ioctl = cnw_ioctl;
  365. ifp->if_watchdog = cnw_watchdog;
  366. ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  367. IFQ_SET_READY(&ifp->if_snd);
  368. /* Attach the interface */
  369. if_attach(ifp);
  370. ether_ifattach(ifp);
  371. if_addgroup(ifp, "wlan");
  372. ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY;
  373. /* Disable the card now, and turn it on when the interface goes up */
  374. pcmcia_function_disable(sc->sc_pf);
  375. }
  376. /*
  377. * Start outputting on the interface.
  378. */
  379. void
  380. cnw_start(ifp)
  381. struct ifnet *ifp;
  382. {
  383. struct cnw_softc *sc = ifp->if_softc;
  384. struct mbuf *m0;
  385. int asr;
  386. #ifdef CNW_DEBUG
  387. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  388. printf("%s: cnw_start\n", ifp->if_xname);
  389. #endif
  390. for (;;) {
  391. /* Is there any buffer space available on the card? */
  392. WAIT_WOC(sc);
  393. asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
  394. if (!(asr & CNW_ASR_TXBA)) {
  395. #ifdef CNW_DEBUG
  396. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  397. printf("%s: no buffer space\n", ifp->if_xname);
  398. #endif
  399. return;
  400. }
  401. IFQ_DEQUEUE(&ifp->if_snd, m0);
  402. if (m0 == NULL)
  403. return;
  404. #if NBPFILTER > 0
  405. if (ifp->if_bpf)
  406. bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
  407. #endif
  408. cnw_transmit(sc, m0);
  409. ++ifp->if_opackets;
  410. ifp->if_timer = 3; /* start watchdog timer */
  411. }
  412. }
  413. /*
  414. * Transmit a packet.
  415. */
  416. void
  417. cnw_transmit(sc, m0)
  418. struct cnw_softc *sc;
  419. struct mbuf *m0;
  420. {
  421. int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n;
  422. struct mbuf *m;
  423. u_int8_t *mptr;
  424. /* Get buffer info from card */
  425. buffer = read16(sc, CNW_EREG_TDP);
  426. bufsize = read16(sc, CNW_EREG_TDP + 2);
  427. bufoffset = read16(sc, CNW_EREG_TDP + 4);
  428. #ifdef CNW_DEBUG
  429. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  430. printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n",
  431. sc->sc_dev.dv_xname, buffer, bufsize, bufoffset);
  432. #endif
  433. /* Copy data from mbuf chain to card buffers */
  434. bufptr = sc->sc_memoff + buffer + bufoffset;
  435. bufspace = bufsize;
  436. len = 0;
  437. for (m = m0; m; ) {
  438. mptr = mtod(m, u_int8_t *);
  439. mbytes = m->m_len;
  440. len += mbytes;
  441. while (mbytes > 0) {
  442. if (bufspace == 0) {
  443. buffer = read16(sc, buffer);
  444. bufptr = sc->sc_memoff + buffer + bufoffset;
  445. bufspace = bufsize;
  446. #ifdef CNW_DEBUG
  447. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  448. printf("%s: next buffer @0x%x\n",
  449. sc->sc_dev.dv_xname, buffer);
  450. #endif
  451. }
  452. n = mbytes <= bufspace ? mbytes : bufspace;
  453. bus_space_write_region_1(sc->sc_memt, sc->sc_memh,
  454. bufptr, mptr, n);
  455. bufptr += n;
  456. bufspace -= n;
  457. mptr += n;
  458. mbytes -= n;
  459. }
  460. m0 = m_free(m);
  461. m = m0;
  462. }
  463. /* Issue transmit command */
  464. CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8);
  465. }
  466. /*
  467. * Pull a packet from the card into an mbuf chain.
  468. */
  469. struct mbuf *
  470. cnw_read(sc)
  471. struct cnw_softc *sc;
  472. {
  473. struct mbuf *m, *top, **mp;
  474. int totbytes, buffer, bufbytes, bufptr, mbytes, n;
  475. u_int8_t *mptr;
  476. WAIT_WOC(sc);
  477. totbytes = read16(sc, CNW_EREG_RDP);
  478. #ifdef CNW_DEBUG
  479. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  480. printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes);
  481. #endif
  482. buffer = CNW_EREG_RDP + 2;
  483. bufbytes = 0;
  484. bufptr = 0; /* XXX make gcc happy */
  485. MGETHDR(m, M_DONTWAIT, MT_DATA);
  486. if (m == NULL)
  487. return (0);
  488. m->m_pkthdr.len = totbytes;
  489. mbytes = MHLEN;
  490. top = 0;
  491. mp = &top;
  492. while (totbytes > 0) {
  493. if (top) {
  494. MGET(m, M_DONTWAIT, MT_DATA);
  495. if (m == NULL) {
  496. m_freem(top);
  497. return (0);
  498. }
  499. mbytes = MLEN;
  500. }
  501. if (totbytes >= MINCLSIZE) {
  502. MCLGET(m, M_DONTWAIT);
  503. if ((m->m_flags & M_EXT) == 0) {
  504. m_free(m);
  505. m_freem(top);
  506. return (0);
  507. }
  508. mbytes = MCLBYTES;
  509. }
  510. if (!top) {
  511. int pad =
  512. ALIGN(sizeof(struct ether_header)) -
  513. sizeof(struct ether_header);
  514. m->m_data += pad;
  515. mbytes -= pad;
  516. }
  517. mptr = mtod(m, u_int8_t *);
  518. mbytes = m->m_len = min(totbytes, mbytes);
  519. totbytes -= mbytes;
  520. while (mbytes > 0) {
  521. if (bufbytes == 0) {
  522. buffer = read16(sc, buffer);
  523. bufbytes = read16(sc, buffer + 2);
  524. bufptr = sc->sc_memoff + buffer +
  525. read16(sc, buffer + 4);
  526. #ifdef CNW_DEBUG
  527. if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  528. printf("%s: %d bytes @0x%x+0x%x\n",
  529. sc->sc_dev.dv_xname, bufbytes,
  530. buffer, bufptr - buffer -
  531. sc->sc_memoff);
  532. #endif
  533. }
  534. n = mbytes <= bufbytes ? mbytes : bufbytes;
  535. bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
  536. bufptr, mptr, n);
  537. bufbytes -= n;
  538. bufptr += n;
  539. mbytes -= n;
  540. mptr += n;
  541. }
  542. *mp = m;
  543. mp = &m->m_next;
  544. }
  545. return (top);
  546. }
  547. /*
  548. * Handle received packets.
  549. */
  550. void
  551. cnw_recv(sc)
  552. struct cnw_softc *sc;
  553. {
  554. int rser;
  555. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  556. struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  557. struct mbuf *m;
  558. for (;;) {
  559. WAIT_WOC(sc);
  560. rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  561. sc->sc_memoff + CNW_EREG_RSER);
  562. if (!(rser & CNW_RSER_RXAVAIL))
  563. break;
  564. /* Pull packet off card */
  565. m = cnw_read(sc);
  566. /* Acknowledge packet */
  567. CNW_CMD0(sc, CNW_CMD_SRP);
  568. /* Did we manage to get the packet from the interface? */
  569. if (m == NULL) {
  570. ++ifp->if_ierrors;
  571. break;
  572. }
  573. ml_enqueue(&ml, m);
  574. }
  575. if_input(ifp, &ml);
  576. }
  577. /*
  578. * Interrupt handler.
  579. */
  580. int
  581. cnw_intr(arg)
  582. void *arg;
  583. {
  584. struct cnw_softc *sc = arg;
  585. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  586. int ret, status, rser, tser;
  587. if (!(sc->sc_arpcom.ac_if.if_flags & IFF_RUNNING))
  588. return (0);
  589. ifp->if_timer = 0; /* stop watchdog timer */
  590. ret = 0;
  591. for (;;) {
  592. WAIT_WOC(sc);
  593. if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh,
  594. CNW_REG_CCSR) & 0x02)) {
  595. if (ret == 0)
  596. printf("%s: spurious interrupt\n",
  597. sc->sc_dev.dv_xname);
  598. return (ret);
  599. }
  600. ret = 1;
  601. status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
  602. /* Anything to receive? */
  603. if (status & CNW_ASR_RXRDY)
  604. cnw_recv(sc);
  605. /* Receive error */
  606. if (status & CNW_ASR_RXERR) {
  607. /*
  608. * I get a *lot* of spurious receive errors
  609. * (many per second), even when the interface
  610. * is quiescent, so we don't increment
  611. * if_ierrors here.
  612. */
  613. rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  614. sc->sc_memoff + CNW_EREG_RSER);
  615. /* Clear error bits in RSER */
  616. WAIT_WOC(sc);
  617. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  618. sc->sc_memoff + CNW_EREG_RSERW,
  619. CNW_RSER_RXERR |
  620. (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG)));
  621. /* Clear RXERR in ASR */
  622. WAIT_WOC(sc);
  623. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  624. sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR);
  625. }
  626. /* Transmit done */
  627. if (status & CNW_ASR_TXDN) {
  628. tser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  629. CNW_EREG_TSER);
  630. if (tser & CNW_TSER_TXOK) {
  631. WAIT_WOC(sc);
  632. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  633. sc->sc_memoff + CNW_EREG_TSERW,
  634. CNW_TSER_TXOK | CNW_TSER_RTRY);
  635. }
  636. if (tser & CNW_TSER_ERROR) {
  637. ++ifp->if_oerrors;
  638. WAIT_WOC(sc);
  639. bus_space_write_1(sc->sc_memt, sc->sc_memh,
  640. sc->sc_memoff + CNW_EREG_TSERW,
  641. (tser & CNW_TSER_ERROR) |
  642. CNW_TSER_RTRY);
  643. }
  644. /* Continue to send packets from the queue */
  645. cnw_start(&sc->sc_arpcom.ac_if);
  646. }
  647. }
  648. }
  649. /*
  650. * Handle device ioctls.
  651. */
  652. int
  653. cnw_ioctl(ifp, cmd, data)
  654. register struct ifnet *ifp;
  655. u_long cmd;
  656. caddr_t data;
  657. {
  658. struct cnw_softc *sc = ifp->if_softc;
  659. struct ifaddr *ifa = (struct ifaddr *)data;
  660. int s, error = 0;
  661. s = splnet();
  662. switch (cmd) {
  663. case SIOCSIFADDR:
  664. if (!(ifp->if_flags & IFF_RUNNING) &&
  665. (error = cnw_enable(sc)) != 0)
  666. break;
  667. ifp->if_flags |= IFF_UP;
  668. switch (ifa->ifa_addr->sa_family) {
  669. case AF_INET:
  670. arp_ifinit(&sc->sc_arpcom, ifa);
  671. break;
  672. }
  673. break;
  674. case SIOCSIFFLAGS:
  675. if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) {
  676. /*
  677. * The interface is marked down and it is running, so
  678. * stop it.
  679. */
  680. cnw_disable(sc);
  681. } else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){
  682. /*
  683. * The interface is marked up and it is stopped, so
  684. * start it.
  685. */
  686. error = cnw_enable(sc);
  687. }
  688. break;
  689. default:
  690. error = ENOTTY;
  691. break;
  692. }
  693. splx(s);
  694. return (error);
  695. }
  696. /*
  697. * Device timeout/watchdog routine. Entered if the device neglects to
  698. * generate an interrupt after a transmit has been started on it.
  699. */
  700. void
  701. cnw_watchdog(ifp)
  702. struct ifnet *ifp;
  703. {
  704. struct cnw_softc *sc = ifp->if_softc;
  705. printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname);
  706. ++ifp->if_oerrors;
  707. cnw_init(sc);
  708. }
  709. int
  710. cnw_detach(dev, flags)
  711. struct device *dev;
  712. int flags;
  713. {
  714. struct cnw_softc *sc = (struct cnw_softc *)dev;
  715. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  716. int rv = 0;
  717. pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
  718. pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
  719. pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
  720. pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
  721. ether_ifdetach(ifp);
  722. if_detach(ifp);
  723. return (rv);
  724. }
  725. int
  726. cnw_activate(dev, act)
  727. struct device *dev;
  728. int act;
  729. {
  730. struct cnw_softc *sc = (struct cnw_softc *)dev;
  731. struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  732. switch (act) {
  733. case DVACT_DEACTIVATE:
  734. ifp->if_timer = 0;
  735. ifp->if_flags &= ~IFF_RUNNING; /* XXX no cnw_stop() ? */
  736. if (sc->sc_ih)
  737. pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  738. sc->sc_ih = NULL;
  739. pcmcia_function_disable(sc->sc_pf);
  740. break;
  741. }
  742. return (0);
  743. }