Sync with sys/i386/isa/fd.c revision 1.128.
This commit is contained in:
parent
ba8d06b9f7
commit
c2a3601760
|
@ -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 */
|
||||
|
@ -1975,6 +2315,16 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
|
|||
nrdsec = sec;
|
||||
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
|
||||
|
@ -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();
|
||||
|
|
|
@ -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 */
|
||||
|
@ -1975,6 +2315,16 @@ fdstate(fdcu_t fdcu, fdc_p fdc)
|
|||
nrdsec = sec;
|
||||
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
|
||||
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue