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