1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

Make the Y-E Data PCMCIA floppy of the Toshiba Libretto work under

-current.  It doesn't work yet as stable as the 3.x/PAO version of the
driver does, however, i get occasional `FDC direction bit not set' and
other weird messages, but it basically works at least.

The old (defunct) #ifdef FDC_YE stuff has been eliminated completely
now, PCMCIA-FDC specific functions have been implemented differently
where needed.

Unfortunately, due to the fact that the traditional PeeCee FDC with
its funny non-contiguous register space (one register for WD1003
harddisk controllers is interleaved into the FDC register set), and
Peter's subsequent changes involving two different bus space handles
for normal FDCs, the changes required for the Y-E stuff are more
complex than i'd love them to be.  I've done my best to keep the logic
for normal FDCs intact.

Since the Y-E FDC seems to lose interrupts after a FDC reset
sometimes, i've also replaced the timeout logic in fd_turnoff() to
generate an artificial pseudo interrupt in case of a timeout while the
drive has still outstanding transfers waiting.  This avoids the total
starvation of the driver that could be observed with highly damaged
media under 3.x/PAO.  This part of the patch has been revied by bde
previously.

I've fixed a number of occasions where previous commits have been
missing the encapuslation of ISA DMA related functions inside
FDC_NODMA checks.

I've added one call to SET_BCDR() during preparation of the format
floppy operation.  Floppy formatting has been totally broken before in
3.x/PAO (garbage ID fields have been written to the medium, causing
`wrong cylinder' errors upon media reading).  This is just black
magic, i don't have the slightes idea _why_ this needs to be but just
copied over the hack that has been used by the PAO folks in the normal
read/write case anyway.

The entired device_busy() stuff seems to be pointless to me.  In any
case, i had to add device_unbusy() calls symmetrical to the
device_busy() calls, otherwise the PCMCIA floppy driver could never be
deactivated.  (As it used to be, it caused a `mark the device busier
and busier' situation.)  IMHO, all block device drivers should be
marked busy based on active buffers still waiting for the driver, so
the device_unbusy() calls should probably go to biodone().  Only one
other driver (whose name escapes me at the moment) uses device_busy()
calls at all, so i question the value of all this...

I think this entire `device busy' logic simply doesn't fit for PCMCIA
&al.  It cannot be the decision of some piece of kernel software to
declare a device `busy by now, you can't remove it', when the actual
physical power of removing it is the user pulling the card.  The
kernel simply has to cope with the removal, however busy the device
might have been by the time of the removal, period.  Perhaps a force
flag needs to be added?

Upon inserting the card a second time, i get:

WARNING: "fd" is usurping "fd"'s cdevsw[]
WARNING: "fd" is usurping "fd"'s bmaj

I suspect this is related to the XXX comment at the call to
cdevsw_add().  Does anybody know what the correct way is to cleanup
this?
This commit is contained in:
Joerg Wunsch 2000-03-18 18:27:01 +00:00
parent f21cd30bc4
commit 5f830ea2cd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=58240
3 changed files with 491 additions and 491 deletions

View File

@ -52,6 +52,7 @@
*/
#include "opt_fdc.h"
#include "card.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -286,11 +287,17 @@ fddata_rd(fdc_p fdc)
}
static void
fdctl_wr(fdc_p fdc, u_int8_t v)
fdctl_wr_isa(fdc_p fdc, u_int8_t v)
{
bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
}
static void
fdctl_wr_pcmcia(fdc_p fdc, u_int8_t v)
{
bus_space_write_1(fdc->portt, fdc->porth, FDCTL+fdc->port_off, v);
}
#if 0
static u_int8_t
@ -301,82 +308,6 @@ fdin_rd(fdc_p fdc)
#endif
#ifdef FDC_YE
#if NCARD > 0
#include <sys/select.h>
#include <sys/module.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 */
PCCARD_MODULE(fdc, yeinit, yeunload, yeintr, 0, bio_imask);
/*
* Initialize the device - called from Slot manager.
*/
static int yeinit(struct pccard_devinfo *devi)
{
fdc_p fdc = &fdc_data[devi->isahd.id_unit];
fdc->baseport = devi->isahd.id_iobase;
/*
* reset controller
*/
fdout_wr(fdc, 0);
DELAY(100);
fdout_wr(fdc, 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 */
static d_open_t Fdopen; /* NOTE, not fdopen */
static d_close_t fdclose;
static d_ioctl_t fdioctl;
@ -586,21 +517,29 @@ static int
fdc_alloc_resources(struct fdc_data *fdc)
{
device_t dev;
int ispnp;
int ispnp, ispcmcia;
dev = fdc->fdc_dev;
ispnp = fdc->fdc_ispnp;
ispnp = (fdc->flags & FDC_ISPNP) != 0;
ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
/*
* We don't just use an 8 port range (e.g. 0x3f0-0x3f7) since that
* covers an IDE control register at 0x3f6.
* On standard ISA, we don't just use an 8 port range
* (e.g. 0x3f0-0x3f7) since that covers an IDE control
* register at 0x3f6.
*
* Isn't PC hardware wonderful.
*
* The Y-E Data PCMCIA FDC doesn't have this problem, it
* uses the register with offset 6 for pseudo-DMA, and the
* one with offset 7 as control register.
*/
fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, 0ul, ~0ul,
ispnp ? 1 : 6, RF_ACTIVE);
ispcmcia ? 8 : (ispnp ? 1 : 6),
RF_ACTIVE);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range\n");
return ENXIO;
@ -608,47 +547,55 @@ fdc_alloc_resources(struct fdc_data *fdc)
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
/*
* Some BIOSen report the device at 0x3f2-0x3f5,0x3f7 and some at
* 0x3f0-0x3f5,0x3f7. We detect the former by checking the size
* and adjust the port address accordingly.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
fdc->port_off = -2;
if (!ispcmcia) {
/*
* Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
* and some at 0x3f0-0x3f5,0x3f7. We detect the former
* by checking the size and adjust the port address
* accordingly.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
fdc->port_off = -2;
/*
* Register the control port range as rid 1 if it isn't there
* already. Most PnP BIOSen will have already done this but
* non-PnP configurations don't.
*
* And some (!!) report 0x3f2-0x3f5 and completely leave out the
* control register! It seems that some non-antique controller chips
* have a different method of programming the transfer speed which
* doesn't require the control register, but it's mighty bogus as the
* chip still responds to the address for the control register.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
u_long ctlstart;
/*
* Register the control port range as rid 1 if it
* isn't there already. Most PnP BIOSen will have
* already done this but non-PnP configurations don't.
*
* And some (!!) report 0x3f2-0x3f5 and completely
* leave out the control register! It seems that some
* non-antique controller chips have a different
* method of programming the transfer speed which
* doesn't require the control register, but it's
* mighty bogus as the chip still responds to the
* address for the control register.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
u_long ctlstart;
/* Find the control port, usually 0x3f7 */
ctlstart = rman_get_start(fdc->res_ioport) + fdc->port_off + 7;
/* Find the control port, usually 0x3f7 */
ctlstart = rman_get_start(fdc->res_ioport) +
fdc->port_off + 7;
bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
}
/*
* Now (finally!) allocate the control port.
*/
fdc->rid_ctl = 1;
fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT,
&fdc->rid_ctl,
0ul, ~0ul, 1, RF_ACTIVE);
if (fdc->res_ctl == 0) {
device_printf(dev,
"cannot reserve control I/O port range\n");
return ENXIO;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
}
/*
* Now (finally!) allocate the control port.
*/
fdc->rid_ctl = 1;
fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ctl,
0ul, ~0ul, 1, RF_ACTIVE);
if (fdc->res_ctl == 0) {
device_printf(dev, "cannot reserve control I/O port range\n");
return ENXIO;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
fdc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
&fdc->rid_irq, 0ul, ~0ul, 1,
RF_ACTIVE);
@ -656,14 +603,17 @@ fdc_alloc_resources(struct fdc_data *fdc)
device_printf(dev, "cannot reserve interrupt line\n");
return ENXIO;
}
fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
&fdc->rid_drq, 0ul, ~0ul, 1,
RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
if ((fdc->flags & FDC_NODMA) == 0) {
fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
&fdc->rid_drq, 0ul, ~0ul, 1,
RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
}
fdc->dmachan = fdc->res_drq->r_start;
}
fdc->dmachan = fdc->res_drq->r_start;
return 0;
}
@ -737,12 +687,14 @@ fdc_probe(device_t dev)
fdc = device_get_softc(dev);
bzero(fdc, sizeof *fdc);
fdc->fdc_dev = dev;
fdc->fdctl_wr = fdctl_wr_isa;
/* Check pnp ids */
error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
if (error == ENXIO)
return ENXIO;
fdc->fdc_ispnp = (error == 0);
if (error == 0)
fdc->flags |= FDC_ISPNP;
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_alloc_resources(fdc);
@ -788,6 +740,73 @@ fdc_probe(device_t dev)
return (error);
}
#if NCARD > 0
static int
fdc_pccard_probe(device_t dev)
{
int error;
struct fdc_data *fdc;
fdc = device_get_softc(dev);
bzero(fdc, sizeof *fdc);
fdc->fdc_dev = dev;
fdc->fdctl_wr = fdctl_wr_pcmcia;
fdc->flags |= FDC_ISPCMCIA | FDC_NODMA;
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_alloc_resources(fdc);
if (error)
goto out;
/* First - lets reset the floppy controller */
fdout_wr(fdc, 0);
DELAY(100);
fdout_wr(fdc, FDO_FRST);
/* see if it can handle a command */
if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
NE7_SPEC_2(2, 0), 0)) {
error = ENXIO;
goto out;
}
device_set_desc(dev, "Y-E Data PCMCIA floppy");
fdc->fdct = FDC_NE765;
out:
fdc_release_resources(fdc);
return (error);
}
static int
fdc_pccard_detach(device_t dev)
{
struct fdc_data *fdc;
int error;
fdc = device_get_softc(dev);
/* have our children detached first */
if ((error = bus_generic_detach(dev)))
return (error);
if ((fdc->flags & FDC_ATTACHED) == 0) {
device_printf(dev, "already unloaded\n");
return (0);
}
fdc->flags &= ~FDC_ATTACHED;
BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq,
fdc->fdc_intr);
fdc_release_resources(fdc);
device_printf(dev, "unload\n");
return (0);
}
#endif /* NCARD > 0 */
/*
* Add a child device to the fdc controller. It will then be probed etc.
*/
@ -834,10 +853,12 @@ fdc_attach(device_t dev)
fdc->fdcu = device_get_unit(dev);
fdc->flags |= FDC_ATTACHED;
/* Acquire the DMA channel forever, The driver will do the rest */
if ((fdc->flags & FDC_NODMA) == 0) {
/* Acquire the DMA channel forever, The driver will do the rest */
/* XXX should integrate with rman */
isa_dma_acquire(fdc->dmachan);
isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
isa_dma_acquire(fdc->dmachan);
isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
}
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
@ -894,6 +915,35 @@ static driver_t fdc_driver = {
DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);
#if NCARD > 0
static device_method_t fdc_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_pccard_probe),
DEVMETHOD(device_attach, fdc_attach),
DEVMETHOD(device_detach, fdc_pccard_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
DEVMETHOD(bus_print_child, fdc_print_child),
DEVMETHOD(bus_read_ivar, fdc_read_ivar),
/* Our children never use any other bus interface methods. */
{ 0, 0 }
};
static driver_t fdc_pccard_driver = {
"fdc",
fdc_pccard_methods,
sizeof(struct fdc_data)
};
DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
#endif /* NCARD > 0 */
/******************************************************************/
/*
* devices attached to the controller section.
@ -922,7 +972,9 @@ fd_probe(device_t dev)
/* look up what bios thinks we have */
switch (fd->fdu) {
case 0:
if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
if ((fdc->flags & FDC_ISPCMCIA))
fdt = RTCFDT_144M;
else if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
else
fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
@ -1069,11 +1121,22 @@ fd_attach(device_t dev)
return (0);
}
static int
fd_detach(device_t dev)
{
struct fd_data *fd;
fd = device_get_softc(dev);
untimeout(fd_turnoff, fd, fd->toffhandle);
return (0);
}
static device_method_t fd_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fd_probe),
DEVMETHOD(device_attach, fd_attach),
DEVMETHOD(device_detach, bus_generic_detach),
DEVMETHOD(device_detach, fd_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX */
DEVMETHOD(device_resume, bus_generic_resume), /* XXX */
@ -1089,100 +1152,6 @@ static driver_t fd_driver = {
DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
/******************************************************************/
#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;
fdc->fdcu = fdcu;
/*
* the FDC_NODMA flag is used to to indicate special PIO is used
* instead of DMA
*/
fdc->flags = FDC_ATTACHED|FDC_NODMA;
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
fdout_wr(fdc, ((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;
return (1);
}
#endif
/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
@ -1237,17 +1206,21 @@ fd_turnoff(void *xfd)
TRACE1("[fd%d: turnoff]", fd->fdu);
s = splbio();
/*
* Don't turn off the motor yet if the drive is active.
* XXX shouldn't even schedule turnoff until drive is inactive
* and nothing is queued on it.
*
* If we got here, this could only mean we missed an interrupt.
* This can e. g. happen on the Y-E Date PCMCIA floppy controller
* after a controller reset. Just schedule a pseudo-interrupt
* so the state machine gets re-entered.
*/
if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
fdc_intr(fd->fdc);
splx(s);
return;
}
s = splbio();
fd->flags &= ~FD_MOTOR;
set_motor(fd->fdc, fd->fdsu, TURNOFF);
splx(s);
@ -1453,8 +1426,7 @@ Fdopen(dev_t dev, int flags, int mode, struct proc *p)
}
fd->ft = fd_types + type - 1;
fd->flags |= FD_OPEN;
device_busy(fd->dev);
device_busy(fd->fdc->fdc_dev);
return 0;
}
@ -1547,6 +1519,7 @@ fdstrategy(struct buf *bp)
/* Tell devstat we are starting on the transaction */
devstat_start_transaction(&fd->device_stats);
device_busy(fd->dev);
fdstart(fdc);
splx(s);
@ -1731,7 +1704,7 @@ fdstate(fdc_p fdc)
fd->skip = 0;
fdc->fd = fd;
fdc->fdu = fdu;
fdctl_wr(fdc, fd->ft->trans);
fdc->fdctl_wr(fdc, fd->ft->trans);
TRACE1("[0x%x->FDCTL]", fd->ft->trans);
/*******************************************************\
* If the next drive has a motor startup pending, then *
@ -1867,9 +1840,11 @@ fdstate(fdc_p fdc)
if(fd_sense_drive_status(fdc, &st3) != 0)
{
/* stuck controller? */
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags,
bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
fdc->retry = 6; /* reset the beast */
return (retrier(fdc));
}
@ -1895,10 +1870,26 @@ fdstate(fdc_p fdc)
}
if (format) {
if (fdc->flags & FDC_NODMA)
if (fdc->flags & FDC_NODMA) {
/*
* This seems to be necessary for
* whatever obscure reason; if we omit
* it, we end up filling the sector ID
* fields of the newly formatted track
* entirely with garbage, causing
* `wrong cylinder' errors all over
* the place when trying to read them
* back.
*
* Umpf.
*/
SET_BCDR(fdc, 1, bp->b_bcount, 0);
(void)fdcpio(fdc,bp->b_flags,
bp->b_data+fd->skip,
bp->b_bcount);
}
/* formatting */
if(fd_cmd(fdc, 6, NE7CMD_FORMAT, head << 2 | fdu,
finfo->fd_formb_secshift,
@ -1906,9 +1897,11 @@ fdstate(fdc_p fdc)
finfo->fd_formb_gaplen,
finfo->fd_formb_fillbyte, 0)) {
/* controller fell over */
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags,
bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
fdc->retry = 6;
return (retrier(fdc));
}
@ -1941,9 +1934,11 @@ fdstate(fdc_p fdc)
fd->ft->datalen, /* data length */
0)) {
/* the beast is sleeping again */
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags,
bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
fdc->retry = 6;
return (retrier(fdc));
}
@ -1978,9 +1973,10 @@ fdstate(fdc_p fdc)
untimeout(fd_iotimeout, fdc, fd->tohandle);
if (fd_read_status(fdc, fd->fdsu)) {
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (fdc->retry < 6)
fdc->retry = 6; /* force a reset */
return (retrier(fdc));
@ -2025,6 +2021,7 @@ fdstate(fdc_p fdc)
/* ALL DONE */
fd->skip = 0;
fdc->bp = NULL;
device_unbusy(fd->dev);
devstat_end_transaction_buf(&fd->device_stats, bp);
biodone(bp);
fdc->fd = (fd_p) 0;
@ -2189,6 +2186,7 @@ retrier(struct fdc_data *fdc)
bp->b_resid += bp->b_bcount - fdc->fd->skip;
fdc->bp = NULL;
fdc->fd->skip = 0;
device_unbusy(fd->dev);
devstat_end_transaction_buf(&fdc->fd->device_stats, bp);
biodone(bp);
fdc->state = FINDWORK;
@ -2257,6 +2255,7 @@ fdformat(dev, finfo, p)
if (rv == EWOULDBLOCK) {
/* timed out */
rv = EIO;
device_unbusy(fd->dev);
biodone(bp);
}
if (bp->b_flags & B_ERROR)

View File

@ -52,6 +52,7 @@
*/
#include "opt_fdc.h"
#include "card.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -286,11 +287,17 @@ fddata_rd(fdc_p fdc)
}
static void
fdctl_wr(fdc_p fdc, u_int8_t v)
fdctl_wr_isa(fdc_p fdc, u_int8_t v)
{
bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
}
static void
fdctl_wr_pcmcia(fdc_p fdc, u_int8_t v)
{
bus_space_write_1(fdc->portt, fdc->porth, FDCTL+fdc->port_off, v);
}
#if 0
static u_int8_t
@ -301,82 +308,6 @@ fdin_rd(fdc_p fdc)
#endif
#ifdef FDC_YE
#if NCARD > 0
#include <sys/select.h>
#include <sys/module.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 */
PCCARD_MODULE(fdc, yeinit, yeunload, yeintr, 0, bio_imask);
/*
* Initialize the device - called from Slot manager.
*/
static int yeinit(struct pccard_devinfo *devi)
{
fdc_p fdc = &fdc_data[devi->isahd.id_unit];
fdc->baseport = devi->isahd.id_iobase;
/*
* reset controller
*/
fdout_wr(fdc, 0);
DELAY(100);
fdout_wr(fdc, 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 */
static d_open_t Fdopen; /* NOTE, not fdopen */
static d_close_t fdclose;
static d_ioctl_t fdioctl;
@ -586,21 +517,29 @@ static int
fdc_alloc_resources(struct fdc_data *fdc)
{
device_t dev;
int ispnp;
int ispnp, ispcmcia;
dev = fdc->fdc_dev;
ispnp = fdc->fdc_ispnp;
ispnp = (fdc->flags & FDC_ISPNP) != 0;
ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
/*
* We don't just use an 8 port range (e.g. 0x3f0-0x3f7) since that
* covers an IDE control register at 0x3f6.
* On standard ISA, we don't just use an 8 port range
* (e.g. 0x3f0-0x3f7) since that covers an IDE control
* register at 0x3f6.
*
* Isn't PC hardware wonderful.
*
* The Y-E Data PCMCIA FDC doesn't have this problem, it
* uses the register with offset 6 for pseudo-DMA, and the
* one with offset 7 as control register.
*/
fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, 0ul, ~0ul,
ispnp ? 1 : 6, RF_ACTIVE);
ispcmcia ? 8 : (ispnp ? 1 : 6),
RF_ACTIVE);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range\n");
return ENXIO;
@ -608,47 +547,55 @@ fdc_alloc_resources(struct fdc_data *fdc)
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
/*
* Some BIOSen report the device at 0x3f2-0x3f5,0x3f7 and some at
* 0x3f0-0x3f5,0x3f7. We detect the former by checking the size
* and adjust the port address accordingly.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
fdc->port_off = -2;
if (!ispcmcia) {
/*
* Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
* and some at 0x3f0-0x3f5,0x3f7. We detect the former
* by checking the size and adjust the port address
* accordingly.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
fdc->port_off = -2;
/*
* Register the control port range as rid 1 if it isn't there
* already. Most PnP BIOSen will have already done this but
* non-PnP configurations don't.
*
* And some (!!) report 0x3f2-0x3f5 and completely leave out the
* control register! It seems that some non-antique controller chips
* have a different method of programming the transfer speed which
* doesn't require the control register, but it's mighty bogus as the
* chip still responds to the address for the control register.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
u_long ctlstart;
/*
* Register the control port range as rid 1 if it
* isn't there already. Most PnP BIOSen will have
* already done this but non-PnP configurations don't.
*
* And some (!!) report 0x3f2-0x3f5 and completely
* leave out the control register! It seems that some
* non-antique controller chips have a different
* method of programming the transfer speed which
* doesn't require the control register, but it's
* mighty bogus as the chip still responds to the
* address for the control register.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
u_long ctlstart;
/* Find the control port, usually 0x3f7 */
ctlstart = rman_get_start(fdc->res_ioport) + fdc->port_off + 7;
/* Find the control port, usually 0x3f7 */
ctlstart = rman_get_start(fdc->res_ioport) +
fdc->port_off + 7;
bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
}
/*
* Now (finally!) allocate the control port.
*/
fdc->rid_ctl = 1;
fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT,
&fdc->rid_ctl,
0ul, ~0ul, 1, RF_ACTIVE);
if (fdc->res_ctl == 0) {
device_printf(dev,
"cannot reserve control I/O port range\n");
return ENXIO;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
}
/*
* Now (finally!) allocate the control port.
*/
fdc->rid_ctl = 1;
fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ctl,
0ul, ~0ul, 1, RF_ACTIVE);
if (fdc->res_ctl == 0) {
device_printf(dev, "cannot reserve control I/O port range\n");
return ENXIO;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
fdc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
&fdc->rid_irq, 0ul, ~0ul, 1,
RF_ACTIVE);
@ -656,14 +603,17 @@ fdc_alloc_resources(struct fdc_data *fdc)
device_printf(dev, "cannot reserve interrupt line\n");
return ENXIO;
}
fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
&fdc->rid_drq, 0ul, ~0ul, 1,
RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
if ((fdc->flags & FDC_NODMA) == 0) {
fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
&fdc->rid_drq, 0ul, ~0ul, 1,
RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
}
fdc->dmachan = fdc->res_drq->r_start;
}
fdc->dmachan = fdc->res_drq->r_start;
return 0;
}
@ -737,12 +687,14 @@ fdc_probe(device_t dev)
fdc = device_get_softc(dev);
bzero(fdc, sizeof *fdc);
fdc->fdc_dev = dev;
fdc->fdctl_wr = fdctl_wr_isa;
/* Check pnp ids */
error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
if (error == ENXIO)
return ENXIO;
fdc->fdc_ispnp = (error == 0);
if (error == 0)
fdc->flags |= FDC_ISPNP;
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_alloc_resources(fdc);
@ -788,6 +740,73 @@ fdc_probe(device_t dev)
return (error);
}
#if NCARD > 0
static int
fdc_pccard_probe(device_t dev)
{
int error;
struct fdc_data *fdc;
fdc = device_get_softc(dev);
bzero(fdc, sizeof *fdc);
fdc->fdc_dev = dev;
fdc->fdctl_wr = fdctl_wr_pcmcia;
fdc->flags |= FDC_ISPCMCIA | FDC_NODMA;
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_alloc_resources(fdc);
if (error)
goto out;
/* First - lets reset the floppy controller */
fdout_wr(fdc, 0);
DELAY(100);
fdout_wr(fdc, FDO_FRST);
/* see if it can handle a command */
if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
NE7_SPEC_2(2, 0), 0)) {
error = ENXIO;
goto out;
}
device_set_desc(dev, "Y-E Data PCMCIA floppy");
fdc->fdct = FDC_NE765;
out:
fdc_release_resources(fdc);
return (error);
}
static int
fdc_pccard_detach(device_t dev)
{
struct fdc_data *fdc;
int error;
fdc = device_get_softc(dev);
/* have our children detached first */
if ((error = bus_generic_detach(dev)))
return (error);
if ((fdc->flags & FDC_ATTACHED) == 0) {
device_printf(dev, "already unloaded\n");
return (0);
}
fdc->flags &= ~FDC_ATTACHED;
BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq,
fdc->fdc_intr);
fdc_release_resources(fdc);
device_printf(dev, "unload\n");
return (0);
}
#endif /* NCARD > 0 */
/*
* Add a child device to the fdc controller. It will then be probed etc.
*/
@ -834,10 +853,12 @@ fdc_attach(device_t dev)
fdc->fdcu = device_get_unit(dev);
fdc->flags |= FDC_ATTACHED;
/* Acquire the DMA channel forever, The driver will do the rest */
if ((fdc->flags & FDC_NODMA) == 0) {
/* Acquire the DMA channel forever, The driver will do the rest */
/* XXX should integrate with rman */
isa_dma_acquire(fdc->dmachan);
isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
isa_dma_acquire(fdc->dmachan);
isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
}
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
@ -894,6 +915,35 @@ static driver_t fdc_driver = {
DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);
#if NCARD > 0
static device_method_t fdc_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_pccard_probe),
DEVMETHOD(device_attach, fdc_attach),
DEVMETHOD(device_detach, fdc_pccard_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
DEVMETHOD(bus_print_child, fdc_print_child),
DEVMETHOD(bus_read_ivar, fdc_read_ivar),
/* Our children never use any other bus interface methods. */
{ 0, 0 }
};
static driver_t fdc_pccard_driver = {
"fdc",
fdc_pccard_methods,
sizeof(struct fdc_data)
};
DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
#endif /* NCARD > 0 */
/******************************************************************/
/*
* devices attached to the controller section.
@ -922,7 +972,9 @@ fd_probe(device_t dev)
/* look up what bios thinks we have */
switch (fd->fdu) {
case 0:
if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
if ((fdc->flags & FDC_ISPCMCIA))
fdt = RTCFDT_144M;
else if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
else
fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
@ -1069,11 +1121,22 @@ fd_attach(device_t dev)
return (0);
}
static int
fd_detach(device_t dev)
{
struct fd_data *fd;
fd = device_get_softc(dev);
untimeout(fd_turnoff, fd, fd->toffhandle);
return (0);
}
static device_method_t fd_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fd_probe),
DEVMETHOD(device_attach, fd_attach),
DEVMETHOD(device_detach, bus_generic_detach),
DEVMETHOD(device_detach, fd_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX */
DEVMETHOD(device_resume, bus_generic_resume), /* XXX */
@ -1089,100 +1152,6 @@ static driver_t fd_driver = {
DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
/******************************************************************/
#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;
fdc->fdcu = fdcu;
/*
* the FDC_NODMA flag is used to to indicate special PIO is used
* instead of DMA
*/
fdc->flags = FDC_ATTACHED|FDC_NODMA;
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
fdout_wr(fdc, ((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;
return (1);
}
#endif
/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
@ -1237,17 +1206,21 @@ fd_turnoff(void *xfd)
TRACE1("[fd%d: turnoff]", fd->fdu);
s = splbio();
/*
* Don't turn off the motor yet if the drive is active.
* XXX shouldn't even schedule turnoff until drive is inactive
* and nothing is queued on it.
*
* If we got here, this could only mean we missed an interrupt.
* This can e. g. happen on the Y-E Date PCMCIA floppy controller
* after a controller reset. Just schedule a pseudo-interrupt
* so the state machine gets re-entered.
*/
if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
fdc_intr(fd->fdc);
splx(s);
return;
}
s = splbio();
fd->flags &= ~FD_MOTOR;
set_motor(fd->fdc, fd->fdsu, TURNOFF);
splx(s);
@ -1453,8 +1426,7 @@ Fdopen(dev_t dev, int flags, int mode, struct proc *p)
}
fd->ft = fd_types + type - 1;
fd->flags |= FD_OPEN;
device_busy(fd->dev);
device_busy(fd->fdc->fdc_dev);
return 0;
}
@ -1547,6 +1519,7 @@ fdstrategy(struct buf *bp)
/* Tell devstat we are starting on the transaction */
devstat_start_transaction(&fd->device_stats);
device_busy(fd->dev);
fdstart(fdc);
splx(s);
@ -1731,7 +1704,7 @@ fdstate(fdc_p fdc)
fd->skip = 0;
fdc->fd = fd;
fdc->fdu = fdu;
fdctl_wr(fdc, fd->ft->trans);
fdc->fdctl_wr(fdc, fd->ft->trans);
TRACE1("[0x%x->FDCTL]", fd->ft->trans);
/*******************************************************\
* If the next drive has a motor startup pending, then *
@ -1867,9 +1840,11 @@ fdstate(fdc_p fdc)
if(fd_sense_drive_status(fdc, &st3) != 0)
{
/* stuck controller? */
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags,
bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
fdc->retry = 6; /* reset the beast */
return (retrier(fdc));
}
@ -1895,10 +1870,26 @@ fdstate(fdc_p fdc)
}
if (format) {
if (fdc->flags & FDC_NODMA)
if (fdc->flags & FDC_NODMA) {
/*
* This seems to be necessary for
* whatever obscure reason; if we omit
* it, we end up filling the sector ID
* fields of the newly formatted track
* entirely with garbage, causing
* `wrong cylinder' errors all over
* the place when trying to read them
* back.
*
* Umpf.
*/
SET_BCDR(fdc, 1, bp->b_bcount, 0);
(void)fdcpio(fdc,bp->b_flags,
bp->b_data+fd->skip,
bp->b_bcount);
}
/* formatting */
if(fd_cmd(fdc, 6, NE7CMD_FORMAT, head << 2 | fdu,
finfo->fd_formb_secshift,
@ -1906,9 +1897,11 @@ fdstate(fdc_p fdc)
finfo->fd_formb_gaplen,
finfo->fd_formb_fillbyte, 0)) {
/* controller fell over */
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags,
bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
fdc->retry = 6;
return (retrier(fdc));
}
@ -1941,9 +1934,11 @@ fdstate(fdc_p fdc)
fd->ft->datalen, /* data length */
0)) {
/* the beast is sleeping again */
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags,
bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
fdc->retry = 6;
return (retrier(fdc));
}
@ -1978,9 +1973,10 @@ fdstate(fdc_p fdc)
untimeout(fd_iotimeout, fdc, fd->tohandle);
if (fd_read_status(fdc, fd->fdsu)) {
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (!(fdc->flags & FDC_NODMA))
isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
format ? bp->b_bcount : fdblk,
fdc->dmachan);
if (fdc->retry < 6)
fdc->retry = 6; /* force a reset */
return (retrier(fdc));
@ -2025,6 +2021,7 @@ fdstate(fdc_p fdc)
/* ALL DONE */
fd->skip = 0;
fdc->bp = NULL;
device_unbusy(fd->dev);
devstat_end_transaction_buf(&fd->device_stats, bp);
biodone(bp);
fdc->fd = (fd_p) 0;
@ -2189,6 +2186,7 @@ retrier(struct fdc_data *fdc)
bp->b_resid += bp->b_bcount - fdc->fd->skip;
fdc->bp = NULL;
fdc->fd->skip = 0;
device_unbusy(fd->dev);
devstat_end_transaction_buf(&fdc->fd->device_stats, bp);
biodone(bp);
fdc->state = FINDWORK;
@ -2257,6 +2255,7 @@ fdformat(dev, finfo, p)
if (rv == EWOULDBLOCK) {
/* timed out */
rv = EIO;
device_unbusy(fd->dev);
biodone(bp);
}
if (bp->b_flags & B_ERROR)

View File

@ -54,6 +54,8 @@ struct fdc_data
#define FDC_HAS_FIFO 0x10
#define FDC_NEEDS_RESET 0x20
#define FDC_NODMA 0x40
#define FDC_ISPNP 0x80
#define FDC_ISPCMCIA 0x100
struct fd_data *fd;
int fdu; /* the active drive */
int state;
@ -73,7 +75,7 @@ struct fdc_data
bus_space_handle_t ctlh;
void *fdc_intr;
struct device *fdc_dev;
int fdc_ispnp;
void (*fdctl_wr)(struct fdc_data *fdc, u_int8_t v);
};
/***********************************************************************\