? boot/boot.h ? boot/devopen.c ? boot/dp8390.c ? boot/dp8390.h ? boot/if_ne.c ? boot/ne.c ? boot/ne.h ? libsa/clock.c Index: boot/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/boot/Makefile,v retrieving revision 1.22 diff -u -p -r1.22 Makefile --- boot/Makefile 20 Mar 2012 12:37:01 -0000 1.22 +++ boot/Makefile 7 Oct 2012 08:10:51 -0000 @@ -13,6 +13,9 @@ NEWVERSWHAT= "${BOOT}" # text address TEXT= 006000 +# RTC offset +RTC_OFFSET= -540 + PROG= boot BINDIR= /usr/mdec BINMODE= 444 @@ -22,7 +25,8 @@ BFDNAME= a.out-m68k-netbsd STRIP?= /usr/bin/strip OBJCOPY?= /usr/bin/objcopy -SRCS= srt0.S boot.c conf.c exec_image.S +SRCS= srt0.S boot.c conf.c devopen.c exec_image.S +SRCS+= if_ne.c ne.c dp8390.c S= ${.CURDIR}/../../../.. M= ${.CURDIR}/../.. COMMONDIR= $M/stand/common @@ -40,7 +44,10 @@ CPPFLAGS+= -I$M/stand/libiocs -I${COMMON CPPFLAGS+= -D_STANDALONE -DHEAP_VARIABLE CPPFLAGS+= -DTEXTADDR="0x${TEXT}" CPPFLAGS+= -DBOOT=\"${BOOT}\" -DBOOT_VERS=\"${VERSION}\" +CPPFLAGS+= -DRTC_OFFSET=${RTC_OFFSET} +CPPFLAGS+= -DSUPPORT_BOOTP -DSUPPORT_DHCP CPPFLAGS+= -DLIBSA_ENABLE_LS_OP +#CPPFLAGS+= -DDEBUG CFLAGS= -Wno-main -Os -m68020-60 LINKFLAGS= -N -static -T ${.CURDIR}/boot.ldscript LIBIOCS!= cd $M/stand/libiocs && ${PRINTOBJDIR} Index: boot/boot.c =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/boot/boot.c,v retrieving revision 1.18 diff -u -p -r1.18 boot.c --- boot/boot.c 20 Mar 2012 12:37:01 -0000 1.18 +++ boot/boot.c 7 Oct 2012 08:10:51 -0000 @@ -32,8 +32,10 @@ #include #include #include +#include #include +#include "boot.h" #include "libx68k.h" #include "iocs.h" @@ -91,6 +93,7 @@ help(void) printf(" dev: sd, ID=0-7, PART=a-p\n"); printf(" cda, ID=0-7\n"); printf(" fda, UNIT=0-3, format is detected.\n"); + printf(" nfs, first probed NE2000 is used.\n"); printf(" file: netbsd, netbsd.gz, etc.\n"); printf(" flags: abdqsv\n"); printf("ls [dev:][directory]\n"); @@ -128,14 +131,23 @@ doboot(const char *file, int flags) printf("dev = %x, unit = %d, part = %c, name = %s\n", dev, unit, part + 'a', name); #endif - - if (dev == 0) { /* SCSI */ + switch (dev) { + case 0: /* SCSI disk */ + case 1: /* SCSI CD */ dev = X68K_MAKESCSIBOOTDEV(X68K_MAJOR_SD, hostadaptor >> 4, hostadaptor & 15, unit & 7, 0, 0); - } else { + break; + case 2: /* floppy */ dev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0); + break; + case 3: /* NFS via Neptune-X or Nereid */ + dev = X68K_MAKEBOOTDEV(X68K_MAJOR_NE, unit, 0); + break; + default: + dev = 0; + break; } #ifdef DEBUG printf("boot device = %x\n", dev); @@ -292,6 +304,8 @@ bootmain(int bootdev) { hostadaptor = get_scsi_host_adapter(); mpu = detectmpu(); + rtc_offset = RTC_OFFSET; + try_bootp = 1; if (mpu < 3) { /* not tested on 68020 */ printf("This MPU cannot run NetBSD.\n"); Index: boot/conf.c =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/boot/conf.c,v retrieving revision 1.9 diff -u -p -r1.9 conf.c --- boot/conf.c 20 Mar 2012 12:38:33 -0000 1.9 +++ boot/conf.c 7 Oct 2012 08:10:51 -0000 @@ -33,21 +33,28 @@ #include #include +#include +#include +#include + +#include "boot.h" #include "libx68k.h" struct devsw devsw[] = { { "sd", sdstrategy, sdopen, sdclose, noioctl }, { "cd", cdstrategy, cdopen, cdclose, noioctl }, { "fd", fdstrategy, fdopen, fdclose, noioctl }, + { "nfs", net_strategy, net_open, net_close, net_ioctl }, { 0, 0, 0, 0, 0 } }; int ndevs = sizeof(devsw) / sizeof(devsw[0]); const struct devspec devspec[] = { - { "sd", 0, 7 }, - { "cd", 1, 7 }, - { "fd", 2, 3 }, + { "sd", 0, 7, 0 }, + { "cd", 1, 7, 0 }, + { "fd", 2, 3, 0 }, + { "nfs", 3, 1, 1 }, { 0, 0, 0 } }; @@ -62,4 +69,14 @@ struct fs_ops file_system[] = { int nfsys = sizeof(file_system) / sizeof(file_system[0]); +struct fs_ops file_system_net = FS_OPS(nfs); + +extern struct netif_driver ne_netif_driver; + +struct netif_driver *netif_drivers[] = { + &ne_netif_driver, +}; + +int n_netif_drivers = sizeof(netif_drivers) / sizeof(netif_drivers[0]); + struct open_file files[SOPEN_MAX]; Index: boot/version =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/boot/version,v retrieving revision 1.5 diff -u -p -r1.5 version --- boot/version 20 Mar 2012 12:38:33 -0000 1.5 +++ boot/version 7 Oct 2012 08:10:51 -0000 @@ -10,3 +10,4 @@ is taken as the current. 1.2: Fix serial console output. 1.3: Avoid exception on 68060 in UFS ops. 1.4: ffsv2 support. +1.5: netboot support. Index: libsa/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/libsa/Makefile,v retrieving revision 1.28 diff -u -p -r1.28 Makefile --- libsa/Makefile 25 Dec 2011 06:09:09 -0000 1.28 +++ libsa/Makefile 7 Oct 2012 08:10:51 -0000 @@ -11,6 +11,7 @@ CPPFLAGS+= -DHEAP_VARIABLE CPPFLAGS+= -DHAVE_CHANGEDISK_HOOK CPPFLAGS+= -DUSTAR_SECT_PER_CYL=16 CPPFLAGS+= -DLIBSA_ENABLE_LS_OP +CPPFLAGS+= -DSUPPORT_BOOTP -DSUPPORT_DHCP #CPPFLAGS+= -DDEBUG .PATH: ${LIBSADIR} ${LIBKERNDIR} ${LIBZDIR} ${LIBZDIST} Index: libsa/Makefile.inc =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/libsa/Makefile.inc,v retrieving revision 1.1 diff -u -p -r1.1 Makefile.inc --- libsa/Makefile.inc 12 Apr 2011 14:07:35 -0000 1.1 +++ libsa/Makefile.inc 7 Oct 2012 08:10:51 -0000 @@ -5,7 +5,8 @@ .PATH.c: ${SA_EXTRADIR} .PATH.S: ${SA_EXTRADIR} -SRCS+= consio.c devopen.c parseutils.c sdcd.c fd.c fdsub.S chdsk.c +SRCS+= consio.c parseutils.c sdcd.c fd.c fdsub.S chdsk.c SRCS+= putimage.S +SRCS+= clock.c -#SRCS+= dev_net.c +SRCS+= dev_net.c Index: libsa/devopen.c =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/libsa/devopen.c,v retrieving revision 1.5 diff -u -p -r1.5 devopen.c --- libsa/devopen.c 11 Apr 2011 14:00:02 -0000 1.5 +++ libsa/devopen.c 7 Oct 2012 08:10:51 -0000 @@ -33,6 +33,7 @@ #include "libx68k.h" extern struct devspec devspec[]; /* defined in conf.c */ +extern struct fs_ops file_system_net; int devopen_open_dir = 0; /* @@ -60,14 +61,22 @@ devparse(const char *fname, int *dev, in s += strlen(devspec[i].ds_name); *dev = devspec[i].ds_dev; - *unit = *s++ - '0'; - if (*unit < 0 || *unit > devspec[i].ds_maxunit) - /* bad unit */ - return ENODEV; - *part = *s++ - 'a'; - if (*part < 0 || *part > MAXPARTITIONS) - /* bad partition */ - return ENODEV; + if (devspec[i].ds_net) { + *unit = 0; + *part = 0; + file_system[0] = file_system_net; + nfsys = 1; + } else { + *unit = *s++ - '0'; + if (*unit < 0 || *unit > devspec[i].ds_maxunit) + /* bad unit */ + return ENODEV; + + *part = *s++ - 'a'; + if (*part < 0 || *part > MAXPARTITIONS) + /* bad partition */ + return ENODEV; + } if (*s++ != ':') return ENODEV; Index: libsa/libx68k.h =================================================================== RCS file: /cvsroot/src/sys/arch/x68k/stand/libsa/libx68k.h,v retrieving revision 1.5 diff -u -p -r1.5 libx68k.h --- libsa/libx68k.h 18 Nov 2007 04:59:51 -0000 1.5 +++ libsa/libx68k.h 7 Oct 2012 08:10:51 -0000 @@ -30,12 +30,6 @@ * Prototypes for x68k-specific libsa functions. */ -struct devspec { - const char *ds_name; - int ds_dev; - int ds_maxunit; -}; - /* consio.c */ int consio_init(int); int check_getchar(void); @@ -62,9 +56,9 @@ int fdstrategy(void *, int, daddr_t, siz int fdopen(struct open_file *, ...); int fdclose(struct open_file *); -/* devopen.c */ -int devparse(const char *, int *, int *, int *, char **); -extern int devopen_open_dir; - /* chdsk.c */ int changedisk_hook(struct open_file *); + +/* clock.c */ +void delay(int); +extern int rtc_offset; --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ boot/boot.h 2012-10-07 16:59:35.000000000 +0900 @@ -0,0 +1,38 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 2001 Minoura Makoto + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct devspec { + const char *ds_name; + int ds_dev; + int ds_maxunit; + int ds_net; /* 1 = network boot (i.e. no partition) */ +}; + +/* devopen.c */ +int devparse(const char *, int *, int *, int *, char **); +extern int devopen_open_dir; --- /dev/null 2012-10-07 17:21:22.000000000 +0900 +++ boot/devopen.c 2012-10-07 17:21:45.000000000 +0900 @@ -0,0 +1,117 @@ +/* $NetBSD: devopen.c,v 1.5 2011/04/11 14:00:02 tsutsui Exp $ */ + +/* + * Copyright (c) 2001 Minoura Makoto + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include /* for MAXPARTITIONS */ +#include +#include +#include "boot.h" +#include "libx68k.h" + +extern struct devspec devspec[]; /* defined in conf.c */ +extern struct fs_ops file_system_net; +int devopen_open_dir = 0; + +/* + * Parse a device spec. + * + * sd: + * unit - 0-7 + * part - a-p + */ +int +devparse(const char *fname, int *dev, int *unit, int *part, char **file) +{ + char const *s; + int i; + + s = fname; + for (i = 0; devspec[i].ds_name != 0; i++) { + if (strncmp (devspec[i].ds_name, s, + strlen(devspec[i].ds_name)) == 0) + break; + } + + if (devspec[i].ds_name == 0) + return ENODEV; + s += strlen(devspec[i].ds_name); + *dev = devspec[i].ds_dev; + + if (devspec[i].ds_net) { + *unit = 0; + *part = 0; + file_system[0] = file_system_net; + nfsys = 1; + } else { + *unit = *s++ - '0'; + if (*unit < 0 || *unit > devspec[i].ds_maxunit) + /* bad unit */ + return ENODEV; + + *part = *s++ - 'a'; + if (*part < 0 || *part > MAXPARTITIONS) + /* bad partition */ + return ENODEV; + } + + if (*s++ != ':') + return ENODEV; + + if (*s == '/') { + s++; + if (devopen_open_dir && *s == 0) + s--; + } + *file = __UNCONST(s); + + return 0; +} + +int +devopen(struct open_file *f, const char *fname, char **file) +{ + int error; + int dev, unit, part; + struct devsw *dp = &devsw[0]; + + error = devparse(fname, &dev, &unit, &part, file); + if (error) + return error; + + dp = &devsw[dev]; + + if (dp->dv_open == NULL) + return ENODEV; + + f->f_dev = dp; + + if ((error = (*dp->dv_open)(f, unit, part)) == 0) + return 0; + + return error; +} --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ boot/dp8390.c 2012-10-07 14:49:19.000000000 +0900 @@ -0,0 +1,300 @@ +/* $NetBSD$ */ +/* $Id: dp8390.c,v 1.14 2011/10/05 13:16:20 isaki Exp $ */ + +/* + * This file is derived from sys/arch/i386/stand/lib/netif/dp8390.c + * NetBSD: dp8390.c,v 1.6 2008/12/14 18:46:33 christos Exp + */ + +/* + * Polling driver for National Semiconductor DS8390/WD83C690 based + * ethernet adapters. + * + * Copyright (c) 1998 Matthias Drochner. All rights reserved. + * + * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. + * + * Copyright (C) 1993, David Greenman. This software may be used, modified, + * copied, distributed, and sold, in both source and binary form provided that + * the above copyright and these terms are retained. Under no circumstances is + * the author responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its use. + */ + + +#include + +#include +#include + +#include +#include "dp8390.h" +#include "ne.h" + +int dp8390_iobase, dp8390_membase, dp8390_memsize; +#if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA) +int dp8390_is790; +#endif +uint8_t dp8390_cr_proto; +uint8_t dp8390_dcr_reg; + +#define WE_IOBASE dp8390_iobase + +static u_short rec_page_start; +static u_short rec_page_stop; +static u_short next_packet; + +extern u_char eth_myaddr[6]; + +static void dp8390_read(int, char *, u_short); + +#define NIC_GET(reg) inb(WE_IOBASE + (reg) * 2) +#define NIC_PUT(reg, val) outb(WE_IOBASE + (reg) * 2, val) + +static void +dp8390_init(void) +{ + int i; + + /* + * Initialize the NIC in the exact order outlined in the NS manual. + * This init procedure is "mandatory"...don't change what or when + * things happen. + */ + + /* Set interface for page 0, remote DMA complete, stopped. */ + NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + + if ((dp8390_dcr_reg & ED_DCR_LS)) { + NIC_PUT(ED_P0_DCR, dp8390_dcr_reg); + } else { + /* + * Set FIFO threshold to 8, No auto-init Remote DMA, byte + * order=80x86, byte-wide DMA xfers, + */ + NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); + } + + /* Clear remote byte count registers. */ + NIC_PUT(ED_P0_RBCR0, 0); + NIC_PUT(ED_P0_RBCR1, 0); + + /* Tell RCR to do nothing for now. */ + NIC_PUT(ED_P0_RCR, ED_RCR_MON); + + /* Place NIC in internal loopback mode. */ + NIC_PUT(ED_P0_TCR, ED_TCR_LB0); + + /* Set lower bits of byte addressable framing to 0. */ + if (dp8390_is790) + NIC_PUT(0x09, 0); + + /* Initialize receive buffer ring. */ + NIC_PUT(ED_P0_BNRY, rec_page_start); + NIC_PUT(ED_P0_PSTART, rec_page_start); + NIC_PUT(ED_P0_PSTOP, rec_page_stop); + + /* + * Clear all interrupts. A '1' in each bit position clears the + * corresponding flag. + */ + NIC_PUT(ED_P0_ISR, 0xff); + + /* + * Disable all interrupts. + */ + NIC_PUT(ED_P0_IMR, 0); + + /* Program command register for page 1. */ + NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP); + + /* Copy out our station address. */ + for (i = 0; i < 6; i++) + NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]); + + /* + * Set current page pointer to one page after the boundary pointer, as + * recommended in the National manual. + */ + next_packet = rec_page_start + 1; + NIC_PUT(ED_P1_CURR, next_packet); + + /* Program command register for page 0. */ + NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + + /* directed and broadcast */ + NIC_PUT(ED_P0_RCR, ED_RCR_AB); + + /* Take interface out of loopback. */ + NIC_PUT(ED_P0_TCR, 0); + + /* Fire up the interface. */ + NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA); +} + +int +dp8390_config(void) +{ + + rec_page_start = TX_PAGE_START + ED_TXBUF_SIZE; + rec_page_stop = TX_PAGE_START + (dp8390_memsize >> ED_PAGE_SHIFT); + + dp8390_init(); + + return 0; +} + +void +dp8390_stop(void) +{ + int n = 5000; + + /* Stop everything on the interface, and select page 0 registers. */ + NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + + /* + * Wait for interface to enter stopped state, but limit # of checks to + * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but + * just in case it's an old one. + */ + while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n) + continue; +} + +int +EtherSend(char *pkt, int len) +{ + ne2000_writemem(pkt, dp8390_membase, len); + + /* Set TX buffer start page. */ + NIC_PUT(ED_P0_TPSR, TX_PAGE_START); + + /* Set TX length. */ + NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len); + NIC_PUT(ED_P0_TBCR1, len >> 8); + + /* Set page 0, remote DMA complete, transmit packet, and *start*. */ + NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA); + + return len; +} + +static void +dp8390_read(int buf, char *dest, u_short len) +{ + u_short tmp_amount; + + /* Does copy wrap to lower addr in ring buffer? */ + if (buf + len > dp8390_membase + dp8390_memsize) { + tmp_amount = dp8390_membase + dp8390_memsize - buf; + + /* Copy amount up to end of NIC memory. */ + ne2000_readmem(buf, dest, tmp_amount); + + len -= tmp_amount; + buf = RX_BUFBASE + (rec_page_start << ED_PAGE_SHIFT); + dest += tmp_amount; + } + ne2000_readmem(buf, dest, len); +} + +int +EtherReceive(char *pkt, int maxlen) +{ + struct dp8390_ring packet_hdr; + int packet_ptr; + u_short len; + u_char boundary, current; +#ifdef DP8390_OLDCHIPS + u_char nlen; +#endif + + if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX)) + return 0; /* XXX error handling */ + + /* Set NIC to page 1 registers to get 'current' pointer. */ + NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STA); + + /* + * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. + * it points to where new data has been buffered. The 'CURR' (current) + * register points to the logical end of the ring-buffer - i.e. it + * points to where additional new data will be added. We loop here + * until the logical beginning equals the logical end (or in other + * words, until the ring-buffer is empty). + */ + current = NIC_GET(ED_P1_CURR); + + /* Set NIC to page 0 registers to update boundary register. */ + NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA); + + if (next_packet == current) + return 0; + + /* Get pointer to this buffer's header structure. */ + packet_ptr = RX_BUFBASE + (next_packet << ED_PAGE_SHIFT); + + /* + * The byte count includes a 4 byte header that was added by + * the NIC. + */ + ne2000_readmem(packet_ptr, (void *)&packet_hdr, 4); + + len = le16toh(packet_hdr.count); + +#ifdef DP8390_OLDCHIPS + /* + * Try do deal with old, buggy chips that sometimes duplicate + * the low byte of the length into the high byte. We do this + * by simply ignoring the high byte of the length and always + * recalculating it. + * + * NOTE: sc->next_packet is pointing at the current packet. + */ + if (packet_hdr.next_packet >= next_packet) + nlen = (packet_hdr.next_packet - next_packet); + else + nlen = ((packet_hdr.next_packet - rec_page_start) + + (rec_page_stop - next_packet)); + --nlen; + if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE) + --nlen; + len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT); +#ifdef DIAGNOSTIC + if (len != packet_hdr.count) { + printf(IFNAME ": length does not match next packet pointer\n"); + printf(IFNAME ": len %04x nlen %04x start %02x " + "first %02x curr %02x next %02x stop %02x\n", + packet_hdr.count, len, + rec_page_start, next_packet, current, + packet_hdr.next_packet, rec_page_stop); + } +#endif +#endif + + if (packet_hdr.next_packet < rec_page_start || + packet_hdr.next_packet >= rec_page_stop) + panic(IFNAME ": RAM corrupt"); + + len -= sizeof(struct dp8390_ring); + if (len <= maxlen) { + /* Go get packet. */ + dp8390_read(packet_ptr + sizeof(struct dp8390_ring), + pkt, len); + } else + len = 0; + + /* Update next packet pointer. */ + next_packet = packet_hdr.next_packet; + + /* + * Update NIC boundary pointer - being careful to keep it one + * buffer behind (as recommended by NS databook). + */ + boundary = next_packet - 1; + if (boundary < rec_page_start) + boundary = rec_page_stop - 1; + NIC_PUT(ED_P0_BNRY, boundary); + + return len; +} --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ boot/dp8390.h 2012-10-07 14:41:01.000000000 +0900 @@ -0,0 +1,36 @@ +/* $NetBSD$ */ +/* $Id: dp8390.h,v 1.7 2011/10/05 13:16:20 isaki Exp $ */ + +/* + * This file is derived from sys/arch/i386/stand/lib/netif/dp8390.h + * NetBSD: dp8390.h,v 1.6 2008/12/14 18:46:33 christos Exp + */ + +int dp8390_config(void); +void dp8390_stop(void); + +extern int dp8390_iobase; +extern int dp8390_membase; +extern int dp8390_memsize; +#ifdef SUPPORT_WD80X3 +#ifdef SUPPORT_SMC_ULTRA +extern int dp8390_is790; +#else +#define dp8390_is790 0 +#endif +#else +#ifdef SUPPORT_SMC_ULTRA +#define dp8390_is790 1 +#endif +#endif + +#define dp8390_is790 0 +#define IFNAME "ne" +#define RX_BUFBASE 0 +#define TX_PAGE_START (dp8390_membase >> ED_PAGE_SHIFT) + +extern uint8_t dp8390_cr_proto; /* values always set in CR */ +extern uint8_t dp8390_dcr_reg; /* override DCR if LS is set */ + +int EtherSend(char *, int); +int EtherReceive(char *, int); --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ boot/if_ne.c 2012-10-07 16:16:52.000000000 +0900 @@ -0,0 +1,157 @@ +/* $NetBSD$ */ +/* $Id: if_ne.c,v 1.28 2011/10/05 13:17:06 isaki Exp $ */ + +/* + * Copyright (c) 2003 Tetsuya Isaki. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "iocs.h" +#include "ne.h" +#include "dp8390.h" + +extern int badbaddr(void *); + +static int ne_match(struct netif *, void *); +static int ne_probe(struct netif *, void *); +static void ne_init(struct iodesc *, void *); +static int ne_get(struct iodesc *, void *, size_t, saseconds_t); +static int ne_put(struct iodesc *, void *, size_t); +static void ne_end(struct netif *); + +uint neaddr_conf[] = { + 0xece200, /* Neptune-X at ISA addr 0x300 */ + 0xece300, /* Nereid #1 */ + 0xeceb00, /* Nereid #2 */ +}; +uint neaddr; + + +static int +ne_match(struct netif *nif, void *machdep_hint) +{ + int i; + + for (i = 0; i < sizeof(neaddr_conf) / sizeof(neaddr_conf[0]); i++) { + if (!badbaddr((void *)neaddr_conf[i])) { + neaddr = neaddr_conf[i]; + return 1; + } + } + printf("ne_match: no match\n"); + return 0; +} + +static int +ne_probe(struct netif *nif, void *machdep_hint) +{ + + return 0; +} + +static void +ne_init(struct iodesc *desc, void *machdep_hint) +{ + +#ifdef DEBUG + printf("ne_init\n"); +#endif + if (EtherInit(desc->myea) == 0) { + printf("EtherInit failed?\n"); + exit(1); + } + + printf("ethernet address = %s\n", ether_sprintf(desc->myea)); +} + +static int +ne_get(struct iodesc *desc, void *pkt, size_t maxlen, saseconds_t timeout) +{ + int len = 0; + saseconds_t t; + + t = getsecs() + timeout; + while (getsecs() < t) { + len = EtherReceive(pkt, maxlen); + if (len) + break; + } + + return len; +} + +static int +ne_put(struct iodesc *desc, void *pkt, size_t len) +{ +#ifdef DEBUG + struct ether_header *eh; + + eh = pkt; + printf("dst: %s\n", ether_sprintf(eh->ether_dhost)); + printf("src: %s\n", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xffff); +#endif + + return EtherSend(pkt, len); +} + +static void +ne_end(struct netif *nif) +{ + +#ifdef DEBUG + printf("ne_end\n"); +#endif + + EtherStop(); +} + + +struct netif_stats ne_stats; +struct netif_dif ne_ifs[] = { + { 0, 1, &ne_stats, 0, 0, }, +}; + +struct netif_driver ne_netif_driver = { + "ne", + ne_match, + ne_probe, + ne_init, + ne_get, + ne_put, + ne_end, + ne_ifs, + sizeof(ne_ifs) / sizeof(ne_ifs[0]), +}; --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ boot/ne.c 2012-10-07 14:48:46.000000000 +0900 @@ -0,0 +1,273 @@ +/* $NetBSD$ */ +/* $Id: ne.c,v 1.22 2011/10/05 13:16:20 isaki Exp $ */ + +/* + * This file is derived from sys/arch/i386/stand/lib/netif/ne.c + * NetBSD: ne.c,v 1.7 2008/12/14 18:46:33 christos Exp + */ + +/*- + * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Device driver for National Semiconductor DS8390/WD83C690 based ethernet + * adapters. + * + * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. + * + * Copyright (C) 1993, David Greenman. This software may be used, modified, + * copied, distributed, and sold, in both source and binary form provided that + * the above copyright and these terms are retained. Under no circumstances is + * the author responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its use. + */ + +/* + * this code is mainly obtained from /sys/dev/ic/ne2000.c . + */ + +#include + +#include +#include + +#include + +#include +#include +#include "dp8390.h" +#include "ne.h" + +#define NE_BASEREG neaddr +#define NE_ASIC_BASEREG (NE_BASEREG + NE2000_ASIC_OFFSET * 2) + +#define NIC_PORT(x) (NE_BASEREG + (x) * 2) +#define NIC_INB(x) inb(NIC_PORT(x)) +#define NIC_OUTB(x, b) outb(NIC_PORT(x), (b)) + +#define NE_16BIT + +#define DELAY(x) delay(x) + +/* + * NE2000 on Neptune-X and Nereid has the following regsiter mappings: + * - 8bit NIC registers are mapped at sparse even addresses + * - 16bit data registers on NE2000 ASIC are used to transfer stream data + * so no software byte swap ops are necessary even on word access + */ +#define ASIC_PORT(x) (NE_ASIC_BASEREG + (x) * 2) +#define ASIC_INB(x) inb(ASIC_PORT(x)) +#define ASIC_INW(x) inw(ASIC_PORT(x)) +#define ASIC_OUTB(x, b) outb(ASIC_PORT(x), (b)) +#define ASIC_OUTW(x, b) outw(ASIC_PORT(x), (b)) + +uint8_t eth_myaddr[6]; + +int +EtherInit(unsigned char *myadr) +{ + uint8_t romdata[16]; + uint8_t tmp; + int i; + + printf("ne: trying iobase=0x%x\n", NE_BASEREG); + + dp8390_iobase = NE_BASEREG; + dp8390_membase = 16384; +#ifdef NE_16BIT + dp8390_memsize = 16384; +#else + dp8390_memsize = 8192; +#endif + dp8390_cr_proto = ED_CR_RD2; + dp8390_dcr_reg = ED_DCR_FT1 | ED_DCR_LS; +#ifdef NE_16BIT + dp8390_dcr_reg |= ED_DCR_WTS; +#endif + + /* reset */ + tmp = ASIC_INB(NE2000_ASIC_RESET); + DELAY(10000); + ASIC_OUTB(NE2000_ASIC_RESET, tmp); + DELAY(5000); + + NIC_OUTB(ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); + DELAY(5000); + + tmp = NIC_INB(ED_P0_CR); + if ((tmp & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) != + (ED_CR_RD2 | ED_CR_STP)) { + goto out; + } + + tmp = NIC_INB(ED_P0_ISR); + if ((tmp & ED_ISR_RST) != ED_ISR_RST) { + goto out; + } + + NIC_OUTB(ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); + + for (i = 0; i < 100; i++) { + if ((NIC_INB(ED_P0_ISR) & ED_ISR_RST) == ED_ISR_RST) { + /* Ack the reset bit. */ + NIC_OUTB(ED_P0_ISR, ED_ISR_RST); + break; + } + DELAY(100); + } + + printf("ne: found\n"); + + /* + * This prevents packets from being stored in the NIC memory when + * the readmem routine turns on the start bit in the CR. + */ + NIC_OUTB(ED_P0_RCR, ED_RCR_MON); + + /* Temporarily initialize DCR for to read romdata. */ +#ifdef NE_16BIT + NIC_OUTB(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS | ED_DCR_WTS); +#else + NIC_OUTB(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); +#endif + +#if 0 + /* + * dp8390_config() will init these registers later. + * Note sys/dev/ic/ne2000.c sets these values to detect NE1000. + */ + NIC_OUTB(ED_P0_PSTART, 8192 >> ED_PAGE_SHIFT); + NIC_OUTB(ED_P0_PSTOP, 16384 >> ED_PAGE_SHIFT); +#endif + + ne2000_readmem(0, romdata, sizeof(romdata)); + for (i = 0; i < 6; i++) + myadr[i] = eth_myaddr[i] = romdata[i * 2]; + + if (dp8390_config()) + goto out; + + return 1; + out: + return 0; +} + +void +EtherStop(void) +{ + uint8_t tmp; + + dp8390_stop(); + + tmp = ASIC_INB(NE2000_ASIC_RESET); + DELAY(10000); + ASIC_OUTB(NE2000_ASIC_RESET, tmp); + DELAY(5000); + + NIC_OUTB(ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); + DELAY(5000); +} + +void +ne2000_writemem(uint8_t *src, int dst, size_t len) +{ + size_t i; + int maxwait = 100; /* about 120us */ + + /* Select page 0 registers. */ + NIC_OUTB(ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); + + /* Reset remote DMA complete flag. */ + NIC_OUTB(ED_P0_ISR, ED_ISR_RDC); + + /* Set up DMA byte count. */ + NIC_OUTB(ED_P0_RBCR0, len); + NIC_OUTB(ED_P0_RBCR1, len >> 8); + + /* Set up destination address in NIC mem. */ + NIC_OUTB(ED_P0_RSAR0, dst); + NIC_OUTB(ED_P0_RSAR1, dst >> 8); + + /* Set remote DMA write. */ + NIC_OUTB(ED_P0_CR, ED_CR_RD1 | ED_CR_PAGE_0 | ED_CR_STA); + +#ifdef NE_16BIT + for (i = 0; i < len; i += 2, src += 2) + ASIC_OUTW(NE2000_ASIC_DATA, *(uint16_t *)src); +#else + for (i = 0; i < len; i++) + ASIC_OUTB(NE2000_ASIC_DATA, *src++); +#endif + + /* + * Wait for remote DMA to complete. This is necessary because on the + * transmit side, data is handled internally by the NIC in bursts, and + * we can't start another remote DMA until this one completes. Not + * waiting causes really bad things to happen - like the NIC wedging + * the bus. + */ + while (((NIC_INB(ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait) + DELAY(1); + + if (maxwait == 0) + printf("ne2000_writemem: failed to complete\n"); +} + +void +ne2000_readmem(int src, uint8_t *dst, size_t amount) +{ + size_t i; + + /* Select page 0 registers. */ + NIC_OUTB(ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); + + /* Round up to a word. */ + if (amount & 1) + ++amount; + + /* Set up DMA byte count. */ + NIC_OUTB(ED_P0_RBCR0, amount); + NIC_OUTB(ED_P0_RBCR1, amount >> 8); + + /* Set up source address in NIC mem. */ + NIC_OUTB(ED_P0_RSAR0, src); + NIC_OUTB(ED_P0_RSAR1, src >> 8); + + NIC_OUTB(ED_P0_CR, ED_CR_RD0 | ED_CR_PAGE_0 | ED_CR_STA); + +#ifdef NE_16BIT + for (i = 0; i < amount; i += 2, dst += 2) { + *(uint16_t *)dst = ASIC_INW(NE2000_ASIC_DATA); + } +#else + for (i = 0; i < amount; i++) + *dst++ = ASIC_INB(NE2000_ASIC_DATA); +#endif +} --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ boot/ne.h 2012-10-07 14:24:10.000000000 +0900 @@ -0,0 +1,38 @@ +/* $NetBSD: ne.h,v 1.3 2008/12/14 18:46:33 christos Exp $ */ + +/* + * Copyright (c) 2003 Tetsuya Isaki. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define inb(x) *(volatile uint8_t *)(x) +#define inw(x) *(volatile uint16_t *)(x) +#define outb(x, b) *(volatile uint8_t *)(x) = (b) +#define outw(x, w) *(volatile uint16_t *)(x) = (w) + +extern uint neaddr; + +int EtherInit(unsigned char *); +void EtherStop(void); +void ne2000_readmem(int, uint8_t *, size_t); +void ne2000_writemem(uint8_t *, int, size_t); --- /dev/null 2012-10-07 17:08:07.000000000 +0900 +++ libsa/clock.c 2012-10-07 14:21:28.000000000 +0900 @@ -0,0 +1,93 @@ +/* $NetBSD$ */ +/* $Id: clock.c,v 1.4 2011/04/10 09:21:45 isaki Exp $ */ + +/* + * Copyright (c) 2003 Tetsuya Isaki. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include "iocs.h" +#include "libx68k.h" + +/* x68k's RTC is defunct 2079, so there is no y2100 problem. */ +#define LEAPYEAR(y) (((y) % 4) == 0) +#define SECDAY (24 * 60 * 60) + +int rtc_offset; + +const int yday[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +satime_t +getsecs(void) +{ + int val; + int sec, min, hour, day, mon, year; + int days, y; + + /* Get date & time via IOCS */ + val = IOCS_DATEBIN(IOCS_BINDATEGET()); + year = ((val & 0x0fff0000) >> 16) + 1980; + mon = ((val & 0x0000ff00) >> 8); + day = (val & 0x000000ff); + + val = IOCS_TIMEBIN(IOCS_TIMEGET()); + hour = ((val & 0x00ff0000) >> 16); + min = ((val & 0x0000ff00) >> 8); + sec = (val & 0x000000ff); + + /* simple sanity checks */ + if (mon < 1 || mon > 12 || day < 1 || day > 31) + return 0; + if (hour > 23 || min > 59 || sec > 59) + return 0; + + days = 0; + for (y = 1970; y < year; y++) + days += 365 + LEAPYEAR(y); + days += yday[mon - 1] + day - 1; + if (LEAPYEAR(y) && mon > 2) + days++; + + /* now we have days since Jan 1, 1970. the rest is easy... */ + return (days * SECDAY) + (hour * 3600) + (min * 60) + sec + + (rtc_offset * 60); +} + +/* XXX AD-HOC delay(us) */ +void +delay(int us) +{ + int cnt, start; + + cnt = us / 1000 / 10; /* 10msec unit */ + if (cnt == 0) + cnt = 1; + start = IOCS_ONTIME(); + while (IOCS_ONTIME() >= start + cnt) + ; +}