summaryrefslogtreecommitdiffstats
path: root/sys/pc98
diff options
context:
space:
mode:
authorkato <kato@FreeBSD.org>1998-12-14 09:06:23 +0000
committerkato <kato@FreeBSD.org>1998-12-14 09:06:23 +0000
commit89c9c41887ed8aa97a01e14fc20114c102274863 (patch)
tree64c7cdc0a6892e9c76c1735a800418826bc90a15 /sys/pc98
parent7733b9192b815a4b5dbf6793bb43bba0fa5a0be2 (diff)
downloadFreeBSD-src-89c9c41887ed8aa97a01e14fc20114c102274863.zip
FreeBSD-src-89c9c41887ed8aa97a01e14fc20114c102274863.tar.gz
Sync with sys/i386/isa/fd.c revision 1.128.
Diffstat (limited to 'sys/pc98')
-rw-r--r--sys/pc98/cbus/fdc.c367
-rw-r--r--sys/pc98/pc98/fd.c367
2 files changed, 720 insertions, 14 deletions
diff --git a/sys/pc98/cbus/fdc.c b/sys/pc98/cbus/fdc.c
index 154c33a..4446b82 100644
--- a/sys/pc98/cbus/fdc.c
+++ b/sys/pc98/cbus/fdc.c
@@ -5,6 +5,10 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
+ * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
+ * aided by the Linux floppy driver modifications from David Bateman
+ * (dbateman@eng.uts.edu.au).
+ *
* Copyright (c) 1993, 1994 by
* jc@irbs.UUCP (John Capo)
* vak@zebub.msk.su (Serge Vakulenko)
@@ -43,7 +47,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.44 1998/12/08 08:18:58 kato Exp $
+ * $Id: fd.c,v 1.45 1998/12/10 19:57:00 eivind Exp $
*
*/
@@ -97,6 +101,10 @@
/* configuration flags */
#define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */
+#ifdef FDC_YE
+#define FDC_IS_PCMCIA (1 << 1) /* if successful probe, then it's
+ a PCMCIA device */
+#endif
/* internally used only, not really from CMOS: */
#define RTCFDT_144M_PRETENDED 0x1000
@@ -296,6 +304,11 @@ int ftsize(dev_t);
int ftattach(struct isa_device *, struct isa_device *, int);
#endif
+#ifdef FDC_YE
+#include "card.h"
+static int yeattach(struct isa_device *);
+#endif
+
/* autoconfig functions */
static int fdprobe(struct isa_device *);
static int fdattach(struct isa_device *);
@@ -339,6 +352,9 @@ static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
#define MOTORWAIT 10
#define IOTIMEDOUT 11
#define RESETCOMPLETE 12
+#ifdef FDC_YE
+#define PIOREAD 13
+#endif
#ifdef FDC_DEBUG
static char const * const fdstates[] =
@@ -356,6 +372,9 @@ static char const * const fdstates[] =
"MOTORWAIT",
"IOTIMEDOUT",
"RESETCOMPLETE",
+#ifdef FDC_YE
+,"PIOREAD"
+#endif
};
/* CAUTION: fd_debug causes huge amounts of logging output */
@@ -367,6 +386,99 @@ static int volatile fd_debug = 0;
#define TRACE1(arg1, arg2)
#endif /* FDC_DEBUG */
+#ifdef FDC_YE
+#if NCARD > 0
+#include <sys/select.h>
+#include <pccard/cardinfo.h>
+#include <pccard/driver.h>
+#include <pccard/slot.h>
+
+/*
+ * PC-Card (PCMCIA) specific code.
+ */
+static int yeinit(struct pccard_devinfo *); /* init device */
+static void yeunload(struct pccard_devinfo *); /* Disable driver */
+static int yeintr(struct pccard_devinfo *); /* Interrupt handler */
+
+static struct pccard_device ye_info = {
+ "fdc",
+ yeinit,
+ yeunload,
+ yeintr,
+ 0, /* Attributes - presently unused */
+ &bio_imask /* Interrupt mask for device */
+};
+
+DATA_SET(pccarddrv_set, ye_info);
+
+/*
+ * this is the secret PIO data port (offset from base)
+ */
+#define FDC_YE_DATAPORT 6
+
+/*
+ * Initialize the device - called from Slot manager.
+ */
+static int yeinit(struct pccard_devinfo *devi)
+{
+ fdc_p fdc = &fdc_data[devi->isahd.id_unit];
+
+ /* validate unit number. */
+ if (devi->isahd.id_unit >= NFDC)
+ return(ENODEV);
+ fdc->baseport = devi->isahd.id_iobase;
+ /*
+ * reset controller
+ */
+ outb(fdc->baseport+FDOUT, 0);
+ DELAY(100);
+ outb(fdc->baseport+FDOUT, FDO_FRST);
+
+ /*
+ * wire into system
+ */
+ if (yeattach(&devi->isahd) == 0)
+ return(ENXIO);
+
+ return(0);
+}
+
+/*
+ * yeunload - unload the driver and clear the table.
+ * XXX TODO:
+ * This is usually called when the card is ejected, but
+ * can be caused by a modunload of a controller driver.
+ * The idea is to reset the driver's view of the device
+ * and ensure that any driver entry points such as
+ * read and write do not hang.
+ */
+static void yeunload(struct pccard_devinfo *devi)
+{
+ if (fd_data[devi->isahd.id_unit].type == NO_TYPE)
+ return;
+
+ /*
+ * this prevents Fdopen() and fdstrategy() from attempting
+ * to access unloaded controller
+ */
+ fd_data[devi->isahd.id_unit].type = NO_TYPE;
+
+ printf("fdc%d: unload\n", devi->isahd.id_unit);
+}
+
+/*
+ * yeintr - Shared interrupt called from
+ * front end of PC-Card handler.
+ */
+static int yeintr(struct pccard_devinfo *devi)
+{
+ fdintr((fdcu_t)devi->isahd.id_unit);
+ return(1);
+}
+#endif /* NCARD > 0 */
+#endif /* FDC_YE */
+
+
/* autoconfig structure */
struct isa_driver fdcdriver = {
@@ -405,7 +517,7 @@ fdc_err(fdcu_t fdcu, const char *s)
printf("fdc%d: %s", fdcu, s);
else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
printf("fdc%d: too many errors, not logging any more\n",
- fdcu);
+ fdcu);
}
return FD_FAILED;
@@ -698,6 +810,14 @@ fdprobe(struct isa_device *dev)
{
return(0);
}
+#ifdef FDC_YE
+ /*
+ * don't succeed on probe; wait
+ * for PCCARD subsystem to do it
+ */
+ if (dev->id_flags & FDC_IS_PCMCIA)
+ return(0);
+#endif
return (IO_FDCSIZE);
}
@@ -880,7 +1000,7 @@ fdattach(struct isa_device *dev)
enable_fifo(fdc) == 0) {
printf("fdc%d: FIFO enabled", fdcu);
printf(", %d bytes threshold\n",
- fifo_threshold);
+ fifo_threshold);
}
}
if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
@@ -1091,6 +1211,138 @@ fdattach(struct isa_device *dev)
+#ifdef FDC_YE
+/*
+ * this is a subset of fdattach() optimized for the Y-E Data
+ * PCMCIA floppy drive.
+ */
+static int yeattach(struct isa_device *dev)
+{
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fdsu_t fdsu = 0; /* assume 1 drive per YE controller */
+ fdu_t fdu;
+ fd_p fd;
+ int st0, st3, i;
+#ifdef DEVFS
+ int mynor;
+ int typemynor;
+ int typesize;
+#endif
+ fdc->fdcu = fdcu;
+ /*
+ * the FDC_PCMCIA flag is used to to indicate special PIO is used
+ * instead of DMA
+ */
+ fdc->flags = FDC_ATTACHED|FDC_PCMCIA;
+ fdc->state = DEVIDLE;
+ /* reset controller, turn motor off, clear fdout mirror reg */
+ outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
+ bufq_init(&fdc->head);
+ /*
+ * assume 2 drives/ "normal" controller
+ */
+ fdu = fdcu * 2;
+ if (fdu >= NFD) {
+ printf("fdu %d >= NFD\n",fdu);
+ return(0);
+ };
+ fd = &fd_data[fdu];
+
+ set_motor(fdcu, fdsu, TURNON);
+ DELAY(1000000); /* 1 sec */
+ fdc->fdct = FDC_NE765;
+
+ if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
+ /* if at track 0, first seek inwards */
+ /* seek some steps: */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
+ DELAY(300000); /* ...wait a moment... */
+ (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
+ }
+
+ /* If we're at track 0 first seek inwards. */
+ if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
+ /* Seek some steps... */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
+ /* ...wait a moment... */
+ DELAY(300000);
+ /* make ctrlr happy: */
+ (void)fd_sense_int(fdc, 0, 0);
+ }
+ }
+
+ for(i = 0; i < 2; i++) {
+ /*
+ * we must recalibrate twice, just in case the
+ * heads have been beyond cylinder 76, since most
+ * FDCs still barf when attempting to recalibrate
+ * more than 77 steps
+ */
+ /* go back to 0: */
+ if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
+ /* a second being enough for full stroke seek*/
+ DELAY(i == 0? 1000000: 300000);
+
+ /* anything responding? */
+ if (fd_sense_int(fdc, &st0, 0) == 0 &&
+ (st0 & NE7_ST0_EC) == 0)
+ break; /* already probed succesfully */
+ }
+ }
+
+ set_motor(fdcu, fdsu, TURNOFF);
+
+ if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
+ return(0);
+
+ fd->track = FD_NO_TRACK;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ fd->options = 0;
+ printf("fdc%d: 1.44MB 3.5in PCMCIA\n", fdcu);
+ fd->type = FD_1440;
+
+#ifdef DEVFS
+ mynor = fdcu << 6;
+ fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK,
+ UID_ROOT, GID_OPERATOR, 0640,
+ "fd%d", fdu);
+ fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR,
+ UID_ROOT, GID_OPERATOR, 0640,
+ "rfd%d", fdu);
+ /*
+ * XXX this and the lookup in Fdopen() should be
+ * data driven.
+ */
+ typemynor = mynor | FD_1440;
+ typesize = fd_types[FD_1440 - 1].size / 2;
+ /*
+ * XXX all these conversions give bloated code and
+ * confusing names.
+ */
+ if (typesize == 1476)
+ typesize = 1480;
+ if (typesize == 1722)
+ typesize = 1720;
+ fd->bdevs[FD_1440] = devfs_add_devswf(&fd_bdevsw, typemynor,
+ DV_BLK, UID_ROOT, GID_OPERATOR,
+ 0640, "fd%d.%d", fdu, typesize);
+ fd->cdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor,
+ DV_CHR, UID_ROOT, GID_OPERATOR,
+ 0640,"rfd%d.%d", fdu, typesize);
+ for (i = 0; i < MAXPARTITIONS; i++) {
+ fd->bdevs[1 + NUMDENS + i] = devfs_link(fd->bdevs[0],
+ "fd%d%c", fdu, 'a' + i);
+ fd->cdevs[1 + NUMDENS + i] = devfs_link(fd->cdevs[0],
+ "rfd%d%c", fdu, 'a' + i);
+ }
+#endif /* DEVFS */
+ return (1);
+}
+#endif
+
/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
@@ -1455,6 +1707,17 @@ fdstrategy(struct buf *bp)
fd = &fd_data[fdu];
fdc = fd->fdc;
fdcu = fdc->fdcu;
+#ifdef FDC_YE
+ if (fd->type == NO_TYPE) {
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ /*
+ * I _refuse_ to use a goto
+ */
+ biodone(bp);
+ return;
+ };
+#endif
#if NFT > 0
if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
@@ -1622,6 +1885,38 @@ fdintr(fdcu_t fdcu)
;
}
+#ifdef FDC_YE
+/*
+ * magic pseudo-DMA initialization for YE FDC. Sets count and
+ * direction
+ */
+#define SET_BCDR(wr,cnt,port) outb(port,(((cnt)-1) & 0xff)); \
+ outb(port+1,((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)))
+
+/*
+ * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
+ */
+static int fdcpio(fdcu_t fdcu, long flags, caddr_t addr, u_int count)
+{
+ u_char *cptr = (u_char *)addr;
+ fdc_p fdc = &fdc_data[fdcu];
+ int io = fdc->baseport;
+
+ if (flags & B_READ) {
+ if (fdc->state != PIOREAD) {
+ fdc->state = PIOREAD;
+ return(0);
+ };
+ SET_BCDR(0,count,io);
+ insb(io+FDC_YE_DATAPORT,cptr,count);
+ } else {
+ outsb(io+FDC_YE_DATAPORT,cptr,count);
+ SET_BCDR(0,count,io);
+ };
+ return(1);
+}
+#endif /* FDC_YE */
+
/***********************************************************************\
* The controller state machine. *
* if it returns a non zero value, it should be called again immediatly *
@@ -1861,8 +2156,11 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
- format ? bp->b_bcount : fdblk, fdc->dmachan);
+#ifdef FDC_YE
+ if (!(fdc->flags & FDC_PCMCIA))
+#endif
+ isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
sectrac = fd->ft->sectrac;
sec = blknum % (sectrac * fd->ft->heads);
head = sec / sectrac;
@@ -1903,6 +2201,12 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
if(format)
{
+#ifdef FDC_YE
+ if (fdc->flags & FDC_PCMCIA)
+ (void)fdcpio(fdcu,bp->b_flags,
+ bp->b_data+fd->skip,
+ bp->b_bcount);
+#endif
/* formatting */
if(fd_cmd(fdcu, 6,
NE7CMD_FORMAT,
@@ -1923,6 +2227,24 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
}
else
{
+#ifdef FDC_YE
+ if (fdc->flags & FDC_PCMCIA) {
+ /*
+ * this seems to be necessary even when
+ * reading data
+ */
+ SET_BCDR(1,fdblk,fdc->baseport);
+
+ /*
+ * perform the write pseudo-DMA before
+ * the WRITE command is sent
+ */
+ if (!read)
+ (void)fdcpio(fdcu,bp->b_flags,
+ bp->b_data+fd->skip,
+ fdblk);
+ }
+#endif
if (fd_cmd(fdcu, 9,
(read ? NE7CMD_READ : NE7CMD_WRITE),
head << 2 | fdu, /* head & unit */
@@ -1943,6 +2265,24 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
return(retrier(fdcu));
}
}
+#ifdef FDC_YE
+ if (fdc->flags & FDC_PCMCIA)
+ /*
+ * if this is a read, then simply await interrupt
+ * before performing PIO
+ */
+ if (read && !fdcpio(fdcu,bp->b_flags,
+ bp->b_data+fd->skip,fdblk)) {
+ fd->tohandle = timeout(fd_iotimeout,
+ (caddr_t)fdcu, hz);
+ return(0); /* will return later */
+ };
+
+ /*
+ * write (or format) operation will fall through and
+ * await completion interrupt
+ */
+#endif
fdc->state = IOCOMPLETE;
fd->tohandle = timeout(fd_iotimeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
@@ -1976,6 +2316,16 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
fdc->state = IOCOMPLETE;
}
#endif
+#ifdef FDC_YE
+ case PIOREAD:
+ /*
+ * actually perform the PIO read. The IOCOMPLETE case
+ * removes the timeout for us.
+ */
+ (void)fdcpio(fdcu,bp->b_flags,bp->b_data+fd->skip,fdblk);
+ fdc->state = IOCOMPLETE;
+ /* FALLTHROUGH */
+#endif
case IOCOMPLETE: /* IO DONE, post-analyze */
#ifdef EPSON_NRDISK
if (fdu != nrdu)
@@ -2002,8 +2352,11 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
- format ? bp->b_bcount : fdblk, fdc->dmachan);
+#ifdef FDC_YE
+ if (!(fdc->flags & FDC_PCMCIA))
+#endif
+ isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
#ifdef EPSON_NRDISK
}
else nrd_LED_off();
diff --git a/sys/pc98/pc98/fd.c b/sys/pc98/pc98/fd.c
index 154c33a..4446b82 100644
--- a/sys/pc98/pc98/fd.c
+++ b/sys/pc98/pc98/fd.c
@@ -5,6 +5,10 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
+ * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
+ * aided by the Linux floppy driver modifications from David Bateman
+ * (dbateman@eng.uts.edu.au).
+ *
* Copyright (c) 1993, 1994 by
* jc@irbs.UUCP (John Capo)
* vak@zebub.msk.su (Serge Vakulenko)
@@ -43,7 +47,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.44 1998/12/08 08:18:58 kato Exp $
+ * $Id: fd.c,v 1.45 1998/12/10 19:57:00 eivind Exp $
*
*/
@@ -97,6 +101,10 @@
/* configuration flags */
#define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */
+#ifdef FDC_YE
+#define FDC_IS_PCMCIA (1 << 1) /* if successful probe, then it's
+ a PCMCIA device */
+#endif
/* internally used only, not really from CMOS: */
#define RTCFDT_144M_PRETENDED 0x1000
@@ -296,6 +304,11 @@ int ftsize(dev_t);
int ftattach(struct isa_device *, struct isa_device *, int);
#endif
+#ifdef FDC_YE
+#include "card.h"
+static int yeattach(struct isa_device *);
+#endif
+
/* autoconfig functions */
static int fdprobe(struct isa_device *);
static int fdattach(struct isa_device *);
@@ -339,6 +352,9 @@ static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
#define MOTORWAIT 10
#define IOTIMEDOUT 11
#define RESETCOMPLETE 12
+#ifdef FDC_YE
+#define PIOREAD 13
+#endif
#ifdef FDC_DEBUG
static char const * const fdstates[] =
@@ -356,6 +372,9 @@ static char const * const fdstates[] =
"MOTORWAIT",
"IOTIMEDOUT",
"RESETCOMPLETE",
+#ifdef FDC_YE
+,"PIOREAD"
+#endif
};
/* CAUTION: fd_debug causes huge amounts of logging output */
@@ -367,6 +386,99 @@ static int volatile fd_debug = 0;
#define TRACE1(arg1, arg2)
#endif /* FDC_DEBUG */
+#ifdef FDC_YE
+#if NCARD > 0
+#include <sys/select.h>
+#include <pccard/cardinfo.h>
+#include <pccard/driver.h>
+#include <pccard/slot.h>
+
+/*
+ * PC-Card (PCMCIA) specific code.
+ */
+static int yeinit(struct pccard_devinfo *); /* init device */
+static void yeunload(struct pccard_devinfo *); /* Disable driver */
+static int yeintr(struct pccard_devinfo *); /* Interrupt handler */
+
+static struct pccard_device ye_info = {
+ "fdc",
+ yeinit,
+ yeunload,
+ yeintr,
+ 0, /* Attributes - presently unused */
+ &bio_imask /* Interrupt mask for device */
+};
+
+DATA_SET(pccarddrv_set, ye_info);
+
+/*
+ * this is the secret PIO data port (offset from base)
+ */
+#define FDC_YE_DATAPORT 6
+
+/*
+ * Initialize the device - called from Slot manager.
+ */
+static int yeinit(struct pccard_devinfo *devi)
+{
+ fdc_p fdc = &fdc_data[devi->isahd.id_unit];
+
+ /* validate unit number. */
+ if (devi->isahd.id_unit >= NFDC)
+ return(ENODEV);
+ fdc->baseport = devi->isahd.id_iobase;
+ /*
+ * reset controller
+ */
+ outb(fdc->baseport+FDOUT, 0);
+ DELAY(100);
+ outb(fdc->baseport+FDOUT, FDO_FRST);
+
+ /*
+ * wire into system
+ */
+ if (yeattach(&devi->isahd) == 0)
+ return(ENXIO);
+
+ return(0);
+}
+
+/*
+ * yeunload - unload the driver and clear the table.
+ * XXX TODO:
+ * This is usually called when the card is ejected, but
+ * can be caused by a modunload of a controller driver.
+ * The idea is to reset the driver's view of the device
+ * and ensure that any driver entry points such as
+ * read and write do not hang.
+ */
+static void yeunload(struct pccard_devinfo *devi)
+{
+ if (fd_data[devi->isahd.id_unit].type == NO_TYPE)
+ return;
+
+ /*
+ * this prevents Fdopen() and fdstrategy() from attempting
+ * to access unloaded controller
+ */
+ fd_data[devi->isahd.id_unit].type = NO_TYPE;
+
+ printf("fdc%d: unload\n", devi->isahd.id_unit);
+}
+
+/*
+ * yeintr - Shared interrupt called from
+ * front end of PC-Card handler.
+ */
+static int yeintr(struct pccard_devinfo *devi)
+{
+ fdintr((fdcu_t)devi->isahd.id_unit);
+ return(1);
+}
+#endif /* NCARD > 0 */
+#endif /* FDC_YE */
+
+
/* autoconfig structure */
struct isa_driver fdcdriver = {
@@ -405,7 +517,7 @@ fdc_err(fdcu_t fdcu, const char *s)
printf("fdc%d: %s", fdcu, s);
else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
printf("fdc%d: too many errors, not logging any more\n",
- fdcu);
+ fdcu);
}
return FD_FAILED;
@@ -698,6 +810,14 @@ fdprobe(struct isa_device *dev)
{
return(0);
}
+#ifdef FDC_YE
+ /*
+ * don't succeed on probe; wait
+ * for PCCARD subsystem to do it
+ */
+ if (dev->id_flags & FDC_IS_PCMCIA)
+ return(0);
+#endif
return (IO_FDCSIZE);
}
@@ -880,7 +1000,7 @@ fdattach(struct isa_device *dev)
enable_fifo(fdc) == 0) {
printf("fdc%d: FIFO enabled", fdcu);
printf(", %d bytes threshold\n",
- fifo_threshold);
+ fifo_threshold);
}
}
if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
@@ -1091,6 +1211,138 @@ fdattach(struct isa_device *dev)
+#ifdef FDC_YE
+/*
+ * this is a subset of fdattach() optimized for the Y-E Data
+ * PCMCIA floppy drive.
+ */
+static int yeattach(struct isa_device *dev)
+{
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fdsu_t fdsu = 0; /* assume 1 drive per YE controller */
+ fdu_t fdu;
+ fd_p fd;
+ int st0, st3, i;
+#ifdef DEVFS
+ int mynor;
+ int typemynor;
+ int typesize;
+#endif
+ fdc->fdcu = fdcu;
+ /*
+ * the FDC_PCMCIA flag is used to to indicate special PIO is used
+ * instead of DMA
+ */
+ fdc->flags = FDC_ATTACHED|FDC_PCMCIA;
+ fdc->state = DEVIDLE;
+ /* reset controller, turn motor off, clear fdout mirror reg */
+ outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
+ bufq_init(&fdc->head);
+ /*
+ * assume 2 drives/ "normal" controller
+ */
+ fdu = fdcu * 2;
+ if (fdu >= NFD) {
+ printf("fdu %d >= NFD\n",fdu);
+ return(0);
+ };
+ fd = &fd_data[fdu];
+
+ set_motor(fdcu, fdsu, TURNON);
+ DELAY(1000000); /* 1 sec */
+ fdc->fdct = FDC_NE765;
+
+ if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
+ /* if at track 0, first seek inwards */
+ /* seek some steps: */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
+ DELAY(300000); /* ...wait a moment... */
+ (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
+ }
+
+ /* If we're at track 0 first seek inwards. */
+ if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
+ /* Seek some steps... */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
+ /* ...wait a moment... */
+ DELAY(300000);
+ /* make ctrlr happy: */
+ (void)fd_sense_int(fdc, 0, 0);
+ }
+ }
+
+ for(i = 0; i < 2; i++) {
+ /*
+ * we must recalibrate twice, just in case the
+ * heads have been beyond cylinder 76, since most
+ * FDCs still barf when attempting to recalibrate
+ * more than 77 steps
+ */
+ /* go back to 0: */
+ if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
+ /* a second being enough for full stroke seek*/
+ DELAY(i == 0? 1000000: 300000);
+
+ /* anything responding? */
+ if (fd_sense_int(fdc, &st0, 0) == 0 &&
+ (st0 & NE7_ST0_EC) == 0)
+ break; /* already probed succesfully */
+ }
+ }
+
+ set_motor(fdcu, fdsu, TURNOFF);
+
+ if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
+ return(0);
+
+ fd->track = FD_NO_TRACK;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ fd->options = 0;
+ printf("fdc%d: 1.44MB 3.5in PCMCIA\n", fdcu);
+ fd->type = FD_1440;
+
+#ifdef DEVFS
+ mynor = fdcu << 6;
+ fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK,
+ UID_ROOT, GID_OPERATOR, 0640,
+ "fd%d", fdu);
+ fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR,
+ UID_ROOT, GID_OPERATOR, 0640,
+ "rfd%d", fdu);
+ /*
+ * XXX this and the lookup in Fdopen() should be
+ * data driven.
+ */
+ typemynor = mynor | FD_1440;
+ typesize = fd_types[FD_1440 - 1].size / 2;
+ /*
+ * XXX all these conversions give bloated code and
+ * confusing names.
+ */
+ if (typesize == 1476)
+ typesize = 1480;
+ if (typesize == 1722)
+ typesize = 1720;
+ fd->bdevs[FD_1440] = devfs_add_devswf(&fd_bdevsw, typemynor,
+ DV_BLK, UID_ROOT, GID_OPERATOR,
+ 0640, "fd%d.%d", fdu, typesize);
+ fd->cdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor,
+ DV_CHR, UID_ROOT, GID_OPERATOR,
+ 0640,"rfd%d.%d", fdu, typesize);
+ for (i = 0; i < MAXPARTITIONS; i++) {
+ fd->bdevs[1 + NUMDENS + i] = devfs_link(fd->bdevs[0],
+ "fd%d%c", fdu, 'a' + i);
+ fd->cdevs[1 + NUMDENS + i] = devfs_link(fd->cdevs[0],
+ "rfd%d%c", fdu, 'a' + i);
+ }
+#endif /* DEVFS */
+ return (1);
+}
+#endif
+
/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
@@ -1455,6 +1707,17 @@ fdstrategy(struct buf *bp)
fd = &fd_data[fdu];
fdc = fd->fdc;
fdcu = fdc->fdcu;
+#ifdef FDC_YE
+ if (fd->type == NO_TYPE) {
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ /*
+ * I _refuse_ to use a goto
+ */
+ biodone(bp);
+ return;
+ };
+#endif
#if NFT > 0
if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
@@ -1622,6 +1885,38 @@ fdintr(fdcu_t fdcu)
;
}
+#ifdef FDC_YE
+/*
+ * magic pseudo-DMA initialization for YE FDC. Sets count and
+ * direction
+ */
+#define SET_BCDR(wr,cnt,port) outb(port,(((cnt)-1) & 0xff)); \
+ outb(port+1,((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)))
+
+/*
+ * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
+ */
+static int fdcpio(fdcu_t fdcu, long flags, caddr_t addr, u_int count)
+{
+ u_char *cptr = (u_char *)addr;
+ fdc_p fdc = &fdc_data[fdcu];
+ int io = fdc->baseport;
+
+ if (flags & B_READ) {
+ if (fdc->state != PIOREAD) {
+ fdc->state = PIOREAD;
+ return(0);
+ };
+ SET_BCDR(0,count,io);
+ insb(io+FDC_YE_DATAPORT,cptr,count);
+ } else {
+ outsb(io+FDC_YE_DATAPORT,cptr,count);
+ SET_BCDR(0,count,io);
+ };
+ return(1);
+}
+#endif /* FDC_YE */
+
/***********************************************************************\
* The controller state machine. *
* if it returns a non zero value, it should be called again immediatly *
@@ -1861,8 +2156,11 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
- format ? bp->b_bcount : fdblk, fdc->dmachan);
+#ifdef FDC_YE
+ if (!(fdc->flags & FDC_PCMCIA))
+#endif
+ isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
sectrac = fd->ft->sectrac;
sec = blknum % (sectrac * fd->ft->heads);
head = sec / sectrac;
@@ -1903,6 +2201,12 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
if(format)
{
+#ifdef FDC_YE
+ if (fdc->flags & FDC_PCMCIA)
+ (void)fdcpio(fdcu,bp->b_flags,
+ bp->b_data+fd->skip,
+ bp->b_bcount);
+#endif
/* formatting */
if(fd_cmd(fdcu, 6,
NE7CMD_FORMAT,
@@ -1923,6 +2227,24 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
}
else
{
+#ifdef FDC_YE
+ if (fdc->flags & FDC_PCMCIA) {
+ /*
+ * this seems to be necessary even when
+ * reading data
+ */
+ SET_BCDR(1,fdblk,fdc->baseport);
+
+ /*
+ * perform the write pseudo-DMA before
+ * the WRITE command is sent
+ */
+ if (!read)
+ (void)fdcpio(fdcu,bp->b_flags,
+ bp->b_data+fd->skip,
+ fdblk);
+ }
+#endif
if (fd_cmd(fdcu, 9,
(read ? NE7CMD_READ : NE7CMD_WRITE),
head << 2 | fdu, /* head & unit */
@@ -1943,6 +2265,24 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
return(retrier(fdcu));
}
}
+#ifdef FDC_YE
+ if (fdc->flags & FDC_PCMCIA)
+ /*
+ * if this is a read, then simply await interrupt
+ * before performing PIO
+ */
+ if (read && !fdcpio(fdcu,bp->b_flags,
+ bp->b_data+fd->skip,fdblk)) {
+ fd->tohandle = timeout(fd_iotimeout,
+ (caddr_t)fdcu, hz);
+ return(0); /* will return later */
+ };
+
+ /*
+ * write (or format) operation will fall through and
+ * await completion interrupt
+ */
+#endif
fdc->state = IOCOMPLETE;
fd->tohandle = timeout(fd_iotimeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
@@ -1976,6 +2316,16 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
fdc->state = IOCOMPLETE;
}
#endif
+#ifdef FDC_YE
+ case PIOREAD:
+ /*
+ * actually perform the PIO read. The IOCOMPLETE case
+ * removes the timeout for us.
+ */
+ (void)fdcpio(fdcu,bp->b_flags,bp->b_data+fd->skip,fdblk);
+ fdc->state = IOCOMPLETE;
+ /* FALLTHROUGH */
+#endif
case IOCOMPLETE: /* IO DONE, post-analyze */
#ifdef EPSON_NRDISK
if (fdu != nrdu)
@@ -2002,8 +2352,11 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
- format ? bp->b_bcount : fdblk, fdc->dmachan);
+#ifdef FDC_YE
+ if (!(fdc->flags & FDC_PCMCIA))
+#endif
+ isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
#ifdef EPSON_NRDISK
}
else nrd_LED_off();
OpenPOWER on IntegriCloud