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>