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