Date: Wed, 30 Sep 1998 13:09:36 -0700 From: "Jordan K. Hubbard" <jkh@time.cdrom.com> To: stable@FreeBSD.ORG Subject: Request for feedback: Libretto floppy driver patches. Message-ID: <24550.907186176@time.cdrom.com>
next in thread | raw e-mail | index | archive | help
David Horwitt has been kind enough to submit some patches for supporting the Libretto's PCCARD floppy drive which seems to work fairly well for me modulo a bit of kernel message spew (which doesn't appear to effect its function). I figured it's probably a good time to get more feedback on it and see if the last bits of hair can't be shaved off. Libretto owners will want to apply the patches below to /sys/i386/isa and /etc (for the pccard.conf file) and then add: options FDC_YE to their kernel config file to enable this support. Please let me know how it works for you, and anyone wishing to port this forward to -current also won't see a fight from me. :-) Index: fd.c =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/fd.c,v retrieving revision 1.92.2.6 diff -u -u -r1.92.2.6 fd.c --- fd.c 1998/05/06 19:09:05 1.92.2.6 +++ fd.c 1998/09/30 19:59:51 @@ -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) @@ -92,6 +96,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 @@ -204,6 +212,11 @@ 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 *); @@ -245,6 +258,9 @@ #define RECALWAIT 9 #define MOTORWAIT 10 #define IOTIMEDOUT 11 +#ifdef FDC_YE +#define PIOREAD 12 +#endif #ifdef FDC_DEBUG static char const * const fdstates[] = @@ -261,6 +277,9 @@ "RECALWAIT", "MOTORWAIT", "IOTIMEDOUT" +#ifdef FDC_YE +,"PIOREAD" +#endif }; /* CAUTION: fd_debug causes huge amounts of logging output */ @@ -272,6 +291,102 @@ #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 = { @@ -507,6 +622,14 @@ { 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); } @@ -627,7 +750,7 @@ fdc->fdct = FDC_UNKNOWN; break; } - if (fdc->fdct != FDC_NE765 && + if (fdc->fdct != FDC_NE765 && fdc->fdct != FDC_UNKNOWN && enable_fifo(fdc) == 0) { printf("fdc%d: FIFO enabled", fdcu); @@ -797,6 +920,140 @@ return (1); } +#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 */ @@ -812,7 +1069,6 @@ fdout |= (FDO_MOEN0 << fdsu) + fdsu; } else fdout &= ~(FDO_MOEN0 << fdsu); - if(!turnon && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) /* gonna turn off the last drive, put FDC to bed */ @@ -1108,6 +1364,17 @@ 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) { @@ -1282,6 +1549,38 @@ ; } +#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 * @@ -1466,6 +1765,9 @@ } fd->track = b_cylinder; +#ifdef FDC_YE + if (!(fdc->flags & FDC_PCMCIA)) +#endif isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, format ? bp->b_bcount : fdblk, fdc->dmachan); sectrac = fd->ft->sectrac; @@ -1507,6 +1809,12 @@ if(format) { /* formatting */ +#ifdef FDC_YE + if (fdc->flags & FDC_PCMCIA) + (void)fdcpio(fdcu,bp->b_flags, + bp->b_un.b_addr+fd->skip, + bp->b_bcount); +#endif if(fd_cmd(fdcu, 6, NE7CMD_FORMAT, head << 2 | fdu, @@ -1523,6 +1831,23 @@ } 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_un.b_addr+fd->skip,fdblk); + }; +#endif if (fd_cmd(fdcu, 9, (read ? NE7CMD_READ : NE7CMD_WRITE), head << 2 | fdu, /* head & unit */ @@ -1540,24 +1865,52 @@ 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_un.b_addr+fd->skip,fdblk)) { + timeout(fd_timeout, (caddr_t)fdcu, hz); + return(0); /* will return later */ + }; + + /* + * write (or format) operation will fall through and + * await completion interrupt + */ +#endif fdc->state = IOCOMPLETE; timeout(fd_timeout, (caddr_t)fdcu, hz); return(0); /* will return later */ +#ifdef FDC_YE + case PIOREAD: + /* + * cancel timeout and actually perform the PIO read + */ + untimeout(fd_timeout, (caddr_t)fdcu); + (void)fdcpio(fdcu,bp->b_flags,bp->b_un.b_addr+fd->skip,fdblk); + fdc->state = IOCOMPLETE; + /* FALLTHROUGH */ +#endif case IOCOMPLETE: /* IO DONE, post-analyze */ untimeout(fd_timeout, (caddr_t)fdcu); - if (fd_read_status(fdc, fd->fdsu)) { if (fdc->retry < 6) fdc->retry = 6; /* force a reset */ return retrier(fdcu); } - fdc->state = IOTIMEDOUT; /* FALLTHROUGH */ case IOTIMEDOUT: +#ifdef FDC_YE + if (!(fdc->flags & FDC_PCMCIA)) +#endif isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, format ? bp->b_bcount : fdblk, fdc->dmachan); if (fdc->status[0] & NE7_ST0_IC) Index: fdc.h =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/fdc.h,v retrieving revision 1.6.2.1 diff -u -u -r1.6.2.1 fdc.h --- fdc.h 1997/10/05 21:00:35 1.6.2.1 +++ fdc.h 1998/09/30 19:59:51 @@ -55,6 +55,10 @@ #define FDC_TAPE_BUSY 0x04 #define FDC_STAT_VALID 0x08 #define FDC_HAS_FIFO 0x10 +#ifdef FDC_YE +#define FDC_PCMCIA 0x20 +#define FDC_UNLOADED 0x40 +#endif struct fd_data *fd; int fdu; /* the active drive */ int state; Index: isa.h =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/isa.h,v retrieving revision 1.19 diff -u -u -r1.19 isa.h --- isa.h 1996/06/14 11:01:18 1.19 +++ isa.h 1998/09/30 19:59:51 @@ -124,6 +124,7 @@ #define IO_LPT1 0x378 /* Parallel Port #1 */ /* 0x380 - 0x3AA Open */ +#define IO_YEFDC 0x3A8 /* Libretto PCMCIA floppy */ #define IO_ASC8 0x3AB /* AmiScan addr.grp. 8 */ #define IO_MDA 0x3B0 /* Monochome Adapter */ Index: pccard.conf.sample =================================================================== RCS file: /home/ncvs/src/etc/pccard.conf.sample,v retrieving revision 1.4.2.8 diff -u -u -r1.4.2.8 pccard.conf.sample --- pccard.conf.sample 1998/09/12 18:55:46 1.4.2.8 +++ pccard.conf.sample 1998/09/30 20:05:59 @@ -381,3 +381,7 @@ # config 0x3a "spc0" 11 # insert echo REX-5535 SCSI card inserted # remove echo REX-5535 SCSI card removed + +# Libretto floppy drive. +card "Y-E DATA" "External FDD" + config 0x4 "fdc0" 10 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-stable" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?24550.907186176>