Add a DECLARE_DUMMY_MODULE() so we can get linker_set module names
[dragonfly.git] / sys / dev / netif / rdp / if_rdp.c
1 /*
2  * Copyright 1998, Joerg Wunsch
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/i386/isa/if_rdp.c,v 1.6.2.2 2000/07/17 21:24:32 archie Exp $
28  * $DragonFly: src/sys/dev/netif/rdp/if_rdp.c,v 1.6 2003/11/20 22:07:30 dillon Exp $
29  */
30
31 /*
32  * Device driver for RealTek RTL 8002 (`REDP') based pocket-ethernet
33  * adapters, hooked up to a printer port.  `rdp' is a shorthand for
34  * REDP since some tools like netstat work best if the interface name
35  * has no more than three letters.
36  *
37  * Driver configuration flags so far:
38  *   flags 0x1 -- assume 74S288 EEPROM (default 94C46)
39  *   flags 0x2 -- use `slow' mode (mode 3 of the packet driver, default 0)
40  *
41  * Maybe this driver will some day also work with the successor, RTL
42  * 8012 (`AREDP'), which is unfortunately not fully register-
43  * compatible with the 8002.  The 8012 offers support for faster
44  * transfer modi like bidirectional SPP and EPP, 64 K x 4 buffer
45  * memory as opposed to 16 K x 4 for the 8002, a multicast filter, and
46  * a builtin multiplexer that allows chaining a printer behind the
47  * ethernet adapter.
48  *
49  * About the only documentation i've been able to find about the RTL
50  * 8002 was the packet driver source code at ftp.realtek.com.tw, so
51  * this driver is somewhat based on the way the packet driver handles
52  * the chip.  The exact author of the packet driver is unknown, the
53  * only name that i could find in the source was someone called Chiu,
54  * supposedly an employee of RealTek.  So credits to them for that
55  * piece of code which has proven valuable to me.
56  *
57  * Later on, Leo kuo <leo@realtek.com.tw> has been very helpful to me
58  * by sending me a readable (PDF) file documenting the RTL 8012, which
59  * helped me to also understand the 8002, as well as by providing me
60  * with the source code of the 8012 packet driver that i haven't been
61  * able to find on the FTP site.  A big Thanks! goes here to RealTek
62  * for this kind of service.
63  */
64
65 #include "use_rdp.h"
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/conf.h>
70 #include <sys/sockio.h>
71 #include <sys/malloc.h>
72 #include <sys/mbuf.h>
73 #include <sys/socket.h>
74 #include <sys/syslog.h>
75 #include <sys/linker_set.h>
76 #include <sys/module.h>
77
78 #include <net/ethernet.h>
79 #include <net/if.h>
80 #include <net/if_arp.h>
81 #include <net/if_dl.h>
82 #include <net/if_mib.h>
83
84 #ifdef INET
85 #include <netinet/in.h>
86 #include <netinet/if_ether.h>
87 #endif
88
89 #ifdef NS
90 #include <netns/ns.h>
91 #include <netns/ns_if.h>
92 #endif
93
94 #include <net/bpf.h>
95
96 #include <machine/clock.h>
97 #include <machine/md_var.h>
98
99 #include <bus/isa/i386/isa_device.h>
100 #include <i386/isa/icu.h>
101 #include "if_rdpreg.h"
102 #include <i386/isa/intr_machdep.h>
103
104 #define IOCTL_CMD_T u_long
105
106 /*
107  * Debug levels (ORed together):
108  *  != 0 - general (bad packets etc.)
109  *  2 - debug EEPROM IO
110  *  4 - debug interrupt status
111  */
112 #undef DEBUG
113 #define DEBUG 0
114
115 /*
116  * rdp_softc: per interface info and status
117  */
118 struct rdp_softc {
119         struct arpcom arpcom;   /*
120                                  * Ethernet common, always goes first so
121                                  * a rdp_softc * can be cast into an
122                                  * arpcom * or into an ifnet *.
123                                  */
124
125         /*
126          * local stuff, somewhat sorted by memory alignment class
127          */
128         u_short baseaddr;       /* IO port address */
129         u_short txsize;         /* tx size for next (buffered) packet,
130                                  * there's only one additional packet
131                                  * we can buffer, thus a single variable
132                                  * ought to be enough */
133         int txbusy;             /* tx is transmitting */
134         int txbuffered;         /* # of packets in tx buffer */
135         int slow;               /* use lpt_control to send data */
136         u_char irqenbit;        /* mirror of current Ctrl_IRQEN */
137         /*
138          * type of parameter EEPROM; device flags 0x1 selects 74S288
139          */
140         enum {
141                 EEPROM_93C46, EEPROM_74S288 /* or 82S123 */
142         } eeprom;
143 };
144
145 DECLARE_DUMMY_MODULE(if_rdp);
146
147 static struct rdp_softc rdp_softc[NRDP];
148
149 /*
150  * Since there's no fixed location in the EEPROM about where to find
151  * the ethernet hardware address, we drop a table of valid OUIs here,
152  * and search through the EEPROM until we find a possible valid
153  * Ethernet address.  Only the first 16 bits of all possible OUIs are
154  * recorded in the table (as obtained from
155  * http://standards.ieee.org/regauth/oui/oui.txt).
156  */
157
158 static u_short allowed_ouis[] = {
159         0x0000, 0x0001, 0x0002, 0x0004, 0x0005, 0x0006, 0x0007,
160         0x0008, 0x0010, 0x001C, 0x0020, 0x0040, 0x0050, 0x0060,
161         0x0070, 0x0080, 0x0090, 0x009D, 0x00A0, 0x00AA, 0x00BB,
162         0x00C0, 0x00CF, 0x00DD, 0x00E0, 0x00E6, 0x0207, 0x021C,
163         0x0260, 0x0270, 0x029D, 0x02AA, 0x02BB, 0x02C0, 0x02CF,
164         0x02E6, 0x040A, 0x04E0, 0x0800, 0x08BB, 0x1000, 0x1100,
165         0x8000, 0xAA00
166 };
167
168 /*
169  * ISA bus support.
170  */
171 static int rdp_probe            (struct isa_device *);
172 static int rdp_attach           (struct isa_device *);
173
174 /*
175  * Required entry points.
176  */
177 static void rdp_init(void *);
178 static int rdp_ioctl(struct ifnet *, IOCTL_CMD_T, caddr_t);
179 static void rdp_start(struct ifnet *);
180 static void rdp_reset(struct ifnet *);
181 static void rdp_watchdog(struct ifnet *);
182 static void rdpintr(int);
183
184 /*
185  * REDP private functions.
186  */
187
188 static void rdp_stop(struct rdp_softc *);
189 static void rdp_rint(struct rdp_softc *);
190 static void rdp_get_packet(struct rdp_softc *, unsigned);
191 static u_short rdp_write_mbufs(struct rdp_softc *, struct mbuf *);
192 static int rdp_gethwaddr_93c46(struct rdp_softc *, u_char *);
193 static void rdp_gethwaddr_74s288(struct rdp_softc *, u_char *);
194 static void rdp_93c46_cmd(struct rdp_softc *, u_short, unsigned);
195 static u_short rdp_93c46_read(struct rdp_softc *);
196
197 struct isa_driver rdpdriver = {
198         rdp_probe,
199         rdp_attach,
200         "rdp",
201         1                       /* we wanna get a chance before lptN */
202 };
203
204 /*
205  * REDP-specific functions.
206  *
207  * They are inlined, thus go first in this file.  Together with gcc's
208  * usual optimization, these functions probably come close to the
209  * packet driver's hand-optimized code. ;-)
210  *
211  * Comments are partially obtained from the packet driver as well.
212  * Some of the function names contain register names which don't make
213  * much sense for us, but i've kept them for easier reference in
214  * comparision to the packet driver.
215  *
216  * Some of the functions are currently not used by the driver; it's
217  * not quite clear whether we ever need them at all.  They are
218  * supposedly even slower than what is currently implemented as `slow'
219  * mode.  Right now, `fast' (default) mode is what the packet driver
220  * calls mode 0, slow mode is mode 3 (writing through lpt_control,
221  * reading twice).
222  *
223  * We should autoprobe the modi, as opposed to making them dependent
224  * on a kernel configuration flag.
225  */
226
227 /*
228  * read a nibble from rreg; end-of-data cmd is not issued;
229  * used for general register read.
230  *
231  * Unlike the packet driver's version, i'm shifting the result
232  * by 3 here (as opposed to within the caller's code) for clarity.
233  *  -- Joerg
234  */
235 static __inline u_char
236 RdNib(struct rdp_softc *sc, u_char rreg)
237 {
238
239         outb(sc->baseaddr + lpt_data, EOC + rreg);
240         outb(sc->baseaddr + lpt_data, RdAddr + rreg); /* write addr */
241         (void)inb(sc->baseaddr + lpt_status);
242         return (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f;
243 }
244
245 #if 0
246 /*
247  * read a byte from MAR register through lpt_data; the low nibble is
248  * read prior to the high one; end-of-read command is not issued; used
249  * for remote DMA in mode 4 + 5
250  */
251 static __inline u_char
252 RdByte(struct rdp_softc *sc)
253 {
254         u_char hinib, lonib;
255
256         outb(sc->baseaddr + lpt_data, RdAddr + MAR); /* cmd for low nibble */
257         lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f;
258         outb(sc->baseaddr + lpt_data, RdAddr + MAR + HNib);
259         hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0;
260         return hinib + lonib;
261 }
262
263
264 /*
265  * read a byte from MAR register through lpt_data; the low nibble is
266  * read prior to the high one; end-of-read command is not issued; used
267  * for remote DMA in mode 6 + 7
268  */
269 static __inline u_char
270 RdByte1(struct rdp_softc *sc)
271 {
272         u_char hinib, lonib;
273
274         outb(sc->baseaddr + lpt_data, RdAddr + MAR); /* cmd for low nibble */
275         (void)inb(sc->baseaddr + lpt_status);
276         lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f;
277         outb(sc->baseaddr + lpt_data, RdAddr + MAR + HNib);
278         (void)inb(sc->baseaddr + lpt_status);
279         hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0;
280         return hinib + lonib;
281 }
282 #endif
283
284
285 /*
286  * read a byte from MAR register through lpt_control; the low nibble is
287  * read prior to the high one; end-of-read command is not issued; used
288  * for remote DMA in mode 0 + 1
289  */
290 static __inline u_char
291 RdByteA1(struct rdp_softc *sc)
292 {
293         u_char hinib, lonib;
294
295         outb(sc->baseaddr + lpt_control, Ctrl_LNibRead);
296         lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f;
297         outb(sc->baseaddr + lpt_control, Ctrl_HNibRead);
298         hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0;
299         return hinib + lonib;
300 }
301
302
303 /*
304  * read a byte from MAR register through lpt_control; the low nibble is
305  * read prior to the high one; end-of-read command is not issued; used
306  * for remote DMA in mode 2 + 3
307  */
308 static __inline u_char
309 RdByteA2(struct rdp_softc *sc)
310 {
311         u_char hinib, lonib;
312
313         outb(sc->baseaddr + lpt_control, Ctrl_LNibRead);
314         (void)inb(sc->baseaddr + lpt_status);
315         lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f;
316         outb(sc->baseaddr + lpt_control, Ctrl_HNibRead);
317         (void)inb(sc->baseaddr + lpt_status);
318         hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0;
319         return hinib + lonib;
320 }
321
322 /*
323  * End-of-read cmd
324  */
325 static __inline void
326 RdEnd(struct rdp_softc *sc, u_char rreg)
327 {
328
329         outb(sc->baseaddr + lpt_data, EOC + rreg);
330 }
331
332 /*
333  * Write a nibble to a register; end-of-write is issued.
334  * Used for general register write.
335  */
336 static __inline void
337 WrNib(struct rdp_softc *sc, u_char wreg, u_char wdata)
338 {
339
340         /* prepare and write address */
341         outb(sc->baseaddr + lpt_data, EOC + wreg);
342         outb(sc->baseaddr + lpt_data, WrAddr + wreg);
343         outb(sc->baseaddr + lpt_data, WrAddr + wreg);
344         /* prepare and write data */
345         outb(sc->baseaddr + lpt_data, WrAddr + wdata);
346         outb(sc->baseaddr + lpt_data, wdata);
347         outb(sc->baseaddr + lpt_data, wdata);
348         /* end-of-write */
349         outb(sc->baseaddr + lpt_data, EOC + wdata);
350 }
351
352 /*
353  * Write a byte to a register; end-of-write is issued.
354  * Used for general register write.
355  */
356 static __inline void
357 WrByte(struct rdp_softc *sc, u_char wreg, u_char wdata)
358 {
359
360         /* prepare and write address */
361         outb(sc->baseaddr + lpt_data, EOC + wreg);
362         outb(sc->baseaddr + lpt_data, WrAddr + wreg);
363         outb(sc->baseaddr + lpt_data, WrAddr + wreg);
364         /* prepare and write low nibble */
365         outb(sc->baseaddr + lpt_data, WrAddr + (wdata & 0x0F));
366         outb(sc->baseaddr + lpt_data, (wdata & 0x0F));
367         outb(sc->baseaddr + lpt_data, (wdata & 0x0F));
368         /* prepare and write high nibble */
369         wdata >>= 4;
370         outb(sc->baseaddr + lpt_data, wdata);
371         outb(sc->baseaddr + lpt_data, wdata + HNib);
372         outb(sc->baseaddr + lpt_data, wdata + HNib);
373         /* end-of-write */
374         outb(sc->baseaddr + lpt_data, EOC + wdata + HNib);
375 }
376
377 /*
378  * Write the byte to DRAM via lpt_data;
379  * used for remote DMA write in mode 0 / 2 / 4
380  */
381 static __inline void
382 WrByteALToDRAM(struct rdp_softc *sc, u_char val)
383 {
384
385         outb(sc->baseaddr + lpt_data, val & 0x0F);
386         outb(sc->baseaddr + lpt_data, MkHi(val));
387 }
388
389 /*
390  * Write the byte to DRAM via lpt_control;
391  * used for remote DMA write in mode 1 / 3 / 5
392  */
393 static __inline void
394 WrByteALToDRAMA(struct rdp_softc *sc, u_char val)
395 {
396
397         outb(sc->baseaddr + lpt_data, val & 0x0F);
398         outb(sc->baseaddr + lpt_control, Ctrl_LNibRead | sc->irqenbit);
399         outb(sc->baseaddr + lpt_data, val >> 4);
400         outb(sc->baseaddr + lpt_control, Ctrl_HNibRead | sc->irqenbit);
401 }
402
403 #if 0 /* they could be used for the RAM test */
404 /*
405  * Write the u_short to DRAM via lpt_data;
406  * used for remote DMA write in mode 0 / 2 / 4
407  */
408 static __inline void
409 WrWordbxToDRAM(struct rdp_softc *sc, u_short val)
410 {
411
412         outb(sc->baseaddr + lpt_data, val & 0x0F);
413         val >>= 4;
414         outb(sc->baseaddr + lpt_data, (val & 0x0F) + HNib);
415         val >>= 4;
416         outb(sc->baseaddr + lpt_data, val & 0x0F);
417         val >>= 4;
418         outb(sc->baseaddr + lpt_data, val + HNib);
419 }
420
421
422 /*
423  * Write the u_short to DRAM via lpt_control;
424  * used for remote DMA write in mode 1 / 3 / 5
425  */
426 static __inline void
427 WrWordbxToDRAMA(struct rdp_softc *sc, u_short val)
428 {
429
430         outb(sc->baseaddr + lpt_data, val & 0x0F);
431         outb(sc->baseaddr + lpt_control, Ctrl_LNibRead | sc->irqenbit);
432         val >>= 4;
433         outb(sc->baseaddr + lpt_data, (val & 0x0F) + HNib);
434         outb(sc->baseaddr + lpt_control, Ctrl_HNibRead | sc->irqenbit);
435         val >>= 4;
436         outb(sc->baseaddr + lpt_data, val & 0x0F);
437         outb(sc->baseaddr + lpt_control, Ctrl_LNibRead | sc->irqenbit);
438         val >>= 4;
439         outb(sc->baseaddr + lpt_data, val + HNib);
440         outb(sc->baseaddr + lpt_control, Ctrl_HNibRead | sc->irqenbit);
441 }
442 #endif
443
444
445 /*
446  * Determine if the device is present
447  *
448  *   on entry:
449  *      a pointer to an isa_device struct
450  *   on exit:
451  *      0 if device not found
452  *      or # of i/o addresses used (if found)
453  */
454 static int
455 rdp_probe(struct isa_device *isa_dev)
456 {
457         int unit = isa_dev->id_unit;
458         struct rdp_softc *sc = &rdp_softc[unit];
459         u_char b1, b2;
460         intrmask_t irqmap[3];
461         u_char sval[3];
462
463         if (unit < 0 || unit >= NRDP)
464                 return 0;
465
466         sc->baseaddr = isa_dev->id_iobase;
467         if (isa_dev->id_flags & 1)
468                 sc->eeprom = EEPROM_74S288;
469         /* else defaults to 93C46 */
470         if (isa_dev->id_flags & 2)
471                 sc->slow = 1;
472
473         /* let R/WB = A/DB = CSB = high to be ready for next r/w cycle */
474         outb(sc->baseaddr + lpt_data, 0xFF);
475         /* DIR = 0 for write mode, IRQEN=0, SLCT=INIT=AUTOFEED=STB=high */
476         outb(sc->baseaddr + lpt_control, Ctrl_SelData);
477         /* software reset */
478         WrNib(sc, CMR1 + HNib, MkHi(CMR1_RST));
479         DELAY(2000);
480         /* is EPLC alive? */
481         b1 = RdNib(sc, CMR1);
482         RdEnd(sc, CMR1);
483         b2 = RdNib(sc, CMR2) & 0x0f;
484         b2 |= RdNib(sc, CMR2 + HNib) << 4;
485         RdEnd(sc, CMR2 + HNib);
486         /*
487          * After the reset, we expect CMR1 & 7 to be 1 (rx buffer empty),
488          * and CMR2 & 0xf7 to be 0x20 (receive mode set to physical and
489          * broadcasts).
490          */
491         if (bootverbose)
492                 printf("rdp%d: CMR1 = %#x, CMR2 = %#x\n", unit, b1, b2);
493
494         if ((b1 & (CMR1_BUFE | CMR1_IRQ | CMR1_TRA)) != CMR1_BUFE
495             || (b2 & ~CMR2_IRQINV) != CMR2_AM_PB)
496                 return 0;
497
498         /*
499          * We have found something that could be a RTL 80[01]2, now
500          * see whether we can generate an interrupt.
501          */
502         cpu_disable_intr();
503
504         /*
505          * Test whether our configured IRQ is working.
506          *
507          * Set to no acception mode + IRQout, then enable RxE + TxE,
508          * then cause RBER (by advancing the read pointer although
509          * the read buffer is empty) to generate an interrupt.
510          */
511         WrByte(sc, CMR2, CMR2_IRQOUT);
512         WrNib(sc, CMR1 + HNib, MkHi(CMR1_TE | CMR1_RE));
513         WrNib(sc, CMR1, CMR1_RDPAC);
514         DELAY(1000);
515
516         irqmap[0] = isa_irq_pending();
517         sval[0] = inb(sc->baseaddr + lpt_status);
518
519         /* allow IRQs to pass the parallel interface */
520         outb(sc->baseaddr + lpt_control, Ctrl_IRQEN + Ctrl_SelData);
521         DELAY(1000);
522         /* generate interrupt */
523         WrNib(sc, IMR + HNib, MkHi(ISR_RBER));
524         DELAY(1000);
525
526         irqmap[1] = isa_irq_pending();
527         sval[1] = inb(sc->baseaddr + lpt_status);
528
529         /* de-assert and disable IRQ */
530         WrNib(sc, IMR + HNib, MkHi(0));
531         (void)inb(sc->baseaddr + lpt_status); /* might be necessary to
532                                                  clear IRQ */
533         DELAY(1000);
534         irqmap[2] = isa_irq_pending();
535         sval[2] = inb(sc->baseaddr + lpt_status);
536
537         WrNib(sc, CMR1 + HNib, MkHi(0));
538         outb(sc->baseaddr + lpt_control, Ctrl_SelData);
539         WrNib(sc, CMR2, CMR2_IRQINV);
540
541         cpu_enable_intr();
542
543         if (bootverbose)
544                 printf("rdp%d: irq maps / lpt status "
545                        "%#x/%#x - %#x/%#x - %#x/%#x (id_irq %#x)\n",
546                        unit, irqmap[0], sval[0], irqmap[1], sval[1],
547                        irqmap[2], sval[2], isa_dev->id_irq);
548
549         if ((irqmap[1] & isa_dev->id_irq) == 0) {
550                 printf("rdp%d: configured IRQ (%d) cannot be asserted "
551                        "by device",
552                        unit, ffs(isa_dev->id_irq) - 1);
553                 if (irqmap[1])
554                         printf(" (probable IRQ: %d)", ffs(irqmap[1]) - 1);
555                 printf("\n");
556                 return 0;
557         }
558
559         /*
560          * XXX should do RAMtest here
561          */
562
563         switch (sc->eeprom) {
564         case EEPROM_93C46:
565                 if (rdp_gethwaddr_93c46(sc, sc->arpcom.ac_enaddr) == 0) {
566                         printf("rdp%d: failed to find a valid hardware "
567                                "address in EEPROM\n",
568                                unit);
569                         return 0;
570                 }
571                 break;
572
573         case EEPROM_74S288:
574                 rdp_gethwaddr_74s288(sc, sc->arpcom.ac_enaddr);
575                 break;
576         }
577
578         return lpt_control + 1;
579 }
580
581 /*
582  * Install interface into kernel networking data structures
583  */
584 static int
585 rdp_attach(struct isa_device *isa_dev)
586 {
587         int unit = isa_dev->id_unit;
588         struct rdp_softc *sc = &rdp_softc[unit];
589         struct ifnet *ifp = &sc->arpcom.ac_if;
590
591         isa_dev->id_ointr = rdpintr;
592
593         /*
594          * Reset interface
595          */
596         rdp_stop(sc);
597
598         if (!ifp->if_name) {
599                 /*
600                  * Initialize ifnet structure
601                  */
602                 ifp->if_softc = sc;
603                 ifp->if_unit = unit;
604                 ifp->if_name = "rdp";
605                 ifp->if_output = ether_output;
606                 ifp->if_start = rdp_start;
607                 ifp->if_ioctl = rdp_ioctl;
608                 ifp->if_watchdog = rdp_watchdog;
609                 ifp->if_init = rdp_init;
610                 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
611                 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
612
613                 /*
614                  * Attach the interface
615                  */
616                 ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
617         }
618
619         /*
620          * Print additional info when attached
621          */
622         printf("%s%d: RealTek RTL%s pocket ethernet, EEPROM %s, %s mode\n",
623                ifp->if_name, ifp->if_unit,
624                "8002",          /* hook for 8012 */
625                sc->eeprom == EEPROM_93C46? "93C46": "74S288",
626                sc->slow? "slow": "fast");
627         printf("%s%d: address %6D\n", ifp->if_name, ifp->if_unit,
628                sc->arpcom.ac_enaddr, ":");
629
630         return 1;
631 }
632
633 /*
634  * Reset interface.
635  */
636 static void
637 rdp_reset(struct ifnet *ifp)
638 {
639         struct rdp_softc *sc = ifp->if_softc;
640         int s;
641
642         s = splimp();
643
644         /*
645          * Stop interface and re-initialize.
646          */
647         rdp_stop(sc);
648         rdp_init(sc);
649
650         (void) splx(s);
651 }
652
653 /*
654  * Take interface offline.
655  */
656 static void
657 rdp_stop(struct rdp_softc *sc)
658 {
659
660         sc->txbusy = sc->txbusy = 0;
661
662         /* disable printer interface interrupts */
663         sc->irqenbit = 0;
664         outb(sc->baseaddr + lpt_control, Ctrl_SelData);
665         outb(sc->baseaddr + lpt_data, 0xff);
666
667         /* reset the RTL 8002 */
668         WrNib(sc, CMR1 + HNib, MkHi(CMR1_RST));
669         DELAY(100);
670 }
671
672 /*
673  * Device timeout/watchdog routine. Entered if the device neglects to
674  * generate an interrupt after a transmit has been started on it.
675  */
676 static void
677 rdp_watchdog(struct ifnet *ifp)
678 {
679
680         log(LOG_ERR, "rdp%d: device timeout\n", ifp->if_unit);
681         ifp->if_oerrors++;
682
683         rdp_reset(ifp);
684 }
685
686 /*
687  * Initialize device.
688  */
689 static void
690 rdp_init(void *xsc)
691 {
692         struct rdp_softc *sc = xsc;
693         struct ifnet *ifp = &sc->arpcom.ac_if;
694         int i, s;
695         u_char reg;
696
697         /* address not known */
698         if (TAILQ_EMPTY(&ifp->if_addrhead))
699                 return;
700
701         s = splimp();
702
703         ifp->if_timer = 0;
704
705         /* program ethernet ID into the chip */
706         for (i = 0, reg = IDR0; i < 6; i++, reg++)
707                 WrByte(sc, reg, sc->arpcom.ac_enaddr[i]);
708
709         /* set accept mode */
710         WrNib(sc, CMR2 + HNib,
711               MkHi((ifp->if_flags & IFF_PROMISC)? CMR2_AM_ALL: CMR2_AM_PB));
712
713         /* enable tx and rx */
714         WrNib(sc, CMR1 + HNib, MkHi(CMR1_TE | CMR1_RE));
715
716         /* allow interrupts to happen */
717         WrNib(sc, CMR2, CMR2_IRQOUT | CMR2_IRQINV);
718         WrNib(sc, IMR, ISR_TOK | ISR_TER | ISR_ROK | ISR_RER);
719         WrNib(sc, IMR + HNib, MkHi(ISR_RBER));
720
721         /* allow IRQs to pass the parallel interface */
722         sc->irqenbit = Ctrl_IRQEN;
723         outb(sc->baseaddr + lpt_control, sc->irqenbit + Ctrl_SelData);
724
725         /* clear all flags */
726         sc->txbusy = sc->txbuffered = 0;
727
728         /*
729          * Set 'running' flag, and clear output active flag.
730          */
731         ifp->if_flags |= IFF_RUNNING;
732         ifp->if_flags &= ~IFF_OACTIVE;
733
734         /*
735          * ...and attempt to start output
736          */
737         rdp_start(ifp);
738
739         (void) splx(s);
740 }
741
742 /*
743  * Start output on interface.
744  * We make two assumptions here:
745  *  1) that the current priority is set to splimp _before_ this code
746  *     is called *and* is returned to the appropriate priority after
747  *     return
748  *  2) that the IFF_OACTIVE flag is checked before this code is called
749  *     (i.e. that the output part of the interface is idle)
750  */
751 static void
752 rdp_start(struct ifnet *ifp)
753 {
754         struct rdp_softc *sc = ifp->if_softc;
755         struct mbuf *m;
756         int len;
757
758 outloop:
759
760         /*
761          * See if there is room to put another packet in the buffer.
762          */
763         if (sc->txbuffered) {
764                 /*
765                  * No room. Indicate this to the outside world and exit.
766                  */
767                 ifp->if_flags |= IFF_OACTIVE;
768                 return;
769         }
770         IF_DEQUEUE(&ifp->if_snd, m);
771         if (m == 0) {
772                 /*
773                  * We are using the !OACTIVE flag to indicate to the outside
774                  * world that we can accept an additional packet rather than
775                  * that the transmitter is _actually_ active. Indeed, the
776                  * transmitter may be active, but if we haven't filled all the
777                  * buffers with data then we still want to accept more.
778                  */
779                 ifp->if_flags &= ~IFF_OACTIVE;
780                 return;
781         }
782
783         /*
784          * Copy the mbuf chain into the transmit buffer
785          */
786
787         len = rdp_write_mbufs(sc, m);
788         if (len == 0)
789                 goto outloop;
790
791         /* ensure minimal valid ethernet length */
792         len = max(len, (ETHER_MIN_LEN-ETHER_CRC_LEN));
793
794         /*
795          * Actually start the transceiver.  Set a timeout in case the
796          * Tx interrupt never arrives.
797          */
798         if (!sc->txbusy) {
799                 WrNib(sc, TBCR1, len >> 8);
800                 WrByte(sc, TBCR0, len & 0xff);
801                 WrNib(sc, CMR1, CMR1_TRA);
802                 sc->txbusy = 1;
803                 ifp->if_timer = 2;
804         } else {
805                 sc->txbuffered = 1;
806                 sc->txsize = len;
807         }
808
809         /*
810          * Tap off here if there is a bpf listener.
811          */
812         if (ifp->if_bpf) {
813                 bpf_mtap(ifp, m);
814         }
815
816         m_freem(m);
817
818         /*
819          * Loop back to the top to possibly buffer more packets
820          */
821         goto outloop;
822 }
823
824 /*
825  * Process an ioctl request.
826  */
827 static int
828 rdp_ioctl(struct ifnet *ifp, IOCTL_CMD_T command, caddr_t data)
829 {
830         struct rdp_softc *sc = ifp->if_softc;
831         int s, error = 0;
832
833         s = splimp();
834
835         switch (command) {
836
837         case SIOCSIFADDR:
838         case SIOCGIFADDR:
839         case SIOCSIFMTU:
840                 error = ether_ioctl(ifp, command, data);
841                 break;
842
843         case SIOCSIFFLAGS:
844                 /*
845                  * If the interface is marked up and stopped, then start it.
846                  * If it is marked down and running, then stop it.
847                  */
848                 if (ifp->if_flags & IFF_UP) {
849                         if ((ifp->if_flags & IFF_RUNNING) == 0)
850                                 rdp_init(sc);
851                 } else {
852                         if (ifp->if_flags & IFF_RUNNING) {
853                                 rdp_stop(sc);
854                                 ifp->if_flags &= ~IFF_RUNNING;
855                         }
856                 }
857
858                 /*
859                  * Promiscuous flag may have changed, propagage this
860                  * to the NIC.
861                  */
862                 if (ifp->if_flags & IFF_UP)
863                         WrNib(sc, CMR2 + HNib,
864                               MkHi((ifp->if_flags & IFF_PROMISC)?
865                                    CMR2_AM_ALL: CMR2_AM_PB));
866
867                 break;
868
869         case SIOCADDMULTI:
870         case SIOCDELMULTI:
871                 /*
872                  * Multicast list has changed; we don't support it.
873                  */
874                 error = ENOTTY;
875                 break;
876
877         default:
878                 error = EINVAL;
879         }
880         (void) splx(s);
881         return (error);
882 }
883
884 /*
885  * External interrupt service routine.
886  */
887 void 
888 rdpintr(int unit)
889 {
890         struct rdp_softc *sc = rdp_softc + unit;
891         struct ifnet *ifp = (struct ifnet *)sc;
892         u_char isr, tsr, rsr, colls;
893
894         /* disable interrupts, so SD3 can be routed to the pin */
895         sc->irqenbit = 0;
896         outb(sc->baseaddr + lpt_control, Ctrl_SelData);
897         WrNib(sc, CMR2, CMR2_IRQINV);
898         /*
899          * loop until there are no more new interrupts
900          */
901         for (;;) {
902                 isr = RdNib(sc, ISR);
903                 isr |= RdNib(sc, ISR + HNib) << 4;
904                 RdEnd(sc, ISR + HNib);
905
906                 if (isr == 0)
907                         break;
908 #if DEBUG & 4
909                 printf("rdp%d: ISR = %#x\n", unit, isr);
910 #endif
911
912                 /*
913                  * Clear the pending interrupt bits.
914                  */
915                 WrNib(sc, ISR, isr & 0x0f);
916                 if (isr & 0xf0)
917                         WrNib(sc, ISR + HNib, MkHi(isr));
918
919                 /*
920                  * Handle transmitter interrupts.
921                  */
922                 if (isr & (ISR_TOK | ISR_TER)) {
923                         tsr = RdNib(sc, TSR);
924                         RdEnd(sc, TSR);
925 #if DEBUG & 4
926                         if (isr & ISR_TER)
927                                 printf("rdp%d: tsr %#x\n", unit, tsr);
928 #endif
929                         if (tsr & TSR_TABT)
930                                 ifp->if_oerrors++;
931                         else
932                                 /*
933                                  * Update total number of successfully
934                                  * transmitted packets.
935                                  */
936                                 ifp->if_opackets++;
937
938                         if (tsr & TSR_COL) {
939                                 colls = RdNib(sc, COLR);
940                                 RdEnd(sc, COLR);
941                                 ifp->if_collisions += colls;
942                         }
943
944                         /*
945                          * reset tx busy and output active flags
946                          */
947                         sc->txbusy = 0;
948                         ifp->if_flags &= ~IFF_OACTIVE;
949
950                         /*
951                          * If we had already queued up another packet,
952                          * start sending it now.
953                          */
954                         if (sc->txbuffered) {
955                                 WrNib(sc, TBCR1, sc->txsize >> 8);
956                                 WrByte(sc, TBCR0, sc->txsize & 0xff);
957                                 WrNib(sc, CMR1, CMR1_TRA);
958                                 sc->txbusy = 1;
959                                 sc->txbuffered = 0;
960                                 ifp->if_timer = 2;
961                         } else {
962                                 /*
963                                  * clear watchdog timer
964                                  */
965                                 ifp->if_timer = 0;
966                         }
967                         
968                 }
969
970                 /*
971                  * Handle receiver interrupts
972                  */
973                 if (isr & (ISR_ROK | ISR_RER | ISR_RBER)) {
974                         rsr = RdNib(sc, RSR);
975                         rsr |= RdNib(sc, RSR + HNib) << 4;
976                         RdEnd(sc, RSR + HNib);
977 #if DEBUG & 4
978                         if (isr & (ISR_RER | ISR_RBER))
979                                 printf("rdp%d: rsr %#x\n", unit, rsr);
980 #endif
981
982                         if (rsr & (RSR_PUN | RSR_POV)) {
983                                 printf("rdp%d: rsr %#x, resetting\n",
984                                        unit, rsr);
985                                 rdp_reset(ifp);
986                                 break;
987                         }
988
989                         if (rsr & RSR_BUFO)
990                                 /*
991                                  * CRC and FA errors are recorded in
992                                  * rdp_rint() on a per-packet basis
993                                  */
994                                 ifp->if_ierrors++;
995                         if (isr & (ISR_ROK | ISR_RER))
996                                 rdp_rint(sc);
997                 }
998
999                 /*
1000                  * If it looks like the transmitter can take more data,
1001                  * attempt to start output on the interface. This is done
1002                  * after handling the receiver to give the receiver priority.
1003                  */
1004                 if ((ifp->if_flags & IFF_OACTIVE) == 0)
1005                         rdp_start(ifp);
1006
1007         }
1008         /* re-enable interrupts */
1009         WrNib(sc, CMR2, CMR2_IRQOUT | CMR2_IRQINV);
1010         sc->irqenbit = Ctrl_IRQEN;
1011         outb(sc->baseaddr + lpt_control, Ctrl_SelData + sc->irqenbit);
1012 }
1013
1014 /*
1015  * Ethernet interface receiver interrupt.
1016  */
1017 static void
1018 rdp_rint(struct rdp_softc *sc)
1019 {
1020         struct ifnet *ifp = &sc->arpcom.ac_if;
1021         struct rdphdr rh;
1022         u_short len;
1023         size_t i;
1024         u_char *packet_ptr, b, status;
1025         int excessive_bad_pkts = 0;
1026
1027         /*
1028          * Fetch the packets from the NIC's buffer.
1029          */
1030         for (;;) {
1031                 b = RdNib(sc, CMR1);
1032                 RdEnd(sc, CMR1);
1033
1034                 if (b & CMR1_BUFE)
1035                         /* no more packets */
1036                         break;
1037
1038                 /* first, obtain the buffer header */
1039                 
1040                 outb(sc->baseaddr + lpt_data, MAR + EOC); /* prepare addr */
1041                 outb(sc->baseaddr + lpt_control, Ctrl_LNibRead);
1042                 outb(sc->baseaddr + lpt_data, MAR + RdAddr + HNib);
1043
1044                 packet_ptr = (u_char *)&rh;
1045                 if (sc->slow)
1046                         for (i = 0; i < sizeof rh; i++, packet_ptr++)
1047                                 *packet_ptr = RdByteA2(sc);
1048                 else
1049                         for (i = 0; i < sizeof rh; i++, packet_ptr++)
1050                                 *packet_ptr = RdByteA1(sc);
1051
1052                 RdEnd(sc, MAR + HNib);
1053                 outb(sc->baseaddr + lpt_control, Ctrl_SelData);
1054
1055                 len = rh.pktlen - ETHER_CRC_LEN;
1056                 status = rh.status;
1057
1058                 if ((status & (RSR_ROK | RSR_CRC | RSR_FA)) != RSR_ROK ||
1059                     len > (ETHER_MAX_LEN - ETHER_CRC_LEN) ||
1060                     len < (ETHER_MIN_LEN - ETHER_CRC_LEN) ||
1061                     len > MCLBYTES) {
1062 #if DEBUG
1063                         printf("rdp%d: bad packet in buffer, "
1064                                "len %d, status %#x\n",
1065                                ifp->if_unit, (int)len, (int)status);
1066 #endif
1067                         ifp->if_ierrors++;
1068                         /* rx jump packet */
1069                         WrNib(sc, CMR1, CMR1_RDPAC);
1070                         if (++excessive_bad_pkts > 5) {
1071                                 /*
1072                                  * the chip seems to be stuck, we are
1073                                  * probably seeing the same bad packet
1074                                  * over and over again
1075                                  */
1076 #if DEBUG
1077                                 printf("rdp%d: resetting due to an "
1078                                        "excessive number of bad packets\n",
1079                                        ifp->if_unit);
1080 #endif
1081                                 rdp_reset(ifp);
1082                                 return;
1083                         }
1084                         continue;
1085                 }
1086
1087                 /*
1088                  * Go get packet.
1089                  */
1090                 excessive_bad_pkts = 0;
1091                 rdp_get_packet(sc, len);
1092                 ifp->if_ipackets++;
1093         }
1094 }
1095
1096 /*
1097  * Retreive packet from NIC memory and send to the next level up via
1098  * ether_input().
1099  */
1100 static void
1101 rdp_get_packet(struct rdp_softc *sc, unsigned len)
1102 {
1103         struct ether_header *eh;
1104         struct mbuf *m;
1105         u_char *packet_ptr;
1106         size_t s;
1107
1108         /* Allocate a header mbuf */
1109         MGETHDR(m, M_DONTWAIT, MT_DATA);
1110         if (m == NULL)
1111                 return;
1112         m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
1113         m->m_pkthdr.len = m->m_len = len;
1114
1115         /*
1116          * We always put the received packet in a single buffer -
1117          * either with just an mbuf header or in a cluster attached
1118          * to the header. The +2 is to compensate for the alignment
1119          * fixup below.
1120          */
1121         if ((len + 2) > MHLEN) {
1122                 /* Attach an mbuf cluster */
1123                 MCLGET(m, M_DONTWAIT);
1124
1125                 /* Insist on getting a cluster */
1126                 if ((m->m_flags & M_EXT) == 0) {
1127                         m_freem(m);
1128                         return;
1129                 }
1130         }
1131
1132         /*
1133          * The +2 is to longword align the start of the real packet.
1134          * This is important for NFS.
1135          */
1136         m->m_data += 2;
1137         eh = mtod(m, struct ether_header *);
1138
1139         /*
1140          * Get packet, including link layer address, from interface.
1141          */
1142         outb(sc->baseaddr + lpt_control, Ctrl_LNibRead);
1143         outb(sc->baseaddr + lpt_data, RdAddr + MAR);
1144
1145         packet_ptr = (u_char *)eh;
1146         if (sc->slow)
1147                 for (s = 0; s < len; s++, packet_ptr++)
1148                         *packet_ptr = RdByteA2(sc);
1149         else
1150                 for (s = 0; s < len; s++, packet_ptr++)
1151                         *packet_ptr = RdByteA1(sc);
1152
1153         RdEnd(sc, MAR + HNib);
1154         outb(sc->baseaddr + lpt_control, Ctrl_SelData);
1155         WrNib(sc, CMR1, CMR1_RDPAC);
1156
1157         /*
1158          * Remove link layer address.
1159          */
1160         m->m_pkthdr.len = m->m_len = len - sizeof(struct ether_header);
1161         m->m_data += sizeof(struct ether_header);
1162
1163         ether_input(&sc->arpcom.ac_if, eh, m);
1164 }
1165
1166 /*
1167  * Write an mbuf chain to the NIC's tx buffer.
1168  */
1169 static u_short
1170 rdp_write_mbufs(struct rdp_softc *sc, struct mbuf *m)
1171 {
1172         u_short total_len;
1173         struct mbuf *mp;
1174         u_char *dp, b;
1175         int i;
1176
1177         /* First, count up the total number of bytes to copy */
1178         for (total_len = 0, mp = m; mp; mp = mp->m_next)
1179                 total_len += mp->m_len;
1180
1181         if (total_len == 0)
1182                 return 0;
1183
1184         outb(sc->baseaddr + lpt_data, MAR | EOC);
1185
1186         /*
1187          * Transfer the mbuf chain to the NIC memory.
1188          */
1189         if (sc->slow) {
1190                 /* writing the first byte is complicated */
1191                 outb(sc->baseaddr + lpt_control,
1192                      Ctrl_LNibRead | sc->irqenbit);
1193                 outb(sc->baseaddr + lpt_data, MAR | WrAddr);
1194                 b = *(u_char *)m->m_data;
1195                 outb(sc->baseaddr + lpt_data, (b & 0x0f) | 0x40);
1196                 outb(sc->baseaddr + lpt_data, b & 0x0f);
1197                 outb(sc->baseaddr + lpt_data, b >> 4);
1198                 outb(sc->baseaddr + lpt_control,
1199                      Ctrl_HNibRead | sc->irqenbit);
1200                 /* advance the mbuf pointer */
1201                 mp = m;
1202                 m->m_len--;
1203                 m->m_data++;
1204                 /* write the remaining bytes */
1205                 while (m) {
1206                         for (i = 0, dp = (u_char *)m->m_data;
1207                              i < m->m_len;
1208                              i++, dp++)
1209                                 WrByteALToDRAMA(sc, *dp);
1210                         m = m->m_next;
1211                 }
1212                 /*
1213                  * restore old mbuf in case we have to hand it off to
1214                  * BPF again
1215                  */
1216                 m = mp;
1217                 m->m_len++;
1218                 m->m_data--;
1219
1220                 /* the RTL 8002 requires an even byte-count remote DMA */
1221                 if (total_len & 1)
1222                         WrByteALToDRAMA(sc, 0);
1223         } else {
1224                 outb(sc->baseaddr + lpt_data, MAR | WrAddr);
1225                 while (m) {
1226                         for (i = 0, dp = (u_char *)m->m_data;
1227                              i < m->m_len;
1228                              i++, dp++)
1229                                 WrByteALToDRAM(sc, *dp);
1230                         m = m->m_next;
1231                 }
1232
1233                 /* the RTL 8002 requires an even byte-count remote DMA */
1234                 if (total_len & 1)
1235                         WrByteALToDRAM(sc, 0);
1236         }
1237
1238         outb(sc->baseaddr + lpt_data, 0xff);
1239         outb(sc->baseaddr + lpt_control,
1240              Ctrl_HNibRead | Ctrl_SelData | sc->irqenbit);
1241
1242         return total_len;
1243 }
1244
1245 /*
1246  * Read the designated ethernet hardware address out of a 93C46
1247  * (serial) EEPROM.
1248  * Note that the 93C46 uses 16-bit words in big-endian notation.
1249  */
1250 static int
1251 rdp_gethwaddr_93c46(struct rdp_softc *sc, u_char *etheraddr)
1252 {
1253         int i, magic;
1254         size_t j = 0;
1255         u_short w;
1256
1257         WrNib(sc, CMR2, CMR2_PAGE | CMR2_IRQINV); /* select page 1 */
1258
1259         /*
1260          * The original RealTek packet driver had the ethernet address
1261          * starting at EEPROM address 0.  Other vendors seem to have
1262          * gone `creative' here -- while they didn't do anything else
1263          * than changing a few strings in the entire driver, compared
1264          * to the RealTek version, they also moved out the ethernet
1265          * address to a different location in the EEPROM, so the
1266          * original RealTek driver won't work correctly with them, and
1267          * vice versa.  Sounds pretty cool, eh?  $@%&!
1268          *
1269          * Anyway, we walk through the EEPROM, until we find some
1270          * allowable value based upon our table of IEEE OUI assignments.
1271          */
1272         for (i = magic = 0; magic < 3 && i < 32; i++) {
1273                 /* read cmd (+ 6 bit address) */
1274                 rdp_93c46_cmd(sc, 0x180 + i, 10);
1275                 w = rdp_93c46_read(sc);
1276                 switch (magic) {
1277                 case 0:
1278                         for (j = 0;
1279                              j < sizeof allowed_ouis / sizeof(u_short);
1280                              j++)
1281                                 if (w == allowed_ouis[j]) {
1282                                         etheraddr[0] = (w >> 8) & 0xff;
1283                                         etheraddr[1] = w & 0xff;
1284                                         magic++;
1285                                         break;
1286                                 }
1287                         break;
1288
1289                 case 1:
1290                         /*
1291                          * If the first two bytes have been 00:00, we
1292                          * discard the match iff the next two bytes
1293                          * are also 00:00, so we won't get fooled by
1294                          * an EEPROM that has been filled with zeros.
1295                          * This in theory would disallow 64 K of legal
1296                          * addresses assigned to Xerox, but it's
1297                          * almost certain that those addresses haven't
1298                          * been used for RTL80[01]2 chips anyway.
1299                          */
1300                         if ((etheraddr[0] | etheraddr[1]) == 0 && w == 0) {
1301                                 magic--;
1302                                 break;
1303                         }
1304
1305                         etheraddr[2] = (w >> 8) & 0xff;
1306                         etheraddr[3] = w & 0xff;
1307                         magic++;
1308                         break;
1309
1310                 case 2:
1311                         etheraddr[4] = (w >> 8) & 0xff;
1312                         etheraddr[5] = w & 0xff;
1313                         magic++;
1314                         break;
1315                 }
1316         }
1317
1318         WrNib(sc, CMR2, CMR2_IRQINV);   /* back to page 0 */
1319
1320         return magic == 3;
1321 }
1322
1323 /*
1324  * Read the designated ethernet hardware address out of a 74S288
1325  * EEPROM.
1326  *
1327  * This is untested, since i haven't seen any adapter actually using
1328  * a 74S288.  In the RTL 8012, only the serial EEPROM (94C46) is
1329  * supported anymore.
1330  */
1331 static void
1332 rdp_gethwaddr_74s288(struct rdp_softc *sc, u_char *etheraddr)
1333 {
1334         int i;
1335         u_char b;
1336
1337         WrNib(sc, CMR2, CMR2_PAGE | CMR2_IRQINV); /* select page 1 */
1338
1339         for (i = 0; i < 6; i++) {
1340                 WrNib(sc, PCMR, i & 0x0f); /* lower 4 bit of addr */
1341                 WrNib(sc, PCMR + HNib, HNib + 4); /* upper 2 bit addr + /CS */
1342                 WrNib(sc, PCMR + HNib, HNib); /* latch data now */
1343                 b = RdNib(sc, PDR) & 0x0f;
1344                 b |= (RdNib(sc, PDR + HNib) & 0x0f) << 4;
1345                 etheraddr[i] = b;
1346         }
1347
1348         RdEnd(sc, PDR + HNib);
1349         WrNib(sc, CMR2, CMR2_IRQINV);   /* reselect page 0 */
1350 }
1351
1352 /*
1353  * Send nbits of data (starting with MSB) out to the 93c46 as a
1354  * command.  Assumes register page 1 has already been selected.
1355  */
1356 static void
1357 rdp_93c46_cmd(struct rdp_softc *sc, u_short data, unsigned nbits)
1358 {
1359         u_short mask = 1 << (nbits - 1);
1360         unsigned i;
1361         u_char b;
1362
1363 #if DEBUG & 2
1364         printf("rdp_93c46_cmd(): ");
1365 #endif
1366         for (i = 0; i < nbits; i++, mask >>= 1) {
1367                 b = HNib + PCMR_SK + PCMR_CS;
1368                 if (data & mask)
1369                         b += PCMR_DO;
1370 #if DEBUG & 2
1371                 printf("%d", b & 1);
1372 #endif
1373                 WrNib(sc, PCMR + HNib, b);
1374                 DELAY(1);
1375                 WrNib(sc, PCMR + HNib, b & ~PCMR_SK);
1376                 DELAY(1);
1377         }
1378 #if DEBUG & 2
1379         printf("\n");
1380 #endif
1381 }
1382
1383 /*
1384  * Read one word of data from the 93c46.  Actually, we have to read
1385  * 17 bits, and discard the very first bit.  Assumes register page 1
1386  * to be selected as well.
1387  */
1388 static u_short
1389 rdp_93c46_read(struct rdp_softc *sc)
1390 {
1391         u_short data = 0;
1392         u_char b;
1393         int i;
1394
1395 #if DEBUG & 2
1396         printf("rdp_93c46_read(): ");
1397 #endif
1398         for (i = 0; i < 17; i++) {
1399                 WrNib(sc, PCMR + HNib, PCMR_SK + PCMR_CS + HNib);
1400                 DELAY(1);
1401                 WrNib(sc, PCMR + HNib, PCMR_CS + HNib);
1402                 DELAY(1);
1403                 b = RdNib(sc, PDR);
1404                 data <<= 1;
1405                 if (b & 1)
1406                         data |= 1;
1407 #if DEBUG & 2
1408                 printf("%d", b & 1);
1409 #endif
1410                 RdEnd(sc, PDR);
1411                 DELAY(1);
1412         }
1413
1414 #if DEBUG & 2
1415         printf("\n");
1416 #endif
1417         /* end of cycle */
1418         WrNib(sc, PCMR + HNib, PCMR_SK + HNib);
1419         DELAY(1);
1420
1421         return data;
1422 }