summaryrefslogtreecommitdiff
path: root/sys/dev/isa/fdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/isa/fdc.c')
-rw-r--r--sys/dev/isa/fdc.c374
1 files changed, 374 insertions, 0 deletions
diff --git a/sys/dev/isa/fdc.c b/sys/dev/isa/fdc.c
new file mode 100644
index 00000000000..cd59a36ebab
--- /dev/null
+++ b/sys/dev/isa/fdc.c
@@ -0,0 +1,374 @@
+/* $OpenBSD: fdc.c,v 1.1 1996/09/01 20:58:26 downsj Exp $ */
+/* $NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995 Charles Hannum.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Portions Copyright (c) 1993, 1994 by
+ * jc@irbs.UUCP (John Capo)
+ * vak@zebub.msk.su (Serge Vakulenko)
+ * ache@astral.msk.su (Andrew A. Chernov)
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)fd.c 7.4 (Berkeley) 5/25/91
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/disk.h>
+#include <sys/buf.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/mtio.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/conf.h>
+#include <machine/intr.h>
+#include <machine/ioctl_fd.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
+#include <i386/isa/fdreg.h>
+
+#include <dev/ic/mc146818reg.h> /* for NVRAM access */
+#include <i386/isa/nvram.h>
+
+#include <i386/isa/fdlink.h>
+
+#include "fd.h"
+
+/* controller driver configuration */
+int fdcprobe __P((struct device *, void *, void *));
+#ifdef NEWCONFIG
+void fdcforceintr __P((void *));
+#endif
+void fdcattach __P((struct device *, struct device *, void *));
+
+struct cfattach fdc_ca = {
+ sizeof(struct fdc_softc), fdcprobe, fdcattach
+};
+
+struct cfdriver fdc_cd = {
+ NULL, "fdc", DV_DULL
+};
+
+int fddprint __P((void *, char *));
+int fdcintr __P((void *));
+
+int
+fdcprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ register struct isa_attach_args *ia = aux;
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ int rv;
+
+ bc = ia->ia_bc;
+ rv = 0;
+
+ /* Map the i/o space. */
+ if (bus_io_map(bc, ia->ia_iobase, FDC_NPORT, &ioh))
+ return 0;
+
+ /* reset */
+ bus_io_write_1(bc, ioh, fdout, 0);
+ delay(100);
+ bus_io_write_1(bc, ioh, fdout, FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(bc, ioh, NE7CMD_SPECIFY) < 0)
+ goto out;
+ out_fdc(bc, ioh, 0xdf);
+ out_fdc(bc, ioh, 2);
+
+#ifdef NEWCONFIG
+ if (ia->ia_iobase == IOBASEUNK || ia->ia_drq == DRQUNK)
+ return 0;
+
+ if (ia->ia_irq == IRQUNK) {
+ ia->ia_irq = isa_discoverintr(fdcforceintr, aux);
+ if (ia->ia_irq == IRQNONE)
+ goto out;
+
+ /* reset it again */
+ bus_io_write_1(bc, ioh, fdout, 0);
+ delay(100);
+ bus_io_write_1(bc, ioh, fdout, FDO_FRST);
+ }
+#endif
+
+ rv = 1;
+ ia->ia_iosize = FDC_NPORT;
+ ia->ia_msize = 0;
+
+ out:
+ bus_io_unmap(bc, ioh, FDC_NPORT);
+ return rv;
+}
+
+#ifdef NEWCONFIG
+/*
+ * XXX This is broken, and needs fixing. In general, the interface needs
+ * XXX to change.
+ */
+void
+fdcforceintr(aux)
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ int iobase = ia->ia_iobase;
+
+ /* the motor is off; this should generate an error with or
+ without a disk drive present */
+ out_fdc(bc, ioh, NE7CMD_SEEK);
+ out_fdc(bc, ioh, 0);
+ out_fdc(bc, ioh, 0);
+}
+#endif
+
+void
+fdcattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct fdc_softc *fdc = (void *)self;
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ struct isa_attach_args *ia = aux;
+ struct fdc_attach_args fa;
+ int type;
+
+ bc = ia->ia_bc;
+
+ /* Re-map the I/O space. */
+ if (bus_io_map(bc, ia->ia_iobase, FDC_NPORT, &ioh))
+ panic("fdcattach: couldn't map I/O ports");
+
+ fdc->sc_bc = bc;
+ fdc->sc_ioh = ioh;
+
+ fdc->sc_drq = ia->ia_drq;
+ fdc->sc_state = DEVIDLE;
+ TAILQ_INIT(&fdc->sc_drives);
+
+ printf("\n");
+
+#ifdef NEWCONFIG
+ at_setup_dmachan(fdc->sc_drq, FDC_MAXIOSIZE);
+ isa_establish(&fdc->sc_id, &fdc->sc_dev);
+#endif
+ fdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
+ IPL_BIO, fdcintr, fdc, fdc->sc_dev.dv_xname);
+
+ /*
+ * The NVRAM info only tells us about the first two disks on the
+ * `primary' floppy controller.
+ */
+ if (fdc->sc_dev.dv_unit == 0)
+ type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
+ else
+ type = -1;
+
+ /* physical limit: four drives per controller. */
+ for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
+ fa.fa_flags = 0;
+#if NFD > 0
+ if (type >= 0 && fa.fa_drive < 2)
+ fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
+ type, fa.fa_drive);
+ else
+#endif
+ fa.fa_deftype = NULL; /* unknown */
+ (void)config_found(self, (void *)&fa, fddprint);
+ }
+}
+
+/*
+ * Print the location of a disk/tape drive (called just before attaching the
+ * the drive). If `fdc' is not NULL, the drive was found but was not
+ * in the system config file; print the drive name as well.
+ * Return QUIET (config_find ignores this if the device was configured) to
+ * avoid printing `fdN not configured' messages.
+ */
+int
+fddprint(aux, fdc)
+ void *aux;
+ char *fdc;
+{
+ register struct fdc_attach_args *fa = aux;
+
+ if (!fdc)
+ printf(" drive %d", fa->fa_drive);
+ return QUIET;
+}
+
+int
+fdcresult(fdc)
+ struct fdc_softc *fdc;
+{
+ bus_chipset_tag_t bc = fdc->sc_bc;
+ bus_io_handle_t ioh = fdc->sc_ioh;
+ u_char i;
+ int j = 100000,
+ n = 0;
+
+ for (; j; j--) {
+ i = bus_io_read_1(bc, ioh, fdsts) &
+ (NE7_DIO | NE7_RQM | NE7_CB);
+ if (i == NE7_RQM)
+ return n;
+ if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
+ if (n >= sizeof(fdc->sc_status)) {
+ log(LOG_ERR, "fdcresult: overrun\n");
+ return -1;
+ }
+ fdc->sc_status[n++] = bus_io_read_1(bc, ioh, fddata);
+ }
+ }
+ log(LOG_ERR, "fdcresult: timeout\n");
+ return -1;
+}
+
+int
+out_fdc(bc, ioh, x)
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ u_char x;
+{
+ int i = 100000;
+
+ while ((bus_io_read_1(bc, ioh, fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0)
+ return -1;
+ while ((bus_io_read_1(bc, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0)
+ return -1;
+ bus_io_write_1(bc, ioh, fddata, x);
+ return 0;
+}
+
+void
+fdcstart(fdc)
+ struct fdc_softc *fdc;
+{
+
+#ifdef DIAGNOSTIC
+ /* only got here if controller's drive queue was inactive; should
+ be in idle state */
+ if (fdc->sc_state != DEVIDLE) {
+ printf("fdcstart: not idle\n");
+ return;
+ }
+#endif
+ (void) fdcintr(fdc);
+}
+
+void
+fdcstatus(dv, n, s)
+ struct device *dv;
+ int n;
+ char *s;
+{
+ struct fdc_softc *fdc = (void *)dv->dv_parent;
+
+ if (n == 0) {
+ out_fdc(fdc->sc_bc, fdc->sc_ioh, NE7CMD_SENSEI);
+ (void) fdcresult(fdc);
+ n = 2;
+ }
+
+ printf("%s: %s", dv->dv_xname, s);
+
+ switch (n) {
+ case 0:
+ printf("\n");
+ break;
+ case 2:
+ printf(" (st0 %b cyl %d)\n",
+ fdc->sc_status[0], NE7_ST0BITS,
+ fdc->sc_status[1]);
+ break;
+ case 7:
+ printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
+ fdc->sc_status[0], NE7_ST0BITS,
+ fdc->sc_status[1], NE7_ST1BITS,
+ fdc->sc_status[2], NE7_ST2BITS,
+ fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
+ break;
+#ifdef DIAGNOSTIC
+ default:
+ printf("\nfdcstatus: weird size");
+ break;
+#endif
+ }
+}
+
+void
+fdcpseudointr(arg)
+ void *arg;
+{
+ int s;
+
+ /* Just ensure it has the right spl. */
+ s = splbio();
+ (void) fdcintr(arg);
+ splx(s);
+}
+
+int
+fdcintr(arg)
+ void *arg;
+{
+ struct fdc_softc *fdc = arg;
+
+#if NFD > 0
+ /* Will switch on device type, shortly. */
+ return (fdintr(fdc));
+#else
+ printf("fdcintr: got interrupt, but no devices!\n");
+#endif
+}