__P!= wanted
[dragonfly.git] / sys / dev / netif / snc / dp83932subr.c
1 /*      $FreeBSD: src/sys/dev/snc/dp83932subr.c,v 1.2.2.2 2003/06/01 04:24:50 nyan Exp $        */
2 /*      $DragonFly: src/sys/dev/netif/snc/Attic/dp83932subr.c,v 1.4 2003/08/27 09:38:32 rob Exp $       */
3 /*      $NecBSD: dp83932subr.c,v 1.5.6.2 1999/10/09 05:47:23 kmatsuda Exp $     */
4 /*      $NetBSD$        */
5   
6 /*
7  * Copyright (c) 1997, 1998, 1999
8  *      Kouichi Matsuda.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by Kouichi Matsuda for
21  *      NetBSD/pc98.
22  * 4. The name of the author may not be used to endorse or promote products
23  *    derived from this software without specific prior written permission
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 /*
37  * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R 
38  * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda.
39  *
40  * These cards use National Semiconductor DP83934AVQB as Ethernet Controller
41  * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM.
42  */
43
44 /*
45  * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki.
46  */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/mbuf.h>
51 #include <sys/protosw.h>
52 #include <sys/socket.h>
53 #include <sys/syslog.h>
54 #include <sys/errno.h>
55
56 #include <net/ethernet.h>
57 #include <net/if.h>
58 #include <net/if_arp.h>
59 #include <net/if_dl.h>
60 #include <net/if_types.h>
61 #include <net/if_media.h>
62
63 #ifdef INET
64 #include <netinet/in.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/in_var.h>
67 #include <netinet/ip.h>
68 #include <netinet/if_inarp.h>
69 #endif
70
71 #include <net/bpf.h>
72
73 #include <sys/bus.h>
74 #include <machine/clock.h>
75 #include <machine/cpu.h>
76 #include <machine/bus_pio.h>
77 #include <machine/bus_memio.h>
78 #include <machine/bus.h>
79
80 #include "dp83932reg.h"
81 #include "dp83932var.h"
82 #include "if_sncreg.h"
83 #include "dp83932subr.h"
84
85 integrate u_int16_t snc_nec16_select_bank
86         (struct snc_softc *, u_int32_t, u_int32_t);
87
88 /*
89  * Interface exists: make available by filling in network interface
90  * record.  System will initialize the interface when it is ready
91  * to accept packets.
92  */
93 int
94 sncsetup(sc, lladdr)
95         struct snc_softc        *sc;
96         u_int8_t *lladdr;
97 {
98         u_int32_t p, pp;
99         int     i;
100         int     offset;
101
102         /*
103          * Put the pup in reset mode (sncinit() will fix it later),
104          * stop the timer, disable all interrupts and clear any interrupts.
105          */
106         NIC_PUT(sc, SNCR_CR, CR_STP);
107         wbflush();
108         NIC_PUT(sc, SNCR_CR, CR_RST);
109         wbflush();
110         NIC_PUT(sc, SNCR_IMR, 0);
111         wbflush();
112         NIC_PUT(sc, SNCR_ISR, ISR_ALL);
113         wbflush();
114
115         /*
116          * because the SONIC is basically 16bit device it 'concatenates'
117          * a higher buffer address to a 16 bit offset--this will cause wrap
118          * around problems near the end of 64k !!
119          */
120         p = pp = 0;
121
122         for (i = 0; i < NRRA; i++) {
123                 sc->v_rra[i] = SONIC_GETDMA(p);
124                 p += RXRSRC_SIZE(sc);
125         }
126         sc->v_rea = SONIC_GETDMA(p);
127
128         p = SOALIGN(sc, p);
129
130         sc->v_cda = SONIC_GETDMA(p);
131         p += CDA_SIZE(sc);
132
133         p = SOALIGN(sc, p);
134
135         for (i = 0; i < NTDA; i++) {
136                 struct mtd *mtdp = &sc->mtda[i];
137                 mtdp->mtd_vtxp = SONIC_GETDMA(p);
138                 p += TXP_SIZE(sc);
139         }
140
141         p = SOALIGN(sc, p);
142
143         if ((p - pp) > NBPG) {
144                 device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +"
145                     "TDA (%ld) > NBPG (%d). Punt!\n",
146                     (ulong)sc->v_cda - (ulong)sc->v_rra[0],
147                     (ulong)sc->mtda[0].mtd_vtxp - (ulong)sc->v_cda,
148                     (ulong)p - (ulong)sc->mtda[0].mtd_vtxp,
149                     NBPG);
150                 return(1);
151         }
152
153         p = pp + NBPG;
154         pp = p;
155
156         sc->sc_nrda = NBPG / RXPKT_SIZE(sc);
157         sc->v_rda = SONIC_GETDMA(p);
158
159         p = pp + NBPG;
160
161         for (i = 0; i < NRBA; i++) {
162                 sc->rbuf[i] = p;
163                 p += NBPG;
164         }
165
166         pp = p;
167         offset = TXBSIZE;
168         for (i = 0; i < NTDA; i++) {
169                 struct mtd *mtdp = &sc->mtda[i];
170
171                 mtdp->mtd_vbuf = SONIC_GETDMA(p);
172                 offset += TXBSIZE;
173                 if (offset < NBPG) {
174                         p += TXBSIZE;
175                 } else {
176                         p = pp + NBPG;
177                         pp = p;
178                         offset = TXBSIZE;
179                 }
180         }
181
182         return (0);
183 }
184
185 /*
186  * miscellaneous NEC/SONIC detect functions.
187  */
188
189 /*
190  * check if a specified irq is acceptable.
191  */
192 u_int8_t
193 snc_nec16_validate_irq(irq)
194         int irq;
195 {
196         const u_int8_t encoded_irq[16] = {
197             -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1
198         };
199
200         return encoded_irq[irq];
201 }
202
203 /*
204  * specify irq to board.
205  */
206 int
207 snc_nec16_register_irq(sc, irq)
208         struct snc_softc *sc;
209         int irq;
210 {
211         bus_space_tag_t iot = sc->sc_iot;
212         bus_space_handle_t ioh = sc->sc_ioh;
213         u_int8_t encoded_irq;
214
215         encoded_irq = snc_nec16_validate_irq(irq);
216         if (encoded_irq == (u_int8_t) -1) {
217                 printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq);
218                 return 0;
219         }
220
221         /* select SNECR_IRQSEL register */
222         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL);
223         /* write encoded irq value */
224         bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq);
225
226         return 1;
227 }
228
229 /*
230  * check if a specified memory base address is acceptable.
231  */
232 int
233 snc_nec16_validate_mem(maddr)
234         int maddr;
235 {
236
237         /* Check on Normal mode with max range, only */
238         if ((maddr & ~0x1E000) != 0xC0000) {
239                 printf("snc_nec16_validate_mem: "
240                     "unsupported window base (0x%x)\n", maddr);
241                 return 0;
242         }
243
244         return 1;
245 }
246
247 /*
248  * specify memory base address to board and map to first bank.
249  */
250 int
251 snc_nec16_register_mem(sc, maddr)
252         struct snc_softc *sc;
253         int maddr;
254 {
255         bus_space_tag_t iot = sc->sc_iot;
256         bus_space_handle_t ioh = sc->sc_ioh;
257
258         if (snc_nec16_validate_mem(maddr) == 0)
259                 return 0;
260
261         /* select SNECR_MEMSEL register */
262         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL);
263         /* write encoded memory base select value */
264         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr));
265
266         /*
267          * set current bank to 0 (bottom) and map
268          */
269         /* select SNECR_MEMBS register */
270         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
271         /* select new bank */
272         bus_space_write_1(iot, ioh, SNEC_CTRLB,
273             SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN);
274         /* set current bank to 0 */
275         sc->curbank = 0;
276
277         return 1;
278 }
279
280 int
281 snc_nec16_check_memory(iot, ioh, memt, memh)
282         bus_space_tag_t iot;
283         bus_space_handle_t ioh;
284         bus_space_tag_t memt;
285         bus_space_handle_t memh;
286 {
287         u_int16_t val;
288         int i, j;
289
290         val = 0;
291         for (i = 0; i < SNEC_NBANK; i++) {
292                 /* select new bank */
293                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
294                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
295                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
296
297                 /* write test pattern */
298                 for (j = 0; j < SNEC_NMEMS / 2; j++) {
299                         bus_space_write_2(memt, memh, j * 2, val + j);
300                 }
301                 val += 0x1000;
302         }
303
304         val = 0;
305         for (i = 0; i < SNEC_NBANK; i++) {
306                 /* select new bank */
307                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
308                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
309                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
310
311                 /* read test pattern */
312                 for (j = 0; j < SNEC_NMEMS / 2; j++) {
313                         if (bus_space_read_2(memt, memh, j * 2) != val + j)
314                                 break;
315                 }
316
317                 if (j < SNEC_NMEMS / 2) {
318                         printf("snc_nec16_check_memory: "
319                             "memory check failed at 0x%04x%04x"
320                             "val 0x%04x != expected 0x%04x\n", i, j,
321                             bus_space_read_2(memt, memh, j * 2),
322                             val + j);
323                         return 0;
324                 }
325                 val += 0x1000;
326         }
327
328         /* zero clear mem */
329         for (i = 0; i < SNEC_NBANK; i++) {
330                 /* select new bank */
331                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
332                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
333                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
334
335                 bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2);
336         }
337
338         /* again read test if these are 0 */
339         for (i = 0; i < SNEC_NBANK; i++) {
340                 /* select new bank */
341                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
342                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
343                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
344
345                 /* check if cleared */
346                 for (j = 0; j < SNEC_NMEMS; j += 2) {
347                         if (bus_space_read_2(memt, memh, j) != 0)
348                                 break;
349                 }
350
351                 if (j != SNEC_NMEMS) {
352                         printf("snc_nec16_check_memory: "
353                             "memory zero clear failed at 0x%04x%04x\n", i, j);
354                         return 0;
355                 }
356         }
357
358         return 1;
359 }
360
361 int
362 snc_nec16_detectsubr(iot, ioh, memt, memh, irq, maddr, type)
363         bus_space_tag_t iot;
364         bus_space_handle_t ioh;
365         bus_space_tag_t memt;
366         bus_space_handle_t memh;
367         int irq;
368         int maddr;
369         u_int8_t type;
370 {
371         u_int16_t cr;
372         u_int8_t ident;
373         int rv = 0;
374
375         if (snc_nec16_validate_irq(irq) == (u_int8_t) -1)
376                 return 0;
377         /* XXX: maddr already checked */
378         if (snc_nec16_validate_mem(maddr) == 0)
379                 return 0;
380
381         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT);
382         ident = bus_space_read_1(iot, ioh, SNEC_CTRLB);
383         if (ident == 0xff || ident == 0x00) {
384                 /* not found */
385                 return 0;
386         }
387
388         switch (type) {
389         case SNEC_TYPE_LEGACY:
390                 rv = (ident == SNECR_IDENT_LEGACY_CBUS);
391                 break;
392         case SNEC_TYPE_PNP:
393                 rv = ((ident == SNECR_IDENT_PNP_CBUS) ||
394                     (ident == SNECR_IDENT_PNP_PCMCIABUS));
395                 break;
396         default:
397                 break;
398         }
399
400         if (rv == 0) {
401                 printf("snc_nec16_detectsubr: parent bus mismatch\n");
402                 return 0;
403         }
404
405         /* select SONIC register SNCR_CR */
406         bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR);
407         bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST);
408         delay(400);
409
410         cr = bus_space_read_2(iot, ioh, SNEC_CTRL);
411         if (cr != (CR_RXDIS | CR_STP | CR_RST)) {
412 #ifdef DIAGNOSTIC
413                 printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n",
414                     cr);
415 #endif
416                 return 0;
417         }
418
419         if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0)
420                 return 0;
421
422         return 1;
423 }
424
425 /* XXX */
426 #define SNC_VENDOR_NEC          0x00004c
427 #define SNC_NEC_SERIES_LEGACY_CBUS      0xa5
428 #define SNC_NEC_SERIES_PNP_PCMCIA       0xd5
429 #define SNC_NEC_SERIES_PNP_PCMCIA2      0x6d    /* XXX */
430 #define SNC_NEC_SERIES_PNP_CBUS         0x0d
431 #define SNC_NEC_SERIES_PNP_CBUS2        0x3d
432
433 u_int8_t *
434 snc_nec16_detect_type(myea)
435         u_int8_t *myea;
436 {
437         u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2];
438         u_int8_t series = myea[3];
439         u_int8_t type = myea[4] & 0x80;
440         u_int8_t *typestr;
441
442         switch (vendor) {
443         case SNC_VENDOR_NEC:
444                 switch (series) {
445                 case SNC_NEC_SERIES_LEGACY_CBUS:
446                         if (type)
447                                 typestr = "NEC PC-9801-84";
448                         else
449                                 typestr = "NEC PC-9801-83";
450                         break;
451                 case SNC_NEC_SERIES_PNP_CBUS:
452                 case SNC_NEC_SERIES_PNP_CBUS2:
453                         if (type)
454                                 typestr = "NEC PC-9801-104";
455                         else
456                                 typestr = "NEC PC-9801-103";
457                         break;
458                 case SNC_NEC_SERIES_PNP_PCMCIA:
459                 case SNC_NEC_SERIES_PNP_PCMCIA2:
460                         /* XXX: right ? */
461                         if (type)
462                                 typestr = "NEC PC-9801N-J02R";
463                         else
464                                 typestr = "NEC PC-9801N-J02";
465                         break;
466                 default:
467                         typestr = "NEC unknown (PC-9801N-25?)";
468                         break;
469                 }
470                 break;
471         default:
472                 typestr = "unknown (3rd vendor?)";
473                 break;
474         }
475
476         return typestr;
477 }
478
479 int
480 snc_nec16_get_enaddr(iot, ioh, myea)
481         bus_space_tag_t iot;
482         bus_space_handle_t ioh;
483         u_int8_t *myea;
484 {
485         u_int8_t eeprom[SNEC_EEPROM_SIZE];
486         u_int8_t rom_sum, sum = 0x00;
487         int i;
488
489         snc_nec16_read_eeprom(iot, ioh, eeprom);
490
491         for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) {
492                 sum = sum ^ eeprom[i];
493         }
494
495         rom_sum = eeprom[SNEC_EEPROM_CKSUM];
496
497         if (sum != rom_sum) {
498                 printf("snc_nec16_get_enaddr: "
499                     "checksum mismatch; calculated %02x != read %02x",
500                     sum, rom_sum);
501                 return 0;
502         }
503
504         for (i = 0; i < ETHER_ADDR_LEN; i++)
505                 myea[i] = eeprom[SNEC_EEPROM_SA0 + i];
506
507         return 1;
508 }
509
510 /*
511  * read from NEC/SONIC NIC register.
512  */
513 u_int16_t
514 snc_nec16_nic_get(sc, reg)
515         struct snc_softc *sc;
516         u_int8_t reg;
517 {
518         u_int16_t val;
519
520         /* select SONIC register */
521         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg);
522         val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL);
523
524         return val;
525 }
526
527 /*
528  * write to NEC/SONIC NIC register.
529  */
530 void
531 snc_nec16_nic_put(sc, reg, val)
532         struct snc_softc *sc;
533         u_int8_t reg;
534         u_int16_t val;
535 {
536
537         /* select SONIC register */
538         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg);
539         bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val);
540 }
541
542
543 /*
544  * select memory bank and map
545  * where exists specified (internal buffer memory) offset.
546  */
547 integrate u_int16_t
548 snc_nec16_select_bank(sc, base, offset)
549         struct snc_softc *sc;
550         u_int32_t base;
551         u_int32_t offset;
552 {
553         bus_space_tag_t iot = sc->sc_iot;
554         bus_space_handle_t ioh = sc->sc_ioh;
555         u_int8_t bank;
556         u_int16_t noffset;
557
558         /* bitmode is fixed to 16 bit. */
559         bank = (base + offset * 2) >> 13;
560         noffset = (base + offset * 2) & (SNEC_NMEMS - 1);
561
562 #ifdef SNCDEBUG
563         if (noffset % 2) {
564                 device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n",
565                               noffset);
566         }
567 #endif  /* SNCDEBUG */
568
569         if (sc->curbank != bank) {
570                 /* select SNECR_MEMBS register */
571                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
572                 /* select new bank */
573                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
574                     SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN);
575                 /* update current bank */
576                 sc->curbank = bank;
577         }
578
579         return noffset;
580 }
581
582 /*
583  * write to SONIC descriptors.
584  */
585 void
586 snc_nec16_writetodesc(sc, base, offset, val)
587         struct snc_softc *sc;
588         u_int32_t base;
589         u_int32_t offset;
590         u_int16_t val;
591 {
592         bus_space_tag_t memt = sc->sc_memt;
593         bus_space_handle_t memh = sc->sc_memh;
594         u_int16_t noffset;
595
596         noffset = snc_nec16_select_bank(sc, base, offset);
597
598         bus_space_write_2(memt, memh, noffset, val);
599 }
600
601 /*
602  * read from SONIC descriptors.
603  */
604 u_int16_t
605 snc_nec16_readfromdesc(sc, base, offset)
606         struct snc_softc *sc;
607         u_int32_t base;
608         u_int32_t offset;
609 {
610         bus_space_tag_t memt = sc->sc_memt;
611         bus_space_handle_t memh = sc->sc_memh;
612         u_int16_t noffset;
613
614         noffset = snc_nec16_select_bank(sc, base, offset);
615
616         return bus_space_read_2(memt, memh, noffset);
617 }
618
619 /*
620  * read from SONIC data buffer.
621  */
622 void
623 snc_nec16_copyfrombuf(sc, dst, offset, size)
624         struct snc_softc *sc;
625         void *dst;
626         u_int32_t offset;
627         size_t size;
628 {
629         bus_space_tag_t memt = sc->sc_memt;
630         bus_space_handle_t memh = sc->sc_memh;
631         u_int16_t noffset;
632         u_int8_t* bptr = dst;
633
634         noffset = snc_nec16_select_bank(sc, offset, 0);
635
636         /* XXX: should check if offset + size < 0x2000. */
637
638         bus_space_barrier(memt, memh, noffset, size,
639                           BUS_SPACE_BARRIER_READ);
640
641         if (size > 3)  {
642                 if (noffset & 3)  {
643                         size_t asize = 4 - (noffset & 3);
644
645                         bus_space_read_region_1(memt, memh, noffset,
646                             bptr, asize);
647                         bptr += asize;
648                         noffset += asize;
649                         size -= asize;
650                 }
651                 bus_space_read_region_4(memt, memh, noffset,
652                     (u_int32_t *) bptr, size >> 2);
653                 bptr += size & ~3;
654                 noffset += size & ~3;
655                 size &= 3;
656         }
657         if (size)
658                 bus_space_read_region_1(memt, memh, noffset, bptr, size);
659 }
660
661 /*
662  * write to SONIC data buffer.
663  */
664 void
665 snc_nec16_copytobuf(sc, src, offset, size)
666         struct snc_softc *sc;
667         void *src;
668         u_int32_t offset;
669         size_t size;
670 {
671         bus_space_tag_t memt = sc->sc_memt;
672         bus_space_handle_t memh = sc->sc_memh;
673         u_int16_t noffset, onoffset;
674         size_t osize = size;
675         u_int8_t* bptr = src;
676
677         noffset = snc_nec16_select_bank(sc, offset, 0);
678         onoffset = noffset;
679
680         /* XXX: should check if offset + size < 0x2000. */
681
682         if (size > 3)  {
683                 if (noffset & 3)  {
684                         size_t asize = 4 - (noffset & 3);
685
686                         bus_space_write_region_1(memt, memh, noffset,
687                             bptr, asize);
688                         bptr += asize;
689                         noffset += asize;
690                         size -= asize;
691                 }
692                 bus_space_write_region_4(memt, memh, noffset,
693                     (u_int32_t *)bptr, size >> 2);
694                 bptr += size & ~3;
695                 noffset += size & ~3;
696                 size -= size & ~3;
697         }
698         if (size)
699                 bus_space_write_region_1(memt, memh, noffset, bptr, size);
700
701         bus_space_barrier(memt, memh, onoffset, osize,
702                           BUS_SPACE_BARRIER_WRITE);
703 }
704
705 /*
706  * write (fill) 0 to SONIC data buffer.
707  */
708 void
709 snc_nec16_zerobuf(sc, offset, size)
710         struct snc_softc *sc;
711         u_int32_t offset;
712         size_t size;
713 {
714         bus_space_tag_t memt = sc->sc_memt;
715         bus_space_handle_t memh = sc->sc_memh;
716         u_int16_t noffset, onoffset;
717         size_t osize = size;
718
719         noffset = snc_nec16_select_bank(sc, offset, 0);
720         onoffset = noffset;
721
722         /* XXX: should check if offset + size < 0x2000. */
723
724         if (size > 3)  {
725                 if (noffset & 3)  {
726                         size_t asize = 4 - (noffset & 3);
727
728                         bus_space_set_region_1(memt, memh, noffset, 0, asize);
729                         noffset += asize;
730                         size -= asize;
731                 }
732                 bus_space_set_region_4(memt, memh, noffset, 0, size >> 2);
733                 noffset += size & ~3;
734                 size -= size & ~3;
735         }
736         if (size)
737                 bus_space_set_region_1(memt, memh, noffset, 0, size);
738
739         bus_space_barrier(memt, memh, onoffset, osize,
740                           BUS_SPACE_BARRIER_WRITE);
741 }
742
743
744 /* 
745  * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83,
746  * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98.
747  * Ported by Kouichi Matsuda.
748  * 
749  * This algorism is generic to read data sequentially from 4-Wire
750  * Microwire Serial EEPROM.
751  */
752
753 #define SNEC_EEP_DELAY  1000
754
755 void
756 snc_nec16_read_eeprom(iot, ioh, data)
757         bus_space_tag_t iot;
758         bus_space_handle_t ioh;
759         u_int8_t *data;
760 {
761         u_int8_t n, val, bit;
762
763         /* Read bytes from EEPROM; two bytes per an iteration. */
764         for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) {
765                 /* select SNECR_EEP */
766                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP);
767
768                 bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00);
769                 delay(SNEC_EEP_DELAY);
770
771                 /* Start EEPROM access. */
772                 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
773                 delay(SNEC_EEP_DELAY);
774
775                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
776                     SNECR_EEP_CS | SNECR_EEP_SK);
777                 delay(SNEC_EEP_DELAY);
778
779                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
780                     SNECR_EEP_CS | SNECR_EEP_DI);
781                 delay(SNEC_EEP_DELAY);
782
783                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
784                     SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI);
785                 delay(SNEC_EEP_DELAY);
786
787                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
788                     SNECR_EEP_CS | SNECR_EEP_DI);
789                 delay(SNEC_EEP_DELAY);
790
791                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
792                     SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI);
793                 delay(SNEC_EEP_DELAY);
794
795                 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
796                 delay(SNEC_EEP_DELAY);
797
798                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
799                     SNECR_EEP_CS | SNECR_EEP_SK);
800                 delay(SNEC_EEP_DELAY);
801
802                 /* Pass the iteration count to the chip. */
803                 for (bit = 0x20; bit != 0x00; bit >>= 1) {
804                         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS |
805                             ((n & bit) ? SNECR_EEP_DI : 0x00));
806                         delay(SNEC_EEP_DELAY);
807
808                         bus_space_write_1(iot, ioh, SNEC_CTRLB,
809                             SNECR_EEP_CS | SNECR_EEP_SK |
810                             ((n & bit) ? SNECR_EEP_DI : 0x00));
811                         delay(SNEC_EEP_DELAY);
812                 }
813
814                 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
815                 (void) bus_space_read_1(iot, ioh, SNEC_CTRLB);  /* ACK */
816                 delay(SNEC_EEP_DELAY);
817
818                 /* Read a byte. */
819                 val = 0;
820                 for (bit = 0x80; bit != 0x00; bit >>= 1) {
821                         bus_space_write_1(iot, ioh, SNEC_CTRLB,
822                             SNECR_EEP_CS | SNECR_EEP_SK);
823                         delay(SNEC_EEP_DELAY);
824
825                         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
826
827                         if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO)
828                                 val |= bit;
829                 }
830                 *data++ = val;
831
832                 /* Read one more byte. */
833                 val = 0;
834                 for (bit = 0x80; bit != 0x00; bit >>= 1) {
835                         bus_space_write_1(iot, ioh, SNEC_CTRLB,
836                             SNECR_EEP_CS | SNECR_EEP_SK);
837                         delay(SNEC_EEP_DELAY);
838
839                         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
840
841                         if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO)
842                                 val |= bit;
843                 }
844                 *data++ = val;
845
846                 bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00);
847                 delay(SNEC_EEP_DELAY);
848         }
849
850 #ifdef  SNCDEBUG
851         /* Report what we got. */
852         data -= SNEC_EEPROM_SIZE;
853         log(LOG_INFO, "%s: EEPROM:"
854             " %02x%02x%02x%02x %02x%02x%02x%02x -"
855             " %02x%02x%02x%02x %02x%02x%02x%02x -"
856             " %02x%02x%02x%02x %02x%02x%02x%02x -"
857             " %02x%02x%02x%02x %02x%02x%02x%02x\n",
858             "snc_nec16_read_eeprom",
859             data[ 0], data[ 1], data[ 2], data[ 3],
860             data[ 4], data[ 5], data[ 6], data[ 7],
861             data[ 8], data[ 9], data[10], data[11],
862             data[12], data[13], data[14], data[15],
863             data[16], data[17], data[18], data[19],
864             data[20], data[21], data[22], data[23],
865             data[24], data[25], data[26], data[27],
866             data[28], data[29], data[30], data[31]);
867 #endif
868 }
869
870 #ifdef  SNCDEBUG
871 void
872 snc_nec16_dump_reg(iot, ioh)
873         bus_space_tag_t iot;
874         bus_space_handle_t ioh;
875 {
876         u_int8_t n;
877         u_int16_t val;
878
879         printf("SONIC registers (word):");
880         for (n = 0; n < SNC_NREGS; n++) {
881                 /* select required SONIC register */
882                 bus_space_write_1(iot, ioh, SNEC_ADDR, n);
883                 delay(10);
884                 val = bus_space_read_2(iot, ioh, SNEC_CTRL);
885                 if ((n % 0x10) == 0)
886                         printf("\n%04x ", val);
887                 else
888                         printf("%04x ", val);
889         }
890         printf("\n");
891
892         printf("NEC/SONIC registers (byte):\n");
893         for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) {
894                 /* select required SONIC register */
895                 bus_space_write_1(iot, ioh, SNEC_ADDR, n);
896                 delay(10);
897                 val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB);
898                 printf("%04x ", val);
899         }
900         printf("\n");
901 }
902
903 #endif  /* SNCDEBUG */