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