Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Aug 1999 20:35:26 +0900 (JST)
From:      hosokawa@itc.keio.ac.jp (HOSOKAWA Tatsumi)
To:        mobile@freebsd.org
Cc:        hosokawa@itc.keio.ac.jp
Subject:   PC-card ATA patch (single I/O window) for -current
Message-ID:  <199908131135.UAA00766@afs.ntc.mita.keio.ac.jp>

next in thread | raw e-mail | index | archive | help
Hi.

It's PC-card ATA patch for -current.  It still has a few lines I want
to rewrite, but I think it works with many ATA cards.  It uses single
I/O window, so it works on laptop machines with internal CD-ROM.

Please add

	controller	wdc2	at isa? 
	disk		wd4	at wdc1 drive 0
	disk		wd5	at wdc1 drive 1

to kernel config file and compile it.

I'm developping this patch with Hagiwara Sys-com's Compact flash.
"config" line of pccard.conf is

	config 0x01 "wdc2" ? iosize 16

Index: wd.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/isa/wd.c,v
retrieving revision 1.200
diff -u -r1.200 wd.c
--- wd.c	1999/08/09 10:34:52	1.200
+++ wd.c	1999/08/13 11:24:43
@@ -68,6 +68,8 @@
 #include "opt_hw_wdog.h"
 #include "opt_ide_delay.h"
 
+#include "card.h"		/* PC-card Flash/Type3 ATA support */
+
 #include <sys/param.h>
 #include <sys/dkbad.h>
 #include <sys/systm.h>
@@ -93,6 +95,7 @@
 #include <vm/vm.h>
 #include <vm/vm_prot.h>
 #include <vm/pmap.h>
+#include <sys/select.h>
 
 #include <i386/isa/atapi.h>
 
@@ -112,6 +115,9 @@
 #define WDOPT_SLEEPHACK	0x4000
 #define WDOPT_DMA	0x2000
 #define WDOPT_LBA	0x1000
+/* following two options are used for PC-card IDE/ATAPI devices */
+#define	WDOPT_BROKEN_SIGNATURE	0x10000
+
 #define WDOPT_FORCEHD(x)	(((x)&0x0f00)>>8)
 #define WDOPT_MULTIMASK	0x00ff
 
@@ -180,6 +186,9 @@
 	struct diskgeom dk_dd;	/* device configuration data */
 	struct diskslices *dk_slices;	/* virtual drives */
 	void	*dk_dmacookie;	/* handle for DMA services */
+	int	dk_altsts;
+	int	dk_ctlr;
+	int	dk_digin;
 
 	struct devstat dk_stats;	/* devstat entry */
 };
@@ -272,7 +281,124 @@
 static int      eide_quirks;
 
 
+#if	NCARD > 0
+#include <sys/module.h>
+#include <pccard/cardinfo.h>
+#include <pccard/driver.h>
+#include <pccard/slot.h>
+/*
+ *	PC-Card (PCMCIA) specific code.
+ */
+static int card_intr(struct pccard_devinfo *);	/* Interrupt handler */
+static void wdunload(struct pccard_devinfo *);	/* Disable driver */
+static int wdinit(struct pccard_devinfo *);	/* Init. driver */
+static int wdprobe_pccard(struct isa_device *);	/* Probe PC-card */
+
+PCCARD_MODULE(wdc,wdinit,wdunload,card_intr,0,bio_imask);
+
+static int static_init = 1;
+static int lunit_in_use = 0;
+static int ctrlr_in_use = 0;
+
+/*
+ * Initialize the device - called from Slot manager.
+ * if first is set, then initially check for
+ * the device's existence before initialising it.
+ * Once initialised, the device table may be set up.
+ */
+static int
+wdinit(struct pccard_devinfo *devi)
+{
+/*
+ *	dynamic configuration mode
+ */
+	static_init = 0;
+/*
+ *	validate unit number.
+ */
+	if (devi->isahd.id_unit >= NWDC)
+		return(ENODEV);
+/*
+ *	Probe the device. If a value is returned, the
+ *	device was found at the location.
+ */
+	if (wdprobe_pccard(&devi->isahd)==0) {
+		printf("Probe Failed\n");
+		return(ENXIO);
+	}
+	if (wdattach(&devi->isahd)==0) {
+		printf("Attach Failed\n");
+		return(ENXIO);
+	}
+/*
+ *	XXX TODO:
+ *	If it was already inited before, the device structure
+ *	should be already initialised. Here we should
+ *	reset (and possibly restart) the hardware, but
+ *	I am not sure of the best way to do this...
+ */
+	return(0);
+}
+
+/*
+ *	wdunload - unload the driver and clear the table.
+ *	XXX TODO:
+ *	This is called usually when the card is ejected, but
+ *	can be caused by the modunload of a controller driver.
+ *	The idea is 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
+wdunload(struct pccard_devinfo *devi)
+{
+	int ctrlr = devi->isahd.id_unit;
+	int lunit;
+
+	for (lunit=0; lunit<NWD; lunit++) {
+	  if ((lunit_in_use & (1<<lunit)) && wddrives[lunit] &&
+	      wddrives[lunit]->dk_ctrlr == ctrlr &&
+	      wddrives[lunit]->dk_port  == devi->isahd.id_iobase ) {
+	    lunit_in_use &= ~(1<<lunit);
+	    break;
+	  }
+	}
+	ctrlr_in_use &= ~(1<<ctrlr);
+	/* should unload atapi unit */
+#ifdef ATAPI_DETACH
+	for (lunit=0; lunit<2; lunit++)
+		atapi_detach (ctrlr, lunit, devi->isahd.id_iobase);
+#endif
+
+	printf("wdc%d: unloading -- ", ctrlr);
+	if (wdtab[ctrlr].b_active != 0)
+		printf("damage!\n");
+	else
+		printf("done\n");
+}
+
 /*
+ *    card_intr - Shared interrupt called from
+ *    front end of PC-Card handler.
+ */
+static int
+card_intr(struct pccard_devinfo *devi)
+{
+	wdintr((void *)(devi->isahd.id_unit));
+	return(1);
+}
+
+static int
+wdprobe_pccard(struct isa_device *isa_dev)
+{
+	return wdprobe(isa_dev);
+}
+
+#endif	/* NCARD > 0 */
+
+
+
+/*
  *  Here we use the pci-subsystem to find out, whether there is
  *  a cmd640b-chip attached on this pci-bus. This public routine
  *  will be called by ide_pci.c
@@ -294,8 +420,20 @@
 	int	interface;
 	struct disk *du;
 
-	if (unit >= NWDC)
+	if (unit >= NWDC) {
+		printf("wdprobe: bad device unit %d\n", unit);
+		return (0);
+	}
+#if	NCARD > 0
+/*
+ *	If PC-Card probe required, then register driver with
+ *	slot manager.
+ */
+	if (!static_init && (ctrlr_in_use & (1<<unit))) {
+		printf("wdprobe: pccard probe failure unit %d\n", unit);
 		return (0);
+	}
+#endif	/* NCARD > 0 */
 
 	du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
 	if (du == NULL)
@@ -312,9 +450,22 @@
 		du->dk_altport =
 		    wddma[interface].wdd_altiobase(du->dk_dmacookie);
 	}
-	if (du->dk_altport == 0)
-		du->dk_altport = du->dk_port + wd_ctlr;
 
+	if (du->dk_port != IO_WD1 && du->dk_port != IO_WD2) {
+		/* PC-card ATA cards have packed single I/O window */
+		du->dk_altsts -= wd_ctlr - 8;
+		du->dk_ctlr -= wd_ctlr - 8; du->dk_digin -= wd_ctlr - 8;
+		du->dk_altport -= wd_ctlr - 8;
+	}
+	else {
+		if (du->dk_altport == 0)
+			du->dk_altport = du->dk_port + wd_ctlr;
+
+		du->dk_altsts = wd_altsts;
+		du->dk_ctlr = wd_ctlr;
+		du->dk_digin = wd_digin;
+	}
+
 	/* check if we have registers that work */
 	outb(du->dk_port + wd_sdh, WDSD_IBM);   /* set unit 0 */
 	outb(du->dk_port + wd_cyl_lo, 0xa5);	/* wd_cyl_lo is read/write */
@@ -329,6 +480,8 @@
 
 	if (wdreset(du) == 0)
 		goto reset_ok;
+	if (dvp->id_flags & WDOPT_BROKEN_SIGNATURE)
+		goto reset_ok;
 	/* test for ATAPI signature */
 	outb(du->dk_port + wd_sdh, WDSD_IBM);           /* master */
 	if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
@@ -341,6 +494,7 @@
 		goto reset_ok;
 	DELAY(RECOVERYTIME);
 	if (wdreset(du) != 0) {
+		printf("wdreset failed\n");
 		goto nodevice;
 	}
 reset_ok:
@@ -348,6 +502,7 @@
 	/* execute a controller only command */
 	if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
 	    || wdwait(du, 0, TIMEOUT) < 0) {
+		printf("No controller command accepted\n");
 		goto nodevice;
 	}
 
@@ -373,8 +528,10 @@
 			outb(du->dk_port+ wd_sdh, sdh);
 
 			/* Wait, to make sure drv 1 has completed diags */
-			if ( wdwait(du, 0, TIMEOUT) < 0)
+			if ( wdwait(du, 0, TIMEOUT) < 0) {
+				printf("wdprobe: diags not finished\n");
 				goto nodevice;
+			}
 
 			/* Get status for drive 1 */
 			du->dk_error = inb(du->dk_port + wd_error);
@@ -384,13 +541,20 @@
 			 * drives involved) 0x81 really means 0x81
 			 * (drive 0 OK, drive 1 failed).
 			 */
-			if(du->dk_error != 0x01 && du->dk_error != 0x81)
+			if(du->dk_error != 0x01 && du->dk_error != 0x81) {
+				printf("wdprobe: error 0x%x\n", du->dk_error);
 				goto nodevice;
-		} else	/* drive 0 fail */
+			}
+		} else {	/* drive 0 fail */
+			printf("drive 0 fail\n");
 			goto nodevice;
+		}
 	}
 
 
+#if NCARD > 0
+	ctrlr_in_use |= (1<<unit);
+#endif /* NCARD > 0 */
 	free(du, M_TEMP);
 	return (IO_WDCSIZE);
 
@@ -411,6 +575,10 @@
 	int	unit, lunit, flags, i;
 	struct disk *du;
 	struct wdparams *wp;
+#if NCARD > 0
+	static int once_registered = 0;
+	int valid_units = 0;
+#endif /* NCARD > 0 */
 	static char buf[] = "wdcXXX";
 
 	dvp->id_intr = wdintr;
@@ -435,6 +603,21 @@
 			continue;
 
 		lunit = resource_query_unit(i);
+
+#if   NCARD > 0
+		/*
+		 * XXX
+		 * for PCMCIA Flash ATA/Type III HDD cards.
+		 * HOSOKAWA, Tatsumi <hosokawa@jp.FreeBSD.org>
+		 */
+		if (lunit_in_use & (1<<lunit)) {
+			if (static_init)
+				panic("drive attached twice");
+			else
+				continue;
+		}
+#endif        /* NCARD > 0 */
+
 		if (lunit >= NWD)
 			continue;
 
@@ -443,11 +626,19 @@
 		if (resource_int_value("wd", lunit, "flags", &flags) != 0)
 			flags = 0;
 
+#if   NCARD > 0
+		du = wddrives[lunit];
+		if (du == NULL)
+			du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
+		if (du == NULL)
+			continue;
+#else /* NCARD > 0 */
 		du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
 		if (du == NULL)
 			continue;
 		if (wddrives[lunit] != NULL)
 			panic("drive attached twice");
+#endif	/* NCARD > 0 */
 		wddrives[lunit] = du;
 		bufq_init(&drive_queue[lunit]);
 		bzero(du, sizeof *du);
@@ -460,8 +651,19 @@
 		du->dk_unit = unit;
 		du->dk_lunit = lunit;
 		du->dk_port = dvp->id_iobase;
+		du->dk_altsts = wd_altsts;
+		du->dk_ctlr = wd_ctlr;
+		du->dk_digin = wd_digin;
 
 		du->dk_altport = du->dk_port + wd_ctlr;
+
+		if (du->dk_port != IO_WD1 && du->dk_port != IO_WD2) {
+			du->dk_altsts -= wd_ctlr - 8;
+			du->dk_ctlr -= wd_ctlr - 8;
+			du->dk_digin -= wd_ctlr - 8;
+			du->dk_altport -= wd_ctlr - 8;
+		}
+
 		/*
 		 * Use the individual device flags or the controller
 		 * flags.
@@ -522,6 +724,13 @@
 			 */
 			wdtimeout(du);
 
+#if	NCARD > 0
+			lunit_in_use |= (1<<lunit);
+			valid_units++;
+		    /* do not register twice */
+		    if ((once_registered & (1<<lunit)) == 0) {
+			once_registered |= (1<<lunit);
+#endif	/* NCARD > 0 */
 #ifdef DEVFS
 			mynor = dkmakeminor(lunit, WHOLE_DISK_SLICE, RAW_PART);
 			du->dk_bdev = devfs_add_devswf(&wd_cdevsw, mynor,
@@ -543,6 +752,9 @@
 					  DEVSTAT_TYPE_DIRECT |
 					  DEVSTAT_TYPE_IF_IDE,
 					  DEVSTAT_PRIORITY_WD);
+#if   NCARD > 0
+		    }
+#endif /* NCARD > 0 */
 
 		} else {
 			free(du, M_TEMP);
@@ -553,13 +765,28 @@
 	 * Probe all free IDE units, searching for ATAPI drives.
 	 */
 	for (unit=0; unit<2; ++unit) {
+#if   NCARD > 0
 		for (lunit=0; lunit<NWD; ++lunit)
+			if ((lunit_in_use & (1<<lunit)) && wddrives[lunit] &&
+			    wddrives[lunit]->dk_ctrlr == dvp->id_unit &&
+			    wddrives[lunit]->dk_unit == unit)
+				goto next;
+#else /* NCARD > 0 */
+		for (lunit=0; lunit<NWD; ++lunit)
 			if (wddrives[lunit] &&
 			    wddrives[lunit]->dk_ctrlr == dvp->id_unit &&
 			    wddrives[lunit]->dk_unit == unit)
 				goto next;
+#endif /* NCARD > 0 */
+#if   NCARD > 0
+		if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase)) {
+			atapictrlr = dvp->id_unit;
+			valid_units++;
+		}
+#else /* NCARD > 0 */
 		if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase))
 			atapictrlr = dvp->id_unit;
+#endif		/* NCARD > 0 */
 next: ;
 	}
 	/*
@@ -572,6 +799,10 @@
 		wdtab[dvp->id_unit].b_active = 2;
 	}
 
+#if	NCARD > 0
+	if (!static_init && valid_units == 0)
+		return (0); /* no valid unit found */
+#endif /* NCARD > 0 */
 	return (1);
 }
 
@@ -1236,6 +1467,10 @@
 	lunit = dkunit(dev);
 	if (lunit >= NWD || dktype(dev) != 0)
 		return (ENXIO);
+#if NCARD > 0
+	if ((lunit_in_use & (1<<lunit)) == 0)
+		return (ENXIO);
+#endif /* NCARD > 0 */
 	du = wddrives[lunit];
 	if (du == NULL)
 		return (ENXIO);
@@ -2001,6 +2236,9 @@
 	lunit = dkunit(dev);	/* eventually support floppies? */
 	part = dkpart(dev);
 	if (lunit >= NWD || (du = wddrives[lunit]) == NULL
+#if NCARD > 0
+	    || (lunit_in_use & (1<<lunit)) == 0
+#endif /* NCARD > 0 */
 	    || du->dk_state < OPEN
 	    || (lp = dsgetlabel(dev, du->dk_slices)) == NULL)
 		return (ENXIO);
--
HOSOKAWA, Tatsumi
Assistant Manager
Information Technology Center, Keio University
<hosokawa@itc.keio.ac.jp>


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-mobile" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199908131135.UAA00766>