Import of Openfirmware device drivers for PowerPC port.
authorrahnds <rahnds@openbsd.org>
Mon, 23 Dec 1996 00:32:56 +0000 (00:32 +0000)
committerrahnds <rahnds@openbsd.org>
Mon, 23 Dec 1996 00:32:56 +0000 (00:32 +0000)
From NetBSD, with modification to get current time in kernel.

sys/dev/ofw/files.ofw [new file with mode: 0644]
sys/dev/ofw/ofbus.c [new file with mode: 0644]
sys/dev/ofw/ofcons.c [new file with mode: 0644]
sys/dev/ofw/ofdisk.c [new file with mode: 0644]
sys/dev/ofw/ofnet.c [new file with mode: 0644]
sys/dev/ofw/ofrtc.c [new file with mode: 0644]
sys/dev/ofw/openfirm.h [new file with mode: 0644]

diff --git a/sys/dev/ofw/files.ofw b/sys/dev/ofw/files.ofw
new file mode 100644 (file)
index 0000000..799d178
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# First cut on Openfirmware interface
+#
+
+define openfirm {}
+
+# Generic disk support
+device ofdisk: disk
+attach ofdisk at openfirm
+file   dev/ofw/ofdisk.c                ofdisk needs-flag
+
+# Generic net support
+#define        ipkdbofn { [ disable = 0 ] }
+#device        ofnet: ether, ifnet, ipkdbofn
+device ofnet: ether, ifnet
+#device        ipkdbif: ether, ifnet 
+attach ofnet at openfirm
+file   dev/ofw/ofnet.c                 ofnet | ipkdb_ofn needs-flag
+#attach        ipkdbif at ipkdbofn with ipkdb_ofn
+
+# Generic console support
+device ofcons: tty
+attach ofcons at openfirm
+file   dev/ofw/ofcons.c                ofcons needs-flag
+
+# Generic RTC support
+device ofrtc
+attach ofrtc at openfirm
+file   dev/ofw/ofrtc.c                 ofrtc needs-flag
+
+# Generic bus support
+device ofbus: openfirm
+attach ofbus at openfirm
+file   dev/ofw/ofbus.c                 openfirm
+
+device ofroot: openfirm
+attach ofroot at root
+
diff --git a/sys/dev/ofw/ofbus.c b/sys/dev/ofw/ofbus.c
new file mode 100644 (file)
index 0000000..1f335df
--- /dev/null
@@ -0,0 +1,147 @@
+/*     $NetBSD: ofbus.c,v 1.3 1996/10/13 01:38:11 christos Exp $       */
+
+/*
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 <sys/param.h>
+#include <sys/device.h>
+
+#include <dev/ofw/openfirm.h>
+
+int ofbprobe __P((struct device *, void *, void *));
+void ofbattach __P((struct device *, struct device *, void *));
+static int ofbprint __P((void *, const char *));
+
+struct cfattach ofbus_ca = {
+       sizeof(struct device), ofbprobe, ofbattach
+};
+
+struct cfdriver ofbus_cd = {
+       NULL, "ofbus", DV_DULL
+};
+
+struct cfattach ofroot_ca = {
+       sizeof(struct device), ofbprobe, ofbattach
+};
+struct cfdriver ofroot_cd = {
+       NULL, "ofroot", DV_DULL
+};
+
+static int
+ofbprint(aux, name)
+       void *aux;
+       const char *name;
+{
+       struct ofprobe *ofp = aux;
+       char child[64];
+       int l;
+       
+       if ((l = OF_getprop(ofp->phandle, "name", child, sizeof child - 1)) < 0)
+               panic("device without name?");
+       if (l >= sizeof child)
+               l = sizeof child - 1;
+       child[l] = 0;
+       
+       if (name)
+               printf("%s at %s", child, name);
+       else
+               printf(" (%s)", child);
+       return UNCONF;
+}
+
+int
+ofbprobe(parent, cf, aux)
+       struct device *parent;
+       void *cf, *aux;
+{
+       struct ofprobe *ofp = aux;
+       
+       if (!OF_child(ofp->phandle))
+               return 0;
+       return 1;
+}
+
+void
+ofbattach(parent, dev, aux)
+       struct device *parent, *dev;
+       void *aux;
+{
+       int child;
+       char name[5];
+       struct ofprobe *ofp = aux;
+       struct ofprobe probe;
+       int units;
+       
+       if (!parent)
+               ofbprint(aux, 0);
+               
+       printf("\n");
+
+       /*
+        * This is a hack to make the probe work on the scsi (and ide) bus.
+        * YES, I THINK IT IS A BUG IN THE OPENFIRMWARE TO NOT PROBE ALL
+        * DEVICES ON THESE BUSSES.
+        */
+       units = 1;
+       if (OF_getprop(ofp->phandle, "name", name, sizeof name) > 0) {
+               if (!strcmp(name, "scsi"))
+                       units = 7; /* What about wide or hostid != 7?   XXX */
+               else if (!strcmp(name, "ide"))
+                       units = 2;
+       }
+       for (child = OF_child(ofp->phandle); child; child = OF_peer(child)) {
+               /*
+                * This is a hack to skip all the entries in the tree
+                * that aren't devices (packages, openfirmware etc.).
+                */
+               if (OF_getprop(child, "device_type", name, sizeof name) < 0)
+                       continue;
+               probe.phandle = child;
+               for (probe.unit = 0; probe.unit < units; probe.unit++)
+                       config_found(dev, &probe, ofbprint);
+       }
+}
+
+/*
+ * Name matching routine for OpenFirmware
+ */
+int
+ofnmmatch(cp1, cp2)
+       char *cp1, *cp2;
+{
+       int i;
+       
+       for (i = 0; *cp2; i++)
+               if (*cp1++ != *cp2++)
+                       return 0;
+       return i;
+}
diff --git a/sys/dev/ofw/ofcons.c b/sys/dev/ofw/ofcons.c
new file mode 100644 (file)
index 0000000..58883cf
--- /dev/null
@@ -0,0 +1,351 @@
+/*     $NetBSD: ofcons.c,v 1.3 1996/10/13 01:38:11 christos Exp $      */
+
+/*
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 <sys/param.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/tty.h>
+
+#include <dev/cons.h>
+
+#include <dev/ofw/openfirm.h>
+
+struct ofc_softc {
+       struct device of_dev;
+       struct tty *of_tty;
+       int of_flags;
+};
+/* flags: */
+#define        OFPOLL          1
+
+#define        OFBURSTLEN      128     /* max number of bytes to write in one chunk */
+
+static int stdin, stdout;
+
+static int ofcmatch __P((struct device *, void *, void *));
+static void ofcattach __P((struct device *, struct device *, void *));
+
+struct cfattach ofcons_ca = {
+       sizeof(struct ofc_softc), ofcmatch, ofcattach
+};
+
+struct cfdriver ofcons_cd = {
+       NULL, "ofcons", DV_TTY
+};
+
+static int ofcprobe __P((void));
+
+static int
+ofcmatch(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       struct ofprobe *ofp = aux;
+       
+       if (!ofcprobe())
+               return 0;
+       return OF_instance_to_package(stdin) == ofp->phandle
+               || OF_instance_to_package(stdout) == ofp->phandle;
+}
+
+static void
+ofcattach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       printf("\n");
+}
+
+static void ofcstart __P((struct tty *));
+static int ofcparam __P((struct tty *, struct termios *));
+static void ofcpoll __P((void *));
+
+int
+ofcopen(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       struct ofc_softc *sc;
+       int unit = minor(dev);
+       struct tty *tp;
+       
+       if (unit >= ofcons_cd.cd_ndevs)
+               return ENXIO;
+       sc = ofcons_cd.cd_devs[unit];
+       if (!sc)
+               return ENXIO;
+       if (!(tp = sc->of_tty))
+               sc->of_tty = tp = ttymalloc();
+       tp->t_oproc = ofcstart;
+       tp->t_param = ofcparam;
+       tp->t_dev = dev;
+       if (!(tp->t_state & TS_ISOPEN)) {
+               tp->t_state |= TS_WOPEN;
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+               ofcparam(tp, &tp->t_termios);
+               ttsetwater(tp);
+       } else if ((tp->t_state&TS_XCLUDE) && suser(p->p_ucred, &p->p_acflag))
+               return EBUSY;
+       tp->t_state |= TS_CARR_ON;
+       
+       if (!(sc->of_flags & OFPOLL)) {
+               sc->of_flags |= OFPOLL;
+               timeout(ofcpoll, sc, 1);
+       }
+
+       return (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+int
+ofcclose(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
+       struct tty *tp = sc->of_tty;
+
+       untimeout(ofcpoll, sc);
+       sc->of_flags &= ~OFPOLL;
+       (*linesw[tp->t_line].l_close)(tp, flag);
+       ttyclose(tp);
+       return 0;
+}
+
+int
+ofcread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+       int flag;
+{
+       struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
+       struct tty *tp = sc->of_tty;
+       
+       return (*linesw[tp->t_line].l_read)(tp, uio, flag);
+}
+
+int
+ofcwrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+       int flag;
+{
+       struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
+       struct tty *tp = sc->of_tty;
+       
+       return (*linesw[tp->t_line].l_write)(tp, uio, flag);
+}
+
+int
+ofcioctl(dev, cmd, data, flag, p)
+       dev_t dev;
+       u_long cmd;
+       caddr_t data;
+       int flag;
+       struct proc *p;
+{
+       struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
+       struct tty *tp = sc->of_tty;
+       int error;
+       
+       if ((error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p)) >= 0)
+               return error;
+       if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0)
+               return error;
+       return ENOTTY;
+}
+
+struct tty *
+ofctty(dev)
+       dev_t dev;
+{
+       struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
+
+       return sc->of_tty;
+}
+
+void
+ofcstop(tp, flag)
+       struct tty *tp;
+       int flag;
+{
+}
+
+static void
+ofcstart(tp)
+       struct tty *tp;
+{
+       struct clist *cl;
+       int s, len;
+       u_char buf[OFBURSTLEN];
+       
+       s = spltty();
+       if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
+               splx(s);
+               return;
+       }
+       tp->t_state |= TS_BUSY;
+       splx(s);
+       cl = &tp->t_outq;
+       len = q_to_b(cl, buf, OFBURSTLEN);
+       OF_write(stdout, buf, len);
+       s = spltty();
+       tp->t_state &= ~TS_BUSY;
+       if (cl->c_cc) {
+               tp->t_state |= TS_TIMEOUT;
+               timeout(ttrstrt, (void *)tp, 1);
+       }
+       if (cl->c_cc <= tp->t_lowat) {
+               if (tp->t_state & TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup(cl);
+               }
+               selwakeup(&tp->t_wsel);
+       }
+       splx(s);
+}
+
+static int
+ofcparam(tp, t)
+       struct tty *tp;
+       struct termios *t;
+{
+       tp->t_ispeed = t->c_ispeed;
+       tp->t_ospeed = t->c_ospeed;
+       tp->t_cflag = t->c_cflag;
+       return 0;
+}
+
+static void
+ofcpoll(aux)
+       void *aux;
+{
+       struct ofc_softc *sc = aux;
+       struct tty *tp = sc->of_tty;
+       char ch;
+       
+       while (OF_read(stdin, &ch, 1) > 0) {
+               if (tp && (tp->t_state & TS_ISOPEN))
+                       (*linesw[tp->t_line].l_rint)(ch, tp);
+       }
+       timeout(ofcpoll, sc, 1);
+}
+
+static int
+ofcprobe()
+{
+       int chosen;
+
+       if (stdin)
+               return 1;
+       if ((chosen = OF_finddevice("/chosen")) == -1)
+               return 0;
+       if (OF_getprop(chosen, "stdin", &stdin, sizeof stdin) != sizeof stdin
+           || OF_getprop(chosen, "stdout", &stdout, sizeof stdout) != sizeof stdout)
+               return 0;
+       return 1;
+}
+
+void
+ofccnprobe(cd)
+       struct consdev *cd;
+{
+       int maj;
+
+       if (!ofcprobe())
+               return;
+
+       for (maj = 0; maj < nchrdev; maj++)
+               if (cdevsw[maj].d_open == ofcopen)
+                       break;
+       cd->cn_dev = makedev(maj, 0);
+       cd->cn_pri = CN_INTERNAL;
+}
+
+void
+ofccninit(cd)
+       struct consdev *cd;
+{
+}
+
+int
+ofccngetc(dev)
+       dev_t dev;
+{
+       unsigned char ch;
+       int l;
+       
+       while ((l = OF_read(stdin, &ch, 1)) != 1)
+               if (l != -2)
+                       return -1;
+       return ch;
+}
+
+void
+ofccnputc(dev, c)
+       dev_t dev;
+       int c;
+{
+       char ch = c;
+       
+       OF_write(stdout, &ch, 1);
+}
+
+void
+ofccnpollc(dev, on)
+       dev_t dev;
+       int on;
+{
+       struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
+       
+       if (!sc)
+               return;
+       if (on) {
+               if (sc->of_flags & OFPOLL)
+                       untimeout(ofcpoll, sc);
+               sc->of_flags &= ~OFPOLL;
+       } else {
+               if (!(sc->of_flags & OFPOLL)) {
+                       sc->of_flags |= OFPOLL;
+                       timeout(ofcpoll, sc, 1);
+               }
+       }
+}
diff --git a/sys/dev/ofw/ofdisk.c b/sys/dev/ofw/ofdisk.c
new file mode 100644 (file)
index 0000000..addefb2
--- /dev/null
@@ -0,0 +1,374 @@
+/*     $NetBSD: ofdisk.c,v 1.3 1996/10/13 01:38:13 christos Exp $      */
+
+/*
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 <sys/param.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/disk.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/systm.h>
+
+#include <dev/ofw/openfirm.h>
+
+struct ofd_softc {
+       struct device sc_dev;
+       int sc_phandle;
+       int sc_unit;
+       struct disk sc_dk;
+       int sc_ihandle;
+       u_long max_transfer;
+       char sc_name[16];
+};
+
+static int ofdprobe __P((struct device *, void *, void *));
+static void ofdattach __P((struct device *, struct device *, void *));
+
+struct cfattach ofdisk_ca = {
+       sizeof(struct ofd_softc), ofdprobe, ofdattach
+};
+
+struct cfdriver ofdisk_cd = {
+       NULL, "ofdisk", DV_DISK
+};
+
+void ofdstrategy __P((struct buf *));
+
+struct dkdriver ofdkdriver = { ofdstrategy };
+
+static int
+ofdprobe(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       struct ofprobe *ofp = aux;
+       char type[8];
+       int l;
+       
+       if ((l = OF_getprop(ofp->phandle, "device_type", type, sizeof type - 1)) < 0)
+               return 0;
+       if (l >= sizeof type)
+               return 0;
+       type[l] = 0;
+       return !strcmp(type, "block");
+}
+
+static void
+ofdattach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct ofd_softc *of = (void *)self;
+       struct ofprobe *ofp = aux;
+       int l;
+       
+       of->sc_phandle = ofp->phandle;
+       of->sc_unit = ofp->unit;
+       of->sc_ihandle = 0;
+       of->sc_dk.dk_driver = &ofdkdriver;
+       of->sc_dk.dk_name = of->sc_name;
+       strcpy(of->sc_name, of->sc_dev.dv_xname);
+       disk_attach(&of->sc_dk);
+       dk_establish(&of->sc_dk, self);                         /* XXX */
+       printf("\n");
+}
+
+int
+ofdopen(dev, flags, fmt, p)
+       dev_t dev;
+       int flags;
+       int fmt;
+       struct proc *p;
+{
+       int unit = DISKUNIT(dev);
+       struct ofd_softc *of;
+       char path[256];
+       struct disklabel *lp;
+       int l;
+       
+       if (unit >= ofdisk_cd.cd_ndevs)
+               return ENXIO;
+       if (!(of = ofdisk_cd.cd_devs[unit]))
+               return ENXIO;
+
+       if (!of->sc_ihandle) {
+
+               if ((l = OF_package_to_path(of->sc_phandle, path, sizeof path - 3)) < 0)
+                       return ENXIO;
+               if (l >= sizeof path - 3)
+                       return ENXIO;
+               path[l] = 0;
+
+               /*
+                * This is for the benefit of SCSI/IDE disks that don't
+                * have all their childs in the device tree.
+                * YES, I DO THINK THIS IS A BUG IN OPENFIRMWARE!!!
+                * And yes, this is a very gross hack!                                  XXX
+                * See also ofscsi.c
+                */
+               if (!strcmp(path + l - 4, "disk")) {
+                       path[l++] = '@';
+                       path[l++] = '0' + of->sc_unit;
+                       path[l] = 0;
+               }
+
+               strcat(path, ":0");
+
+               if (!(of->sc_ihandle = OF_open(path)))
+                       return ENXIO;
+
+               /*
+                * Try to get characteristics of the disk.
+                */
+               of->max_transfer = OF_call_method_1("max-transfer", of->sc_ihandle, 0);
+               if (of->max_transfer > MAXPHYS)
+                       of->max_transfer = MAXPHYS;
+               
+               lp = of->sc_dk.dk_label;
+               bzero(lp, sizeof *lp);
+               
+               lp->d_secsize = OF_call_method_1("block-size", of->sc_ihandle, 0);
+               if (lp->d_secsize == (u_int32_t)-1 || lp->d_secsize > MAXBSIZE)
+                       lp->d_secsize = DEV_BSIZE;
+               
+               lp->d_secperunit = OF_call_method_1("#blocks", of->sc_ihandle, 0);
+               if (lp->d_secperunit == (u_int32_t)-1)
+                       lp->d_secperunit = 0x7fffffff;
+               
+               lp->d_secpercyl = 1;
+               lp->d_nsectors = 1;
+               lp->d_ntracks = 1;
+               lp->d_ncylinders = lp->d_secperunit;
+                       
+               lp->d_partitions[RAW_PART].p_offset = 0;
+               lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
+               
+               readdisklabel(MAKEDISKDEV(major(dev), unit, RAW_PART), ofdstrategy,
+                             lp, of->sc_dk.dk_cpulabel);
+       }
+
+       switch (fmt) {
+       case S_IFCHR:
+               of->sc_dk.dk_copenmask |= 1 << DISKPART(dev);
+               break;
+       case S_IFBLK:
+               of->sc_dk.dk_bopenmask |= 1 << DISKPART(dev);
+               break;
+       }
+       of->sc_dk.dk_openmask = of->sc_dk.dk_copenmask | of->sc_dk.dk_bopenmask;
+       
+       return 0;
+}
+
+int
+ofdclose(dev, flags, fmt, p)
+       dev_t dev;
+       int flags;
+       int fmt;
+       struct proc *p;
+{
+       struct ofd_softc *of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
+
+       switch (fmt) {
+       case S_IFCHR:
+               of->sc_dk.dk_copenmask &= ~(1 << DISKPART(dev));
+               break;
+       case S_IFBLK:
+               of->sc_dk.dk_bopenmask &= ~(1 << DISKPART(dev));
+               break;
+       }
+       of->sc_dk.dk_openmask = of->sc_dk.dk_copenmask | of->sc_dk.dk_bopenmask;
+       
+#ifdef FIREPOWERBUGS
+       /*
+        * This is a hack to get the firmware to flush its buffers.
+        */
+       OF_seek(of->sc_ihandle, 0);
+#endif
+       if (!of->sc_dk.dk_openmask) {
+               OF_close(of->sc_ihandle);
+               of->sc_ihandle = 0;
+       }
+
+       return 0;
+}
+
+void
+ofdstrategy(bp)
+       struct buf *bp;
+{
+       struct ofd_softc *of = ofdisk_cd.cd_devs[DISKUNIT(bp->b_dev)];
+       struct partition *p;
+       u_quad_t off;
+       int read;
+       int (*OF_io)(int, void *, int);
+       daddr_t blkno = bp->b_blkno;
+       
+       bp->b_resid = 0;
+       if (bp->b_bcount == 0)
+               goto done;
+       
+       OF_io = bp->b_flags & B_READ ? OF_read : OF_write;
+
+       if (DISKPART(bp->b_dev) != RAW_PART) {
+               if (bounds_check_with_label(bp, of->sc_dk.dk_label, 0) <= 0) {
+                       bp->b_resid = bp->b_bcount;
+                       goto done;
+               }
+               p = &of->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
+               blkno = bp->b_blkno + p->p_offset;
+       }
+       
+       disk_busy(&of->sc_dk);
+
+       off = (u_quad_t)blkno * DEV_BSIZE;
+       read = -1;
+       do {
+               if (OF_seek(of->sc_ihandle, off) < 0)
+                       break;
+               read = OF_io(of->sc_ihandle, bp->b_data, bp->b_bcount);
+       } while (read == -2);
+       if (read < 0) {
+               bp->b_error = EIO;
+               bp->b_flags |= B_ERROR;
+               bp->b_resid = bp->b_bcount;
+       } else
+               bp->b_resid = bp->b_bcount - read;
+
+       disk_unbusy(&of->sc_dk, bp->b_bcount - bp->b_resid);
+
+done:
+       biodone(bp);
+}
+
+static void
+ofminphys(bp)
+       struct buf *bp;
+{
+       struct ofd_softc *of = ofdisk_cd.cd_devs[DISKUNIT(bp->b_dev)];
+       
+       if (bp->b_bcount > of->max_transfer)
+               bp->b_bcount = of->max_transfer;
+}
+
+int
+ofdread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       return physio(ofdstrategy, NULL, dev, B_READ, ofminphys, uio);
+}
+
+int
+ofdwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       return physio(ofdstrategy, NULL, dev, B_WRITE, ofminphys, uio);
+}
+
+int
+ofdioctl(dev, cmd, data, flag, p)
+       dev_t dev;
+       u_long cmd;
+       caddr_t data;
+       int flag;
+       struct proc *p;
+{
+       struct ofd_softc *of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
+       int error;
+       
+       switch (cmd) {
+       case DIOCGDINFO:
+               *(struct disklabel *)data = *of->sc_dk.dk_label;
+               return 0;
+               
+       case DIOCGPART:
+               ((struct partinfo *)data)->disklab = of->sc_dk.dk_label;
+               ((struct partinfo *)data)->part =
+                       &of->sc_dk.dk_label->d_partitions[DISKPART(dev)];
+               return 0;
+               
+       case DIOCWDINFO:
+       case DIOCSDINFO:
+               if ((flag & FWRITE) == 0)
+                       return EBADF;
+               
+               error = setdisklabel(of->sc_dk.dk_label,
+                                    (struct disklabel *)data, /*of->sc_dk.dk_openmask */0,
+                                    of->sc_dk.dk_cpulabel);
+               if (error == 0 && cmd == DIOCWDINFO)
+                       error = writedisklabel(MAKEDISKDEV(major(dev),
+                                                          DISKUNIT(dev), RAW_PART),
+                                              ofdstrategy,
+                                              of->sc_dk.dk_label,
+                                              of->sc_dk.dk_cpulabel);
+
+               return error;
+       default:
+               return ENOTTY;
+       }
+}
+
+int
+ofddump(dev, blkno, va, size)
+       dev_t dev;
+       daddr_t blkno;
+       caddr_t va;
+       size_t size;
+{
+       return EINVAL;
+}
+
+int
+ofdsize(dev)
+       dev_t dev;
+{
+       struct ofd_softc *of;
+       int part;
+       int size;
+       
+       if (ofdopen(dev, 0, S_IFBLK) != 0)
+               return -1;
+       of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
+       part = DISKPART(dev);
+       if (of->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
+               size = -1;
+       else
+               size = of->sc_dk.dk_label->d_partitions[part].p_size;
+       if (ofdclose(dev, 0, S_IFBLK) != 0)
+               return -1;
+       return size;
+}
diff --git a/sys/dev/ofw/ofnet.c b/sys/dev/ofw/ofnet.c
new file mode 100644 (file)
index 0000000..6dc6257
--- /dev/null
@@ -0,0 +1,456 @@
+/*     $NetBSD: ofnet.c,v 1.4 1996/10/16 19:33:21 ws Exp $     */
+
+/*
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 "ofnet.h"
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ofw/openfirm.h>
+
+#if NIPKDB_OFN > 0
+#include <ipkdb/ipkdb.h>
+#include <machine/ipkdb.h>
+
+struct cfattach ipkdb_ofn_ca = {
+       0, ipkdb_probe, ipkdb_attach
+};
+
+static struct ipkdb_if *kifp;
+static struct ofn_softc *ipkdb_of;
+
+static int ipkdbprobe __P((void *, void *));
+#endif
+
+struct ofn_softc {
+       struct device sc_dev;
+       int sc_phandle;
+       int sc_ihandle;
+       struct arpcom sc_arpcom;
+};
+
+static int ofnprobe __P((struct device *, void *, void *));
+static void ofnattach __P((struct device *, struct device *, void *));
+
+struct cfattach ofnet_ca = {
+       sizeof(struct ofn_softc), ofnprobe, ofnattach
+};
+
+struct cfdriver ofnet_cd = {
+       NULL, "ofnet", DV_IFNET
+};
+
+static void ofnread __P((struct ofn_softc *));
+static void ofntimer __P((struct ofn_softc *));
+static void ofninit __P((struct ofn_softc *));
+static void ofnstop __P((struct ofn_softc *));
+
+static void ofnstart __P((struct ifnet *));
+static int ofnioctl __P((struct ifnet *, u_long, caddr_t));
+static void ofnwatchdog __P((struct ifnet *));
+
+static int
+ofnprobe(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       struct ofprobe *ofp = aux;
+       char type[32];
+       int l;
+       
+#if NIPKDB_OFN > 0
+       if (!parent)
+               return ipkdbprobe(match, aux);
+#endif
+       if ((l = OF_getprop(ofp->phandle, "device_type", type, sizeof type - 1)) < 0)
+               return 0;
+       if (l >= sizeof type)
+               return 0;
+       type[l] = 0;
+       if (strcmp(type, "network"))
+               return 0;
+       return 1;
+}
+
+static void
+ofnattach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct ofn_softc *of = (void *)self;
+       struct ifnet *ifp = &of->sc_arpcom.ac_if;
+       struct ofprobe *ofp = aux;
+       char path[256];
+       int l;
+       
+       of->sc_phandle = ofp->phandle;
+#if NIPKDB_OFN > 0
+       if (kifp
+           && kifp->unit - 1 == of->sc_dev.dv_unit
+           && OF_instance_to_package(kifp->port) == ofp->phandle)  {
+               ipkdb_of = of;
+               of->sc_ihandle = kifp->port;
+       } else
+#endif
+       if ((l = OF_package_to_path(ofp->phandle, path, sizeof path - 1)) < 0
+           || l >= sizeof path
+           || (path[l] = 0, !(of->sc_ihandle = OF_open(path))))
+               panic("ofnattach: unable to open");
+       if (OF_getprop(ofp->phandle, "mac-address",
+                      of->sc_arpcom.ac_enaddr, sizeof of->sc_arpcom.ac_enaddr)
+           < 0)
+               panic("ofnattach: no max-address");
+       printf(": address %s\n", ether_sprintf(of->sc_arpcom.ac_enaddr));
+       
+       bcopy(of->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+       ifp->if_softc = of;
+       ifp->if_start = ofnstart;
+       ifp->if_ioctl = ofnioctl;
+       ifp->if_watchdog = ofnwatchdog;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+
+       if_attach(ifp);
+       ether_ifattach(ifp);
+
+#if NBPFILTER > 0
+       bpfattach(&of->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
+                 sizeof(struct ether_header));
+#endif
+
+       dk_establish(0, self);                                  /* XXX */
+}
+
+static char buf[ETHERMTU + sizeof(struct ether_header)];
+
+static void
+ofnread(of)
+       struct ofn_softc *of;
+{
+       struct ifnet *ifp = &of->sc_arpcom.ac_if;
+       struct ether_header *eh;
+       struct mbuf *m, **mp, *head;
+       int l, len;
+       char *bufp;
+
+#if NIPKDB_OFN > 0
+       ipkdbrint(kifp, ifp);
+#endif 
+       while (1) {
+               if ((len = OF_read(of->sc_ihandle, buf, sizeof buf)) < 0) {
+                       if (len == -2)
+                               return;
+                       ifp->if_ierrors++;
+                       continue;
+               }
+               if (len < sizeof(struct ether_header)) {
+                       ifp->if_ierrors++;
+                       continue;
+               }
+               bufp = buf;
+               
+               /* Allocate a header mbuf */
+               MGETHDR(m, M_DONTWAIT, MT_DATA);
+               if (m == 0) {
+                       ifp->if_ierrors++;
+                       continue;
+               }
+               m->m_pkthdr.rcvif = ifp;
+               m->m_pkthdr.len = len;
+               l = MHLEN;
+               head = 0;
+               mp = &head;
+               
+               while (len > 0) {
+                       if (head) {
+                               MGET(m, M_DONTWAIT, MT_DATA);
+                               if (m == 0) {
+                                       ifp->if_ierrors++;
+                                       m_freem(head);
+                                       head = 0;
+                                       break;
+                               }
+                               l = MLEN;
+                       }
+                       if (len >= MINCLSIZE) {
+                               MCLGET(m, M_DONTWAIT);
+                               if (m->m_flags & M_EXT)
+                                       l = MCLBYTES;
+                       }
+                       m->m_len = l = min(len, l);
+                       bcopy(bufp, mtod(m, char *), l);
+                       bufp += l;
+                       len -= l;
+                       *mp = m;
+                       mp = &m->m_next;
+               }
+               if (head == 0)
+                       continue;
+               eh = mtod(head, struct ether_header *);
+
+#if    NBPFILTER > 0
+               if (ifp->if_bpf) {
+                       bpf->mtap(ifp->if_bpf, m);
+#endif
+               m_adj(head, sizeof(struct ether_header));
+               ifp->if_ipackets++;
+               ether_input(ifp, eh, head);
+       }
+}
+
+static void
+ofntimer(of)
+       struct ofn_softc *of;
+{
+       ofnread(of);
+       timeout(ofntimer, of, 1);
+}
+
+static void
+ofninit(of)
+       struct ofn_softc *of;
+{
+       struct ifnet *ifp = &of->sc_arpcom.ac_if;
+
+       if (ifp->if_flags & IFF_RUNNING)
+               return;
+
+       ifp->if_flags |= IFF_RUNNING;
+       /* Start reading from interface */
+       ofntimer(of);
+       /* Attempt to start output */
+       ofnstart(ifp);
+}
+
+static void
+ofnstop(of)
+       struct ofn_softc *of;
+{
+       untimeout(ofntimer, of);
+       of->sc_arpcom.ac_if.if_flags &= ~IFF_RUNNING;
+}
+
+static void
+ofnstart(ifp)
+       struct ifnet *ifp;
+{
+       struct ofn_softc *of = ifp->if_softc;
+       struct mbuf *m, *m0;
+       char *bufp;
+       int len;
+       
+       if (!(ifp->if_flags & IFF_RUNNING))
+               return;
+
+       for (;;) {
+               /* First try reading any packets */
+               ofnread(of);
+               
+               /* Now get the first packet on the queue */
+               IF_DEQUEUE(&ifp->if_snd, m0);
+               if (!m0)
+                       return;
+               
+               if (!(m0->m_flags & M_PKTHDR))
+                       panic("ofnstart: no header mbuf");
+               len = m0->m_pkthdr.len;
+               
+               if (len > ETHERMTU + sizeof(struct ether_header)) {
+                       /* packet too large, toss it */
+                       ifp->if_oerrors++;
+                       m_freem(m0);
+                       continue;
+               }
+
+#if NPBFILTER > 0
+               if (ifp->if_bpf)
+                       bpf_mtab(ifp->if_bpf, m0);
+#endif
+               for (bufp = buf; m = m0;) {
+                       bcopy(mtod(m, char *), bufp, m->m_len);
+                       bufp += m->m_len;
+                       MFREE(m, m0);
+               }
+               if (OF_write(of->sc_ihandle, buf, bufp - buf) != bufp - buf)
+                       ifp->if_oerrors++;
+               else
+                       ifp->if_opackets++;
+       }
+}
+
+static int
+ofnioctl(ifp, cmd, data)
+       struct ifnet *ifp;
+       u_long cmd;
+       caddr_t data;
+{
+       struct ofn_softc *of = ifp->if_softc;
+       struct ifaddr *ifa = (struct ifaddr *)data;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int error = 0;
+       
+       switch (cmd) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               
+               switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       arp_ifinit(&of->sc_arpcom, ifa);
+                       break;
+#endif
+               default:
+                       break;
+               }
+               ofninit(of);
+               break;
+       case SIOCSIFFLAGS:
+               if (!(ifp->if_flags & IFF_UP)
+                   && (ifp->if_flags & IFF_RUNNING)) {
+                       /* If interface is down, but running, stop it. */
+                       ofnstop(of);
+               } else if ((ifp->if_flags & IFF_UP)
+                          && !(ifp->if_flags & IFF_RUNNING)) {
+                       /* If interface is up, but not running, start it. */
+                       ofninit(of);
+               } else {
+                       /* Other flags are ignored. */
+               }
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return error;
+}
+
+static void
+ofnwatchdog(ifp)
+       struct ifnet *ifp;
+{
+       struct ofn_softc *of = ifp->if_softc;
+       
+       log(LOG_ERR, "%s: device timeout\n", of->sc_dev.dv_xname);
+       of->sc_arpcom.ac_if.if_oerrors++;
+       ofnstop(of);
+       ofninit(of);
+}
+
+#if NIPKDB_OFN > 0
+static void
+ipkdbofstart(kip)
+       struct ipkdb_if *kip;
+{
+       int unit = kip->unit - 1;
+       
+       if (ipkdb_of)
+               ipkdbattach(kip, &ipkdb_of->sc_arpcom);
+}
+
+static void
+ipkdbofleave(kip)
+       struct ipkdb_if *kip;
+{
+}
+
+static int
+ipkdbofrcv(kip, buf, poll)
+       struct ipkdb_if *kip;
+       u_char *buf;
+       int poll;
+{
+       int l;
+       
+       do {
+               l = OF_read(kip->port, buf, ETHERMTU);
+               if (l < 0)
+                       l = 0;
+       } while (!poll && !l);
+       return l;
+}
+
+static void
+ipkdbofsend(kip, buf, l)
+       struct ipkdb_if *kip;
+       u_char *buf;
+       int l;
+{
+       OF_write(kip->port, buf, l);
+}
+
+static int
+ipkdbprobe(match, aux)
+       void *match, *aux;
+{
+       struct cfdata *cf = match;
+       struct ipkdb_if *kip = aux;
+       static char name[256];
+       int len;
+       int phandle;
+       
+       kip->unit = cf->cf_unit + 1;
+
+       if (!(kip->port = OF_open("net")))
+               return -1;
+       if ((len = OF_instance_to_path(kip->port, name, sizeof name - 1)) < 0
+           || len >= sizeof name)
+               return -1;
+       name[len] = 0;
+       if ((phandle = OF_instance_to_package(kip->port)) == -1)
+               return -1;
+       if (OF_getprop(phandle, "mac-address", kip->myenetaddr, sizeof kip->myenetaddr)
+           < 0)
+               return -1;
+       
+       kip->flags |= IPKDB_MYHW;
+       kip->name = name;
+       kip->start = ipkdbofstart;
+       kip->leave = ipkdbofleave;
+       kip->receive = ipkdbofrcv;
+       kip->send = ipkdbofsend;
+
+       kifp = kip;
+       
+       return 0;
+}
+#endif
diff --git a/sys/dev/ofw/ofrtc.c b/sys/dev/ofw/ofrtc.c
new file mode 100644 (file)
index 0000000..d382c5f
--- /dev/null
@@ -0,0 +1,260 @@
+/*     $NetBSD: ofrtc.c,v 1.3 1996/10/13 01:38:14 christos Exp $       */
+
+/*
+ * Copyright (C) 1996 Wolfgang Solfrank.
+ * Copyright (C) 1996 TooLs GmbH.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 <sys/param.h>
+#include <sys/device.h>
+
+#include <dev/ofw/openfirm.h>
+
+struct ofrtc_softc {
+       struct device sc_dev;
+       int sc_phandle;
+       int sc_ihandle;
+};
+
+static int ofrtcprobe __P((struct device *, void *, void *));
+static void ofrtcattach __P((struct device *, struct device *, void *));
+
+struct cfattach ofrtc_ca = {
+       sizeof(struct ofrtc_softc), ofrtcprobe, ofrtcattach
+};
+
+struct cfdriver ofrtc_cd = {
+       NULL, "ofrtc", DV_DULL
+};
+
+static int
+ofrtcprobe(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       struct ofprobe *ofp = aux;
+       char type[8];
+       int l;
+       
+       if ((l = OF_getprop(ofp->phandle, "device_type", type, sizeof type - 1)) < 0)
+               return 0;
+       if (l >= sizeof type)
+               return 0;
+       
+       return !strcmp(type, "rtc");
+}
+
+int OF_clock_read(int *sec, int *min, int *hour, int *day,
+         int *mon, int *yr);
+typedef int (clock_read_t)(int *sec, int *min, int *hour, int *day,
+         int *mon, int *yr);
+extern clock_read_t *clock_read;
+
+static void
+ofrtcattach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct ofrtc_softc *of = (void *)self;
+       struct ofprobe *ofp = aux;
+       char name[32];
+       int l;
+       
+       clock_read = &OF_clock_read;
+       of->sc_phandle = ofp->phandle;
+       of->sc_ihandle = 0;
+       if ((l = OF_getprop(of->sc_phandle, "name", name, sizeof name - 1)) < 0)
+               panic("Device without name?");
+       if (l >= sizeof name)
+               l = sizeof name - 1;
+       name[l] = 0;
+       printf(": %s\n", name);
+}
+
+int
+ofrtcopen(dev, flags, fmt)
+       dev_t dev;
+       int flags;
+       int fmt;
+{
+       struct ofrtc_softc *of;
+       int unit = minor(dev);
+       char path[256];
+       int l;
+       
+       if (unit >= ofrtc_cd.cd_ndevs)
+               return ENXIO;
+       if (!(of = ofrtc_cd.cd_devs[unit]))
+               return ENXIO;
+       if (!of->sc_ihandle) {
+               if ((l = OF_package_to_path(of->sc_phandle, path, sizeof path - 1)) < 0)
+                       return ENXIO;
+               if (l >= sizeof path)
+                       return ENXIO;
+               path[l] = 0;
+               
+               if (!(of->sc_ihandle = OF_open(path))) {
+                       if (of->sc_ihandle) {
+                               OF_close(of->sc_ihandle);
+                               of->sc_ihandle = 0;
+                       }
+                       return ENXIO;
+               }
+
+       }
+
+       return 0;
+}
+
+int
+ofrtcclose(dev, flags, fmt)
+       dev_t dev;
+       int flags;
+       int fmt;
+{
+       return 0;
+}
+
+static void
+twodigit(bp, i)
+       char *bp;
+       int i;
+{
+       *bp++ = i / 10 + '0';
+       *bp = i % 10 + '0';
+}
+
+static int
+twodigits(bp)
+       char *bp;
+{
+       int i;
+       
+       i = *bp++ - '0';
+       return i * 10 + *bp++ - '0';
+}
+
+int
+ofrtcread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+       int flag;
+{
+       struct ofrtc_softc *of = ofrtc_cd.cd_devs[minor(dev)];
+       int date[6];
+       char buf[14];
+       int xlen;
+       
+       if (uio->uio_offset >= sizeof buf)
+               return 0;
+       
+       if (OF_call_method("get-time", of->sc_ihandle, 0, 6,
+                          date, date + 1, date + 2,
+                          date + 3, date + 4, date + 5))
+               return EIO;
+
+       twodigit(buf, date[5] % 100);
+       twodigit(buf + 2, date[4]);
+       twodigit(buf + 4, date[3]);
+       twodigit(buf + 6, date[2]);
+       twodigit(buf + 8, date[1]);
+       buf[10] = '.';
+       twodigit(buf + 11, date[0]);
+       buf[13] = '\n';
+       
+       xlen = sizeof(buf) - uio->uio_offset;
+       if (xlen > uio->uio_resid)
+               xlen = uio->uio_resid;
+       
+       return uiomove((caddr_t)buf, xlen, uio);
+}
+
+int
+ofrtcwrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+       int flag;
+{
+       struct ofrtc_softc *of = ofrtc_cd.cd_devs[minor(dev)];
+       char buf[14];
+       int cnt, year, error;
+       
+       /*
+        * We require atomic updates!
+        */
+       cnt = uio->uio_resid;
+       if (uio->uio_offset || (cnt != sizeof buf && cnt != sizeof buf - 1))
+               return EINVAL;
+       
+       if (error = uiomove((caddr_t)buf, sizeof buf, uio))
+               return error;
+
+       if (cnt == sizeof buf && buf[sizeof buf - 1] != '\n')
+               return EINVAL;
+       
+       year = twodigits(buf) + 1900;
+       if (year < 1970)
+               year += 100;
+       if (OF_call_method("set-time", of->sc_ihandle, 6, 0,
+                          twodigits(buf + 11), twodigits(buf + 8), twodigits(buf + 6),
+                          twodigits(buf + 4), twodigits(buf + 2), year))
+               return EIO;
+       return 0;
+}
+
+
+int
+OF_clock_read(int *sec, int *min, int *hour, int *day,
+         int *mon, int *yr)
+{
+       struct ofrtc_softc *of;
+        char path[256];
+        int l;
+
+       if (!(of = ofrtc_cd.cd_devs[0]))
+               return 0;
+       if ((l = OF_package_to_path(of->sc_phandle, path, sizeof path - 1)) < 0)
+               return 0;
+       if (l >= sizeof path)
+               return 0;
+       path[l] = 0;
+       
+       if (!(of->sc_ihandle = OF_open(path))) {
+               if (of->sc_ihandle) {
+                       OF_close(of->sc_ihandle);
+                       of->sc_ihandle = 0;
+               }
+               return 0;
+       }
+       if (OF_call_method("get-time", of->sc_ihandle, 0, 6,
+                       sec, min, hour, day, mon, yr))
+               return 0;
+
+       return 1;
+}
diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h
new file mode 100644 (file)
index 0000000..25f5a49
--- /dev/null
@@ -0,0 +1,94 @@
+/*     $NetBSD: openfirm.h,v 1.1 1996/09/30 16:35:10 ws Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
+ */
+/*
+ * Prototypes for OpenFirmware Interface Routines
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+
+int openfirmware __P((void *));
+
+extern char *OF_buf;
+
+int OF_peer __P((int phandle));
+int OF_child __P((int phandle));
+int OF_parent __P((int phandle));
+int OF_instance_to_package __P((int ihandle));
+int OF_getprop __P((int handle, char *prop, void *buf, int buflen));
+int OF_finddevice __P((char *name));
+int OF_instance_to_path __P((int ihandle, char *buf, int buflen));
+int OF_package_to_path __P((int phandle, char *buf, int buflen));
+int OF_call_method_1 __P((char *method, int ihandle, int nargs, ...));
+int OF_call_method __P((char *method, int ihandle, int nargs, int nreturns, ...));
+int OF_open __P((char *dname));
+void OF_close __P((int handle));
+int OF_read __P((int handle, void *addr, int len));
+int OF_write __P((int handle, void *addr, int len));
+int OF_seek __P((int handle, u_quad_t pos));
+void OF_boot __P((char *bootspec)) __attribute__((__noreturn__));
+void OF_enter __P((void));
+void OF_exit __P((void)) __attribute__((__noreturn__));
+void (*OF_set_callback __P((void (*newfunc)(void *)))) ();
+
+/*
+ * Some generic routines for OpenFirmware handling.
+ */
+int ofnmmatch __P((char *cp1, char *cp2));
+
+/*
+ * Generic OpenFirmware probe argument.
+ * This is how all probe structures must start
+ * in order to support generic OpenFirmware device drivers.
+ */
+struct ofprobe {
+       int phandle;
+       /*
+        * Special unit field for disk devices.
+        * This is a KLUDGE to work around the fact that OpenFirmware
+        * doesn't probe the scsi bus completely.
+        * YES, I THINK THIS IS A BUG IN THE OPENFIRMWARE DEFINITION!!! XXX
+        * See also ofdisk.c.
+        */
+       int unit;
+};
+
+/*
+ * The softc structure for devices we might be booted from (i.e. we might
+ * want to set root/swap to) needs to start with these fields:         XXX
+ */
+struct ofb_softc {
+       struct device sc_dev;
+       int sc_phandle;
+       int sc_unit;            /* Might be missing for non-disk devices */
+};