123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /* $OpenBSD: fdc.c,v 1.20 2015/03/14 03:38:47 jsg 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. 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/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 <sys/timeout.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/fdreg.h>
- #if defined(__i386__) || defined(__amd64__) /* XXX */
- #include <dev/ic/mc146818reg.h> /* for NVRAM access */
- #include <i386/isa/nvram.h>
- #endif
- #include <dev/isa/fdlink.h>
- #include "fd.h"
- /* controller driver configuration */
- int fdcprobe(struct device *, void *, void *);
- void fdcattach(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(void *, const char *);
- int fdcintr(void *);
- int
- fdcprobe(struct device *parent, void *match, void *aux)
- {
- register struct isa_attach_args *ia = aux;
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
- bus_space_handle_t ioh_ctl;
- int rv;
- iot = ia->ia_iot;
- rv = 0;
- /* Map the i/o space. */
- if (bus_space_map(iot, ia->ia_iobase, FDC_NPORT, 0, &ioh))
- return 0;
- if (bus_space_map(iot, ia->ia_iobase + FDCTL_OFFSET,
- FDCTL_NPORT, 0, &ioh_ctl))
- return 0;
- /* reset */
- bus_space_write_1(iot, ioh, fdout, 0);
- delay(100);
- bus_space_write_1(iot, ioh, fdout, FDO_FRST);
- /* see if it can handle a command */
- if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
- goto out;
- out_fdc(iot, ioh, 0xdf);
- out_fdc(iot, ioh, 2);
- rv = 1;
- ia->ia_iosize = FDC_NPORT;
- ia->ia_msize = 0;
- out:
- bus_space_unmap(iot, ioh, FDC_NPORT);
- bus_space_unmap(iot, ioh_ctl, FDCTL_NPORT);
- return rv;
- }
- void
- fdcattach(struct device *parent, struct device *self, void *aux)
- {
- struct fdc_softc *fdc = (void *)self;
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
- bus_space_handle_t ioh_ctl;
- struct isa_attach_args *ia = aux;
- struct fdc_attach_args fa;
- int type;
- iot = ia->ia_iot;
- /* Re-map the I/O space. */
- if (bus_space_map(iot, ia->ia_iobase, FDC_NPORT, 0, &ioh) ||
- bus_space_map(iot, ia->ia_iobase + FDCTL_OFFSET,
- FDCTL_NPORT, 0, &ioh_ctl))
- panic("fdcattach: couldn't map I/O ports");
- fdc->sc_iot = iot;
- fdc->sc_ioh = ioh;
- fdc->sc_ioh_ctl = ioh_ctl;
- fdc->sc_drq = ia->ia_drq;
- fdc->sc_state = DEVIDLE;
- TAILQ_INIT(&fdc->sc_link.fdlink.sc_drives); /* XXX */
- printf("\n");
- fdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
- IPL_BIO, fdcintr, fdc, fdc->sc_dev.dv_xname);
- #if defined(__i386__) || defined(__amd64__)
- /*
- * 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
- #endif
- type = -1;
- timeout_set(&fdc->fdcpseudointr_to, fdcpseudointr, fdc);
- /* physical limit: four drives per controller. */
- for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
- fa.fa_flags = 0;
- fa.fa_type = 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(void *aux, const char *fdc)
- {
- register struct fdc_attach_args *fa = aux;
- if (!fdc)
- printf(" drive %d", fa->fa_drive);
- return QUIET;
- }
- int
- fdcresult(struct fdc_softc *fdc)
- {
- bus_space_tag_t iot = fdc->sc_iot;
- bus_space_handle_t ioh = fdc->sc_ioh;
- u_char i;
- int j = 100000, n = 0;
- for (; j; j--) {
- i = bus_space_read_1(iot, 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_space_read_1(iot, ioh, fddata);
- }
- delay(10);
- }
- return -1;
- }
- int
- out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
- {
- int i = 100000;
- while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
- if (i <= 0)
- return -1;
- while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
- if (i <= 0)
- return -1;
- bus_space_write_1(iot, ioh, fddata, x);
- return 0;
- }
- void
- fdcstart(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(struct device *dv, int n, char *s)
- {
- struct fdc_softc *fdc = (void *)dv->dv_parent;
- if (n == 0) {
- out_fdc(fdc->sc_iot, 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(void *arg)
- {
- int s;
- /* Just ensure it has the right spl. */
- s = splbio();
- (void) fdcintr(arg);
- splx(s);
- }
- int
- fdcintr(void *arg)
- {
- #if NFD > 0
- struct fdc_softc *fdc = arg;
- extern int fdintr(struct fdc_softc *);
- /* Will switch on device type, shortly. */
- return (fdintr(fdc));
- #else
- printf("fdcintr: got interrupt, but no devices!\n");
- return (1);
- #endif
- }
|