Skip site navigation (1)Skip section navigation (2)
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>