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:
parent
f21cd30bc4
commit
5f830ea2cd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=58240
@ -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)
|
||||
|
489
sys/isa/fd.c
489
sys/isa/fd.c
@ -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)
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
/***********************************************************************\
|
||||
|
Loading…
Reference in New Issue
Block a user