xref: /netbsd-src/sys/arch/mac68k/nubus/if_netdock_nubus.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: if_netdock_nubus.c,v 1.11 2005/12/24 23:24:01 perry Exp $	*/
2 
3 /*
4  * Copyright (C) 2000,2002 Daishi Kato <daishi@axlight.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Daishi Kato
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Asante NetDock (for Duo series) driver
35  * the chip inside is not known
36  */
37 
38 /*
39  * The author would like to thank Takeo Kuwata <tkuwata@mac.com> for
40  * his help in stabilizing this driver.
41  */
42 
43 /***********************/
44 
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: if_netdock_nubus.c,v 1.11 2005/12/24 23:24:01 perry Exp $");
47 
48 #include <sys/param.h>
49 #include <sys/device.h>
50 #include <sys/socket.h>
51 #include <sys/systm.h>
52 #include <sys/mbuf.h>
53 #include <sys/ioctl.h>
54 
55 #include <net/if.h>
56 #include <net/if_dl.h>
57 #include <net/if_ether.h>
58 
59 #include "opt_inet.h"
60 #ifdef INET
61 #include <netinet/in.h>
62 #include <netinet/if_inarp.h>
63 #endif
64 
65 #include "bpfilter.h"
66 #if NBPFILTER > 0
67 #include <net/bpf.h>
68 #endif
69 
70 #include <machine/bus.h>
71 #include <machine/viareg.h>
72 #include <mac68k/nubus/nubus.h>
73 
74 /***********************/
75 
76 #define NETDOCK_DEBUG
77 
78 #define NETDOCK_NUBUS_CATEGORY	0x0020
79 #define NETDOCK_NUBUS_TYPE	0x0003
80 #define NETDOCK_NUBUS_DRSW	0x0103
81 #define NETDOCK_NUBUS_DRHW	0x0100
82 
83 #define ETHERMICRODOCK_NUBUS_CATEGORY	0x0020
84 #define ETHERMICRODOCK_NUBUS_TYPE	0x0003
85 #define ETHERMICRODOCK_NUBUS_DRSW	0x0102
86 #define ETHERMICRODOCK_NUBUS_DRHW	0x0100
87 
88 #define REG_ISR		0x000c
89 #define REG_000E	0x000e
90 #define REG_0000	0x0000
91 #define REG_0002	0x0002
92 #define REG_0004	0x0004
93 #define REG_0006	0x0006
94 #define REG_DATA	0x0008
95 #define REG_EFD00	0xefd00
96 
97 #define ISR_ALL		0x3300
98 #define ISR_TX		0x0200
99 #define ISR_RX		0x0100
100 #define ISR_READY	0x0800
101 #define ISR_BIT_0C	0x1000
102 #define ISR_BIT_0D	0x2000
103 #define ISR_MASK	0x0033
104 #define ISR_BIT_03	0x0008
105 
106 #define REG_0002_BIT_04	0x0010
107 #define REG_0000_BIT_08	0x0100
108 #define REG_0004_BIT_0F	0x8000
109 #define REG_0004_BIT_07 0x0080
110 #define REG_DATA_BIT_02 0x0004
111 #define REG_DATA_BIT_03 0x0008
112 #define REG_DATA_BIT_04 0x0010
113 #define REG_DATA_BIT_05 0x0020
114 #define REG_DATA_BIT_08	0x0100
115 #define REG_DATA_BIT_07	0x0080
116 #define REG_DATA_BIT_0F	0x8000
117 
118 /***********************/
119 
120 typedef struct netdock_softc {
121 	struct device	sc_dev;
122 	struct ethercom	sc_ethercom;
123 #define sc_if		sc_ethercom.ec_if
124 
125 	bus_space_tag_t		sc_regt;
126 	bus_space_handle_t	sc_regh;
127 
128 	u_int8_t	sc_enaddr[ETHER_ADDR_LEN];
129 
130 } netdock_softc_t;
131 
132 /***********************/
133 
134 static int	netdock_nubus_match(struct device *, struct cfdata *, void *);
135 static void	netdock_nubus_attach(struct device *, struct device *, void *);
136 static int	netdock_nb_get_enaddr(bus_space_tag_t, bus_space_handle_t,
137 			struct nubus_attach_args *, u_int8_t *);
138 #ifdef NETDOCK_DEBUG_DRIVER
139 static void	netdock_print_driver(bus_space_tag_t, bus_space_handle_t,
140 			struct nubus_attach_args *);
141 #endif
142 
143 int	netdock_setup(struct netdock_softc *, u_int8_t *);
144 void	netdock_intr(void *);
145 
146 static void	netdock_watchdog(struct ifnet *);
147 static int	netdock_init(struct netdock_softc *);
148 static int	netdock_stop(struct netdock_softc *);
149 static int	netdock_ioctl(struct ifnet *, u_long, caddr_t);
150 static void	netdock_start(struct ifnet *);
151 static void	netdock_reset(struct netdock_softc *);
152 static void	netdock_txint(struct netdock_softc *);
153 static void	netdock_rxint(struct netdock_softc *);
154 
155 static u_int	netdock_put(struct netdock_softc *, struct mbuf *);
156 static int	netdock_read(struct netdock_softc *, int);
157 static struct mbuf *netdock_get(struct netdock_softc *, int);
158 
159 /***********************/
160 
161 #define NIC_GET_1(sc, o)	(bus_space_read_1((sc)->sc_regt,	\
162 					(sc)->sc_regh, (o)))
163 #define NIC_PUT_1(sc, o, val)	(bus_space_write_1((sc)->sc_regt,	\
164 					(sc)->sc_regh, (o), (val)))
165 #define NIC_GET_2(sc, o)	(bus_space_read_2((sc)->sc_regt,	\
166 					(sc)->sc_regh, (o)))
167 #define NIC_PUT_2(sc, o, val)	(bus_space_write_2((sc)->sc_regt,	\
168 					(sc)->sc_regh, (o), (val)))
169 #define NIC_GET_4(sc, o)	(bus_space_read_4((sc)->sc_regt,	\
170 					(sc)->sc_regh, (o)))
171 #define NIC_PUT_4(sc, o, val)	(bus_space_write_4((sc)->sc_regt,	\
172 					(sc)->sc_regh, (o), (val)))
173 
174 #define NIC_BSET(sc, o, b)						\
175 	__asm volatile("bset %0,%1" : : "di" ((u_short)(b)),	\
176 		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
177 #define NIC_BCLR(sc, o, b)						\
178 	__asm volatile("bclr %0,%1" : : "di" ((u_short)(b)),	\
179 		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
180 #define NIC_ANDW(sc, o, b)						\
181 	__asm volatile("andw %0,%1" : : "di" ((u_short)(b)),	\
182 		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
183 #define NIC_ORW(sc, o, b)						\
184 	__asm volatile("orw %0,%1" : : "di" ((u_short)(b)),	\
185 		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
186 
187 
188 /***********************/
189 
190 CFATTACH_DECL(netdock_nubus, sizeof(struct netdock_softc),
191     netdock_nubus_match, netdock_nubus_attach, NULL, NULL);
192 
193 /***********************/
194 
195 static int
196 netdock_nubus_match(struct device *parent, struct cfdata *cf, void *aux)
197 {
198 	struct nubus_attach_args *na = (struct nubus_attach_args *)aux;
199 	bus_space_handle_t bsh;
200 	int rv;
201 
202 	if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot),
203 	    NBMEMSIZE, 0, &bsh))
204 		return (0);
205 
206 	rv = 0;
207 
208 	if (na->category == NETDOCK_NUBUS_CATEGORY &&
209 	    na->type == NETDOCK_NUBUS_TYPE &&
210 	    na->drsw == NETDOCK_NUBUS_DRSW) {
211 		/* assuming this IS Asante NetDock */
212 		rv = 1;
213 	}
214 
215 	if (na->category == ETHERMICRODOCK_NUBUS_CATEGORY &&
216 	    na->type == ETHERMICRODOCK_NUBUS_TYPE &&
217 	    na->drsw == ETHERMICRODOCK_NUBUS_DRSW) {
218 		/* assuming this IS Newer EtherMicroDock */
219 		rv = 1;
220 	}
221 
222 	bus_space_unmap(na->na_tag, bsh, NBMEMSIZE);
223 
224 	return rv;
225 }
226 
227 static void
228 netdock_nubus_attach(struct device *parent, struct device *self, void *aux)
229 {
230 	struct netdock_softc *sc = (struct netdock_softc *)self;
231 	struct nubus_attach_args *na = (struct nubus_attach_args *)aux;
232 	bus_space_tag_t bst;
233 	bus_space_handle_t bsh;
234 	u_int8_t enaddr[ETHER_ADDR_LEN];
235 	const char *cardtype;
236 
237 	bst = na->na_tag;
238 	if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE, 0, &bsh)) {
239 		printf(": failed to map memory space.\n");
240 		return;
241 	}
242 
243 	sc->sc_regt = bst;
244 	cardtype = nubus_get_card_name(bst, bsh, na->fmt);
245 
246 #ifdef NETDOCK_DEBUG_DRIVER
247 	netdock_print_driver(bst, bsh, na);
248 #endif
249 
250 	if (netdock_nb_get_enaddr(bst, bsh, na, enaddr)) {
251 		printf(": can't find MAC address.\n");
252 		bus_space_unmap(bst, bsh, NBMEMSIZE);
253 		return;
254 	}
255 
256 	if (bus_space_subregion(bst, bsh, 0xe00300, 0xf0000, &sc->sc_regh)) {
257 		printf(": failed to map register space.\n");
258 		bus_space_unmap(bst, bsh, NBMEMSIZE);
259 		return;
260 	}
261 
262 	printf(": %s\n", cardtype);
263 
264 	if (netdock_setup(sc, enaddr)) {
265 		bus_space_unmap(bst, bsh, NBMEMSIZE);
266 		return;
267 	}
268 
269 	add_nubus_intr(na->slot, netdock_intr, (void *)sc);
270 
271 	return;
272 }
273 
274 static int
275 netdock_nb_get_enaddr(bus_space_tag_t bst, bus_space_handle_t bsh,
276     struct nubus_attach_args *na, u_int8_t *ep)
277 {
278 	nubus_dir dir;
279 	nubus_dirent dirent;
280 
281 	/*
282 	 * these hardwired resource IDs are only for NetDock
283 	 */
284 	nubus_get_main_dir(na->fmt, &dir);
285 	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent) <= 0)
286 		return 1;
287 	nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
288 	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x80, &dirent) <= 0)
289 		return 1;
290 	if (nubus_get_ind_data(bst, bsh, na->fmt, &dirent,
291 		ep, ETHER_ADDR_LEN) <= 0)
292 		return 1;
293 
294 	return 0;
295 }
296 
297 #ifdef NETDOCK_DEBUG_DRIVER
298 static void
299 netdock_print_driver(bus_space_tag_t bst, bus_space_handle_t bsh,
300     struct nubus_attach_args *na)
301 {
302 #define HEADSIZE	(8+4)
303 #define CODESIZE	(6759-4)
304 	unsigned char mydata[HEADSIZE + CODESIZE];
305 	nubus_dir dir;
306 	nubus_dirent dirent;
307 	int i, rv;
308 
309 	nubus_get_main_dir(na->fmt, &dir);
310 	rv = nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent);
311 	if (rv <= 0) {
312 		printf(": can't find sResource.\n");
313 		return;
314 	}
315 	nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
316 	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, NUBUS_RSRC_DRVRDIR,
317 	    &dirent) <= 0) {
318 		printf(": can't find sResource.\n");
319 		return;
320 	}
321 	if (nubus_get_ind_data(bst, bsh, na->fmt,
322 		&dirent, mydata, HEADSIZE+CODESIZE) <= 0) {
323 		printf(": can't find indirect data.\n");
324 		return;
325 	}
326 	printf("\n########## begin driver dir");
327 	for (i = 0; i < HEADSIZE; i++) {
328 		if (i % 16 == 0)
329 			printf("\n%02x:",i);
330 		printf(" %02x", mydata[i]);
331 	}
332 	printf("\n########## begin driver code");
333 	for (i = 0; i < CODESIZE; i++) {
334 		if (i % 16 == 0)
335 			printf("\n%02x:",i);
336 		printf(" %02x", mydata[i + HEADSIZE]);
337 	}
338 #if 0
339 	printf("\n########## begin driver code (partial)\n");
340 #define PARTSIZE 256
341 #define OFFSET 0x1568
342 	for (i = OFFSET; i < OFFSET + PARTSIZE; i++) {
343 		if ((i - OFFSET) % 16 == 0)
344 			printf("\n%02x:",i);
345 		printf(" %02x", mydata[i + HEADSIZE]);
346 	}
347 #endif
348 	printf("\n########## end\n");
349 }
350 #endif
351 
352 
353 int
354 netdock_setup(struct netdock_softc *sc, u_int8_t *lladdr)
355 {
356 	struct ifnet *ifp = &sc->sc_if;
357 
358 	memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN);
359 	printf("%s: Ethernet address %s\n",
360 	    sc->sc_dev.dv_xname, ether_sprintf(lladdr));
361 
362 	memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
363 	ifp->if_softc = sc;
364 	ifp->if_ioctl = netdock_ioctl;
365 	ifp->if_start = netdock_start;
366 	ifp->if_flags =
367 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
368 	ifp->if_watchdog = netdock_watchdog;
369 
370 	if_attach(ifp);
371 	ether_ifattach(ifp, lladdr);
372 
373 	return (0);
374 }
375 
376 static int
377 netdock_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
378 {
379 	struct ifaddr *ifa;
380 	struct ifreq *ifr;
381 	struct netdock_softc *sc = ifp->if_softc;
382 	int s = splnet();
383 	int err = 0;
384 	int temp;
385 
386 	switch (cmd) {
387 	case SIOCSIFADDR:
388 		ifa = (struct ifaddr *)data;
389 		ifp->if_flags |= IFF_UP;
390 		switch (ifa->ifa_addr->sa_family) {
391 #ifdef INET
392 		case AF_INET:
393 			(void)netdock_init(sc);
394 			arp_ifinit(ifp, ifa);
395 			break;
396 #endif
397 		default:
398 			(void)netdock_init(sc);
399 			break;
400 		}
401 		break;
402 
403 	case SIOCSIFFLAGS:
404 		if ((ifp->if_flags & IFF_UP) == 0 &&
405 		    (ifp->if_flags & IFF_RUNNING) != 0) {
406 			netdock_stop(sc);
407 			ifp->if_flags &= ~IFF_RUNNING;
408 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
409 		    (ifp->if_flags & IFF_RUNNING) == 0) {
410 			(void)netdock_init(sc);
411 		} else {
412 			temp = ifp->if_flags & IFF_UP;
413 			netdock_reset(sc);
414 			ifp->if_flags |= temp;
415 			netdock_start(ifp);
416 		}
417 		break;
418 
419 	case SIOCADDMULTI:
420 	case SIOCDELMULTI:
421 		ifr = (struct ifreq *)data;
422 		if (cmd == SIOCADDMULTI)
423 			err = ether_addmulti(ifr, &sc->sc_ethercom);
424 		else
425 			err = ether_delmulti(ifr, &sc->sc_ethercom);
426 
427 		if (err == ENETRESET) {
428 			if (ifp->if_flags & IFF_RUNNING) {
429 				temp = ifp->if_flags & IFF_UP;
430 				netdock_reset(sc);
431 				ifp->if_flags |= temp;
432 			}
433 			err = 0;
434 		}
435 		break;
436 	default:
437 		err = EINVAL;
438 		break;
439 	}
440 	splx(s);
441 	return (err);
442 }
443 
444 static void
445 netdock_start(struct ifnet *ifp)
446 {
447 	struct netdock_softc *sc = ifp->if_softc;
448 	struct mbuf *m;
449 
450 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
451 		return;
452 
453 	while (1) {
454 		IF_DEQUEUE(&ifp->if_snd, m);
455 		if (m == 0)
456 			return;
457 
458 		if ((m->m_flags & M_PKTHDR) == 0)
459 			panic("%s: netdock_start: no header mbuf",
460 				sc->sc_dev.dv_xname);
461 
462 #if NBPFILTER > 0
463 		if (ifp->if_bpf)
464 			bpf_mtap(ifp->if_bpf, m);
465 #endif
466 
467 		if ((netdock_put(sc, m)) == 0) {
468 			IF_PREPEND(&ifp->if_snd, m);
469 			return;
470 		}
471 
472 		ifp->if_opackets++;
473 	}
474 
475 }
476 
477 static void
478 netdock_reset(struct netdock_softc *sc)
479 {
480 
481 	netdock_stop(sc);
482 	netdock_init(sc);
483 }
484 
485 static int
486 netdock_init(struct netdock_softc *sc)
487 {
488 	int s;
489 	int saveisr;
490 	int savetmp;
491 
492 	if (sc->sc_if.if_flags & IFF_RUNNING)
493 		return (0);
494 
495 	s = splnet();
496 
497 	/* 0606 */
498 	NIC_PUT_2(sc, REG_000E, 0x0200);
499 	NIC_PUT_2(sc, REG_ISR , 0);
500 	NIC_PUT_2(sc, REG_000E, 0);
501 
502 	NIC_PUT_2(sc, REG_0000, 0x8104);
503 	NIC_PUT_2(sc, REG_0004, 0x0043);
504 	NIC_PUT_2(sc, REG_000E, 0x0100);
505 	NIC_PUT_2(sc, REG_0002, 0x6618);
506 	NIC_PUT_2(sc, REG_0000, 0x8010);
507 
508 	NIC_PUT_1(sc, REG_0004 + 0, sc->sc_enaddr[0]);
509 	NIC_PUT_1(sc, REG_0004 + 1, sc->sc_enaddr[1]);
510 	NIC_PUT_1(sc, REG_0004 + 2, sc->sc_enaddr[2]);
511 	NIC_PUT_1(sc, REG_0004 + 3, sc->sc_enaddr[3]);
512 	NIC_PUT_1(sc, REG_0004 + 4, sc->sc_enaddr[4]);
513 	NIC_PUT_1(sc, REG_0004 + 5, sc->sc_enaddr[5]);
514 
515 	NIC_PUT_2(sc, REG_ISR , 0x2008);
516 	NIC_PUT_2(sc, REG_000E, 0x0200);
517 	NIC_PUT_2(sc, REG_0000, 0x4000);
518 	NIC_PUT_2(sc, REG_ISR, ISR_MASK);
519 
520 
521 	/* 1320 */
522 	saveisr = NIC_GET_2(sc, REG_ISR);
523 	NIC_PUT_2(sc, REG_ISR , 0);
524 	savetmp = NIC_GET_2(sc, REG_000E);
525 	NIC_PUT_2(sc, REG_000E, 0x0100);
526 	NIC_ANDW(sc, REG_ISR, ~ISR_BIT_03);
527 	NIC_PUT_2(sc, REG_000E, savetmp);
528 
529 	/* 1382 */
530 	savetmp = NIC_GET_2(sc, REG_000E);
531 	NIC_PUT_2(sc, REG_000E, 0x0100);
532 	NIC_ORW(sc, REG_ISR, ISR_BIT_03);
533 	NIC_PUT_2(sc, REG_000E, savetmp);
534 	NIC_PUT_2(sc, REG_ISR , saveisr);
535 
536 
537 	sc->sc_if.if_flags |= IFF_RUNNING;
538 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
539 
540 	splx(s);
541 	return (0);
542 }
543 
544 static int
545 netdock_stop(struct netdock_softc *sc)
546 {
547 	int s = splnet();
548 
549 	sc->sc_if.if_timer = 0;
550 	sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
551 
552 	splx(s);
553 	return (0);
554 }
555 
556 static void
557 netdock_watchdog(struct ifnet *ifp)
558 {
559 	struct netdock_softc *sc = ifp->if_softc;
560 	int tmp;
561 
562 	printf("netdock_watchdog: resetting chip\n");
563 	tmp = ifp->if_flags & IFF_UP;
564 	netdock_reset(sc);
565 	ifp->if_flags |= tmp;
566 }
567 
568 static u_int
569 netdock_put(struct netdock_softc *sc, struct mbuf *m0)
570 {
571 	struct mbuf *m;
572 	u_int totlen = 0;
573 	u_int tmplen;
574 	int isr;
575 	int timeout;
576 	int tmp;
577 	u_int i;
578 
579 	for (m = m0; m; m = m->m_next)
580 		totlen += m->m_len;
581 
582 	if (totlen >= ETHER_MAX_LEN)
583 		panic("%s: netdock_put: packet overflow", sc->sc_dev.dv_xname);
584 
585 	totlen += 6;
586 	tmplen = totlen;
587 	tmplen &= 0xff00;
588 	tmplen |= 0x2000;
589 	NIC_PUT_2(sc, REG_0000, tmplen);
590 
591 	timeout = 0x3000;
592 	while ((((isr = NIC_GET_2(sc, REG_ISR)) & ISR_READY) == 0) &&
593 	    timeout--) {
594 		if (isr & ISR_TX)
595 			netdock_txint(sc);
596 	}
597 	if (timeout == 0)
598 		return (0);
599 
600 	tmp = NIC_GET_2(sc, REG_0002);
601 	tmp <<= 8;
602 	NIC_PUT_2(sc, REG_0002, tmp);
603 	NIC_PUT_2(sc, REG_0006, 0x240);
604 	NIC_GET_2(sc, REG_ISR);
605 	tmplen = ((totlen << 8) & 0xfe00) | ((totlen >> 8) & 0x00ff);
606 	NIC_PUT_2(sc, REG_DATA, tmplen);
607 
608 	for (m = m0; m; m = m->m_next) {
609 		u_char *data = mtod(m, u_char *);
610 		int len = m->m_len;
611 		int len4 = len >> 2;
612 		u_int32_t *data4 = (u_int32_t *)data;
613 		for (i = 0; i < len4; i++)
614 			NIC_PUT_4(sc, REG_DATA, data4[i]);
615 		for (i = len4 << 2; i < len; i++)
616 			NIC_PUT_1(sc, REG_DATA, data[i]);
617 	}
618 
619 	if (totlen & 0x01)
620 		NIC_PUT_2(sc, REG_DATA, 0x2020);
621 	else
622 		NIC_PUT_2(sc, REG_DATA, 0);
623 
624 	NIC_PUT_2(sc, REG_0000, 0xc000);
625 
626 	m_freem(m0);
627 	/* sc->sc_if.if_timer = 5; */
628 	return (totlen);
629 }
630 
631 void
632 netdock_intr(void *arg)
633 {
634 	struct netdock_softc *sc = (struct netdock_softc *)arg;
635 	int isr;
636 	int tmp;
637 
638 	NIC_PUT_2(sc, REG_ISR, 0);
639 	while ((isr = (NIC_GET_2(sc, REG_ISR) & ISR_ALL)) != 0) {
640 		if (isr & ISR_TX)
641 			netdock_txint(sc);
642 
643 		if (isr & ISR_RX)
644 			netdock_rxint(sc);
645 
646 		if (isr & (ISR_BIT_0C | ISR_BIT_0D)) {
647 			if (isr & ISR_BIT_0C) {
648 				NIC_PUT_2(sc, REG_000E, 0);
649 				NIC_BSET(sc, REG_0004, 0x08);
650 				NIC_PUT_2(sc, REG_000E, 0x0200);
651 			}
652 			if (isr & ISR_BIT_0D) {
653 				NIC_PUT_2(sc, REG_000E, 0);
654 				tmp = NIC_GET_2(sc, REG_0002);
655 				if (tmp & REG_0002_BIT_04)
656 					NIC_GET_2(sc, REG_0006);
657 				tmp = NIC_GET_2(sc, REG_0000);
658 				if (tmp & REG_0000_BIT_08)
659 					NIC_BSET(sc, REG_0000, 0x08);
660 				NIC_PUT_2(sc, REG_000E, 0x0200);
661 			}
662 			NIC_PUT_2(sc, REG_ISR, isr);
663 		}
664 	}
665 	NIC_PUT_2(sc, REG_ISR, ISR_MASK);
666 }
667 
668 static void
669 netdock_txint(struct netdock_softc *sc)
670 {
671 	struct ifnet *ifp = &sc->sc_if;
672 	int savereg0002;
673 	int reg0004;
674 	int regdata;
675 
676 	ifp->if_flags &= ~IFF_OACTIVE;
677 	ifp->if_timer = 0;
678 
679 	savereg0002 = NIC_GET_2(sc, REG_0002);
680 
681 	while (((reg0004 = NIC_GET_2(sc, REG_0004)) & REG_0004_BIT_0F) == 0) {
682 		NIC_PUT_2(sc, REG_0002, reg0004);
683 		NIC_PUT_2(sc, REG_0006, 0x0060);
684 		NIC_GET_2(sc, REG_ISR);
685 		regdata = NIC_GET_2(sc, REG_DATA);
686 		if ((regdata & REG_DATA_BIT_08) == 0) {
687 			/* ifp->if_collisions++; */
688 			if (regdata & REG_DATA_BIT_07)
689 			/* ifp->if_oerrors++; */
690 			NIC_PUT_2(sc, REG_000E, 0);
691 			NIC_ORW(sc, REG_0000, 0x0100);
692 			NIC_PUT_2(sc, REG_000E, 0x0200);
693 		}
694 		NIC_GET_2(sc ,REG_DATA);
695 
696 		if (regdata & REG_DATA_BIT_0F)
697 			NIC_GET_4(sc, REG_EFD00);
698 		NIC_PUT_2(sc, REG_0000, 0xa000);
699 		NIC_PUT_2(sc, REG_ISR, ISR_TX);
700 	}
701 
702 	NIC_PUT_2(sc, REG_0002, savereg0002);
703 	NIC_PUT_2(sc, REG_000E, 0);
704 	NIC_GET_2(sc, REG_0006);
705 	NIC_PUT_2(sc, REG_000E, 0x0200);
706 	NIC_PUT_2(sc, REG_0006, 0);
707 }
708 
709 static void
710 netdock_rxint(struct netdock_softc *sc)
711 {
712 	struct ifnet *ifp = &sc->sc_if;
713 	int regdata1;
714 	int regdata2;
715 	u_int len;
716 	int timeout;
717 
718 	while ((NIC_GET_2(sc, REG_0004) & REG_0004_BIT_07) == 0) {
719 		NIC_GET_2(sc, REG_ISR);
720 		NIC_PUT_2(sc, REG_0006, 0x00e0);
721 		NIC_GET_2(sc, REG_ISR);
722 		regdata1 = NIC_GET_2(sc, REG_DATA);
723 		regdata2 = NIC_GET_2(sc, REG_DATA);
724 		len = ((regdata2 << 8) & 0x0700) | ((regdata2 >> 8) & 0x00ff);
725 
726 #if 0
727 		printf("netdock_rxint: r1=0x%04x, r2=0x%04x, len=%d\n",
728 		       regdata1, regdata2, len);
729 #endif
730 
731 		if ((regdata1 & REG_DATA_BIT_04) == 0)
732 			len -= 2;
733 
734 		/* CRC is included with the packet; trim it off. */
735 		len -= ETHER_CRC_LEN;
736 
737 		if ((regdata1 & 0x00ac) == 0) {
738 			if (netdock_read(sc, len))
739 				ifp->if_ipackets++;
740 			else
741 				ifp->if_ierrors++;
742 		} else {
743 			ifp->if_ierrors++;
744 
745 			if (regdata1 & REG_DATA_BIT_02)
746 				NIC_GET_4(sc, REG_EFD00);
747 			if (regdata1 & REG_DATA_BIT_03)
748 				;
749 			if (regdata1 & REG_DATA_BIT_05)
750 				NIC_GET_4(sc, REG_EFD00);
751 			if (regdata1 & REG_DATA_BIT_07)
752 				;
753 		}
754 
755 		timeout = 0x14;
756 		while ((NIC_GET_2(sc, REG_0000) & REG_0000_BIT_08) && timeout--)
757 			;
758 		if (timeout == 0)
759 			;
760 
761 		NIC_PUT_2(sc, REG_0000, 0x8000);
762 	}
763 	NIC_PUT_2(sc, REG_0006, 0);
764 }
765 
766 static int
767 netdock_read(struct netdock_softc *sc, int len)
768 {
769 	struct ifnet *ifp = &sc->sc_if;
770 	struct mbuf *m;
771 
772 	m = netdock_get(sc, len);
773 	if (m == 0)
774 		return (0);
775 
776 #if NBPFILTER > 0
777 	if (ifp->if_bpf)
778 		bpf_mtap(ifp->if_bpf, m);
779 #endif
780 
781 	(*ifp->if_input)(ifp, m);
782 
783 	return (1);
784 }
785 
786 static struct mbuf *
787 netdock_get(struct netdock_softc *sc, int datalen)
788 {
789 	struct mbuf *m, *top, **mp;
790 	u_char *data;
791 	int i;
792 	int len;
793 	int len4;
794 	u_int32_t *data4;
795 
796 	MGETHDR(m, M_DONTWAIT, MT_DATA);
797 	if (m == NULL)
798 		return (NULL);
799 	m->m_pkthdr.rcvif = &sc->sc_if;
800 	m->m_pkthdr.len = datalen;
801 	len = MHLEN;
802 	top = NULL;
803 	mp = &top;
804 
805 	while (datalen > 0) {
806 		if (top) {
807 			MGET(m, M_DONTWAIT, MT_DATA);
808 			if (m == 0) {
809 				m_freem(top);
810 				return (NULL);
811 			}
812 			len = MLEN;
813 		}
814 		if (datalen >= MINCLSIZE) {
815 			MCLGET(m, M_DONTWAIT);
816 			if ((m->m_flags & M_EXT) == 0) {
817 				if (top)
818 					m_freem(top);
819 				return (NULL);
820 			}
821 			len = MCLBYTES;
822 		}
823 
824 		if (mp == &top) {
825 			caddr_t newdata = (caddr_t)
826 			    ALIGN(m->m_data + sizeof(struct ether_header)) -
827 			    sizeof(struct ether_header);
828 			len -= newdata - m->m_data;
829 			m->m_data = newdata;
830 		}
831 
832 		m->m_len = len = min(datalen, len);
833 
834 		data = mtod(m, u_char *);
835 		len4 = len >> 2;
836 		data4 = (u_int32_t *)data;
837 		for (i = 0; i < len4; i++)
838 			data4[i] = NIC_GET_4(sc, REG_DATA);
839 		for (i = len4 << 2; i < len; i++)
840 			data[i] = NIC_GET_1(sc, REG_DATA);
841 
842 		datalen -= len;
843 		*mp = m;
844 		mp = &m->m_next;
845 	}
846 
847 	return (top);
848 }
849