Home | History | Annotate | Line # | Download | only in boot
fd.c revision 1.5
      1 /*	$NetBSD: fd.c,v 1.5 2003/12/04 13:05:15 keihan Exp $	*/
      2 
      3 /*-
      4  * Copyright (C) 1997-1998 Kazuki Sakamoto (sakamoto (at) NetBSD.org)
      5  * All rights reserved.
      6  *
      7  * Floppy Disk Drive standalone device driver
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *      This product includes software developed by Kazuki Sakamoto.
     20  * 4. The name of the author may not be used to endorse or promote products
     21  *    derived from this software without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/param.h>
     36 #include <stand.h>
     37 #include "boot.h"
     38 
     39 /*---------------------------------------------------------------------------*
     40  *			Floppy Disk Controller Define			     *
     41  *---------------------------------------------------------------------------*/
     42 /* Floppy Disk Controller Registers */
     43 int FDC_PORT[] = {				/* fdc base I/O port */
     44 		0x3f0, /* primary */
     45 		};
     46 #define	FDC_DOR(x)	(FDC_PORT[x] + 0x2)	/* motor drive control bits */
     47 #define	FDC_STATUS(x)	(FDC_PORT[x] + 0x4)	/* fdc main status register */
     48 #define	FDC_DATA(x)	(FDC_PORT[x] + 0x5)	/* fdc data register */
     49 #define	FDC_RATE(x)	(FDC_PORT[x] + 0x7)	/* transfer rate register */
     50 
     51 #define	FDC_IRQ		6
     52 #define	FD_DMA_CHAN	2
     53 
     54 /* fdc main status register */
     55 #define	RQM	  0x80	/* the host can transfer data if set */
     56 #define	DIO	  0x40	/* direction of data transfer. write required if set */
     57 #define	NON_DMA   0x20  /* fdc have date for transfer in non dma mode */
     58 #define	CMD_BUSY  0x10	/* command busy if set */
     59 
     60 /* fdc result status */
     61 #define	ST0_IC_MASK	0xc0	/* interrupt code  00:normal terminate */
     62 #define	ST1_EN		0x80	/* end of cylinder */
     63 
     64 /* fdc digtal output register */
     65 #define	DOR_DMAEN	0x08	/* DRQ, nDACK, TC and FINTR output enable */
     66 #define	DOR_RESET	0x04	/* fdc software reset */
     67 
     68 /* fdc command */
     69 #define	CMD_RECALIBRATE	0x07	/* recalibrate */
     70 #define	CMD_SENSE_INT	0x08	/* sense interrupt status */
     71 #define	CMD_DRV_SENSE	0x04	/* sense drive status */
     72 #define	CMD_SEEK	0x0f	/* seek */
     73 #define	CMD_FORMAT	0x4d	/* format */
     74 #define	CMD_READ	0x46	/* read e6 */
     75 #define	CMD_WRITE	0xc5	/* write */
     76 #define	CMD_VERIFY	0xf6	/* verify */
     77 #define	CMD_READID	0x4a	/* readID */
     78 #define	CMD_SPECIFY	0x03	/* specify */
     79 #define	CMD_CONFIG	0x13	/* config */
     80 #define	CMD_VERSION	0x10	/* version */
     81 
     82 /* command specify value */
     83 #define	SPECIFY1	((0x0d<<4)|0x0f)
     84 #define	SPECIFY2	((0x01<<1)|0)	/* DMA MODE */
     85 
     86 /* fdc result */
     87 #define	STATUS_MAX	16	/* result status max number */
     88 #define	RESULT_VERSION	0x90	/* enhanced controller */
     89 #define	RESULT_SEEK	0x20	/* seek & recalibrate complete flag on status0 */
     90 
     91 /*---------------------------------------------------------------------------*
     92  *			     Floppy Disk Type Define	 		     *
     93  *---------------------------------------------------------------------------*/
     94 struct	fdd_type {
     95 	int	seccount;	/* sector per track */
     96 	int	secsize;	/* byte per sector (uPD765 paramater) */
     97 	int	datalen;	/* data length */
     98 	int	gap;		/* gap */
     99 	int	gaplen;		/* gap length */
    100 	int	cylinder;	/* track per media */
    101 	int	maxseccount;	/* media max sector count */
    102 	int	step;		/* seek step */
    103 	int	rate;		/* drive rate (250 or 500kbps) */
    104 	int	heads;		/* heads */
    105 	int	f_gap;		/* format gap */
    106 	int	mselect;	/* drive mode select */
    107 	char	*type_name;	/* media type name */
    108 };
    109 typedef struct	fdd_type FDDTYPE;
    110 
    111 #define	FDTYPE_MAX	5
    112 FDDTYPE fdd_types[FDTYPE_MAX] = {
    113 	{ 18,2,0xff,0x1b,0x54,80,2880,1,0,2,0x6c,0,"2HQ" }, /* 2HD (PC/AT) */
    114 	{  8,3,0xff,0x35,0x74,77,1232,1,0,2,0x54,1,"2HD" }, /* 2HD (98) */
    115 	{ 15,2,0xff,0x1b,0x54,80,2400,1,0,2,0x54,1,"2HC" }, /* 2HC */
    116 	{  9,2,0xff,0x23,0x50,80,1440,1,2,2,0x50,1,"2DD9" },/* 2DD 9 sector */
    117 	{  8,2,0xff,0x3a,0x50,80,1280,1,2,2,0x50,1,"2DD8" },/* 2DD 8 sector */
    118 };
    119 
    120 int	fdsectors[] = {128, 256, 512, 1024, 2048, 4096};
    121 #define	SECTOR_MAX	4096
    122 #define	FDBLK	(fdsectors[un->un_type->secsize])
    123 
    124 #define	START_CYL	0
    125 #define	START_SECTOR	1
    126 
    127 #define	DELAY(x)	delay(100000 * x)		/* about 100ms */
    128 #define	INT_TIMEOUT	3000000
    129 
    130 /*---------------------------------------------------------------------------*
    131  *			FDC Device Driver Define			     *
    132  *---------------------------------------------------------------------------*/
    133 #define	CTLR_MAX	1
    134 #define	UNIT_MAX	2
    135 
    136 struct	fd_unit {
    137 	int	ctlr;
    138 	int	unit;
    139 	int	part;
    140 	u_int	un_flags;		/* unit status flag */
    141 	int	stat[STATUS_MAX];	/* result code */
    142 	FDDTYPE	*un_type;		/* floppy type (pointer) */
    143 };
    144 typedef	struct fd_unit FD_UNIT;
    145 FD_UNIT	fd_unit[CTLR_MAX][UNIT_MAX];
    146 
    147 /*
    148  *	un_flags flags
    149  */
    150 #define	INT_ALIVE	0x00000001	/* Device is Alive and Available */
    151 #define	INT_READY	0x00000002	/* Device is Ready */
    152 #define	INT_BUSY	0x00000004	/* Device is busy */
    153 
    154 /*---------------------------------------------------------------------------*
    155  *				Misc define				     *
    156  *---------------------------------------------------------------------------*/
    157 #define	TIMEOUT		10000000
    158 #define	ND_TIMEOUT	10000000
    159 
    160 #define	SUCCESS		0
    161 #define	FAIL		-1
    162 
    163 /*
    164  *	function declaration
    165  */
    166 int fdc_out __P((int, int));
    167 int fdc_in __P((int, u_char *));
    168 int fdc_intr_wait __P((void));
    169 int fd_check __P((FD_UNIT *));
    170 void motor_on __P((int, int));
    171 void motor_off __P((int, int));
    172 void fdReset __P((int));
    173 void fdRecalibrate __P((int, int));
    174 void fdSpecify __P((int));
    175 void fdDriveStatus __P((int, int, int, int *));
    176 int fdSeek __P((int, int, int));
    177 int fdSenseInt __P((int, int *));
    178 int fdReadWrite __P((FD_UNIT *, int, int, int, int, u_char *));
    179 void irq_init __P((void));
    180 int irq_polling __P((int, int));
    181 void dma_setup __P((u_char *, int, int, int));
    182 int dma_finished __P((int));
    183 
    184 /*===========================================================================*
    185  *				   fdinit				     *
    186  *===========================================================================*/
    187 int
    188 fdinit(un)
    189 	FD_UNIT	*un;
    190 {
    191 	int ctlr = un->ctlr;
    192 	u_char result;
    193 
    194 #if 0
    195 	irq_init();
    196 #endif
    197 	fdReset(ctlr);
    198 
    199 	if (fdc_out(ctlr, CMD_VERSION) != SUCCESS) {  /* version check */
    200 		printf ("fdc%d:fatal error: CMD_VERSION cmd fail\n", ctlr);
    201 		return (FAIL);
    202 	}
    203 	if (fdc_in(ctlr, &result) != SUCCESS) {
    204 		printf ("fdc%d:fatal error: CMD_VERSION exec fail\n", ctlr);
    205 		return (FAIL);
    206 	}
    207 	if (result != (u_char)RESULT_VERSION) {
    208 		printf ("fdc%d:fatal error: unknown version fdc\n", ctlr);
    209 		return (FAIL);
    210 	}
    211 
    212 	un->un_flags = INT_ALIVE;
    213 	return (SUCCESS);
    214 }
    215 
    216 /*===========================================================================*
    217  *				   fdopen				     *
    218  *===========================================================================*/
    219 int
    220 fdopen(f, ctlr, unit, part)
    221 	struct open_file *f;
    222 	int ctlr, unit, part;
    223 {
    224 	FD_UNIT	*un;
    225 	int *stat = un->stat;
    226 
    227 	if (ctlr >= CTLR_MAX)
    228 		return (ENXIO);
    229 	if (unit >= UNIT_MAX)
    230 		return (ENXIO);
    231 	un = &fd_unit[ctlr][unit];
    232 
    233 	if (!(un->un_flags & INT_ALIVE)) {
    234 		if (fdinit(un) != SUCCESS)
    235 			return (ENXIO);
    236 	}
    237 
    238 	motor_on(ctlr, unit);
    239 
    240 	fdRecalibrate(ctlr, unit);
    241 	fdSenseInt(ctlr, stat);
    242 	if (stat[1] != START_CYL) {
    243 		printf("fdc%d: unit:%d recalibrate failed. status:0x%x cyl:%d\n",
    244 			ctlr, unit, stat[0], stat[1]);
    245 		motor_off(ctlr, unit);
    246 		return (EIO);
    247 	}
    248 
    249 	if (fd_check(un) != SUCCESS)	/* research disk type */
    250 		return (EIO);
    251 
    252 	f->f_devdata = (void *)un;
    253 	return (SUCCESS);
    254 }
    255 
    256 /*===========================================================================*
    257  *				   fdclose				     *
    258  *===========================================================================*/
    259 int
    260 fdclose(f)
    261 	struct open_file *f;
    262 {
    263 	FD_UNIT *un = f->f_devdata;
    264 
    265 	fdRecalibrate(un->ctlr, un->unit);
    266 	fdSenseInt(un->ctlr, un->stat);
    267 	motor_off(un->ctlr, un->unit);
    268 	un->un_flags = 0;
    269 	return (SUCCESS);
    270 }
    271 
    272 /*===========================================================================*
    273  *				   fdioctl				     *
    274  *===========================================================================*/
    275 int
    276 fdioctl(f, cmd, arg)
    277 	struct open_file *f;
    278 	u_long cmd;
    279 	void *arg;
    280 {
    281 	switch (cmd) {
    282 	default:
    283 		return (EIO);
    284 	}
    285 
    286 	return (SUCCESS);
    287 }
    288 
    289 /*===========================================================================*
    290  *				   fdstrategy				     *
    291  *===========================================================================*/
    292 int
    293 fdstrategy(devdata, func, blk, size, buf, rsize)
    294 	void *devdata;	/* device uniq data */
    295 	int func;	/* function (read or write) */
    296 	daddr_t blk;	/* block number */
    297 	size_t size;	/* request size in bytes */
    298 	void *buf;	/* buffer */
    299 	size_t *rsize;	/* bytes transferred */
    300 {
    301 	int sectrac, cyl, head, sec;
    302 	FD_UNIT *un = devdata;
    303 	int ctlr = un->ctlr;
    304 	int unit = un->unit;
    305 	int *stat = un->stat;
    306 	long nblock, blknum;
    307 	int fd_skip = 0;
    308 	char *cbuf = (char *)buf;
    309 
    310 	if (un->un_flags & INT_BUSY) {
    311 		return (ENXIO);
    312 	}
    313 	fdDriveStatus(ctlr, unit, 0, stat);
    314 
    315 	nblock = un->un_type->maxseccount;
    316 	sectrac = un->un_type->seccount;	/* sector per track */
    317 	*rsize = 0;
    318 
    319 	while (fd_skip < size) {
    320 		blknum = (u_long)blk * DEV_BSIZE/FDBLK + fd_skip/FDBLK;
    321 		cyl = blknum / (sectrac * 2);
    322 		fdSeek(ctlr, unit, cyl);
    323 		fdSenseInt(ctlr, stat);
    324 		if (!(stat[0] & RESULT_SEEK)) {
    325 			printf("fdc%d: unit:%d seek failed."
    326 				"status:0x%x cyl:%d pcyl:%d\n",
    327 				ctlr, unit, stat[0], cyl, stat[1]);
    328 			goto bad;
    329 		}
    330 
    331 		sec = blknum % (sectrac * 2);
    332 		head = sec / sectrac;
    333 		sec = sec % sectrac + 1;
    334 
    335 		if (fdReadWrite(un, func, cyl, head, sec, cbuf) == FAIL) {
    336 			printf("fdc%d: unit%d fdReadWrite error [%s]\n",
    337 			    ctlr, unit, (func==F_READ?"READ":"WRITE"));
    338 			goto bad;
    339 		}
    340 
    341 		*rsize += FDBLK;
    342 		cbuf += FDBLK;
    343 		fd_skip += FDBLK;
    344 	}
    345 	return (SUCCESS);
    346 
    347 bad:
    348 	return (FAIL);
    349 }
    350 
    351 /*===========================================================================*
    352  *				   fd_check				     *
    353  *===========================================================================*/
    354 /*
    355  *	this function is Check floppy disk Type
    356  */
    357 int
    358 fd_check(un)
    359 	FD_UNIT	*un;
    360 {
    361 	int ctlr = un->ctlr;
    362 	int unit = un->unit;
    363 	int *stat = un->stat;
    364 	int type;
    365 	static u_char sec_buff[SECTOR_MAX];
    366 
    367 	un->un_type = (FDDTYPE *)FAIL;
    368 	for (type = 0; type < FDTYPE_MAX; type++) {
    369 		un->un_type = &fdd_types[type];
    370 
    371 		/* try read start sector */
    372 		outb(FDC_RATE(ctlr), un->un_type->rate);   /* rate set */
    373 		fdSpecify(ctlr);
    374 		fdSeek(ctlr, unit, START_CYL);
    375 		fdSenseInt(ctlr, stat);
    376 		if (!(stat[0] & RESULT_SEEK) || stat[1] != START_CYL) {
    377 			printf("fdc%d: unit:%d seek failed. status:0x%x\n",
    378 				ctlr, unit, stat[0]);
    379 			goto bad;
    380 		}
    381 		if (fdReadWrite(un, F_READ,
    382 		    START_CYL, 0, START_SECTOR, sec_buff) == FAIL) {
    383 			continue;	/* bad disk type */
    384 		}
    385 		break;
    386 	}
    387 	if (un->un_type == (FDDTYPE *)FAIL) {
    388 		printf("fdc%d: unit:%d check disk type failed.\n",
    389 		ctlr, unit);
    390 		goto bad;
    391 	}
    392 	return (SUCCESS);
    393 bad:
    394 	return (FAIL);
    395 }
    396 
    397 /*
    398  * for FDC routines.
    399  */
    400 /*===========================================================================*
    401  *				fdc_out					     *
    402  *===========================================================================*/
    403 int
    404 fdc_out(ctlr, cmd)
    405 	int ctlr;	/* controller no */
    406 	int cmd;	/* cmd */
    407 {
    408 	volatile int status;
    409 	int time_out;
    410 
    411 	time_out = TIMEOUT;
    412 	while (((status = inb(FDC_STATUS(ctlr))) & (RQM | DIO))
    413 		!= (RQM | 0) && time_out-- > 0);
    414 	if (time_out <= 0) {
    415 		printf("fdc_out: timeout  status = 0x%x\n", status);
    416 		return (FAIL);
    417 	}
    418 
    419 	outb(FDC_DATA(ctlr), cmd);
    420 
    421 	return (SUCCESS);
    422 }
    423 
    424 /*===========================================================================*
    425  *				fdc_in					     *
    426  *===========================================================================*/
    427 int
    428 fdc_in(ctlr, data)
    429 	int ctlr;	/* controller no */
    430 	u_char *data;
    431 {
    432 	volatile int status;
    433 	int time_out;
    434 
    435 	time_out = TIMEOUT;
    436 	while ((status = inb(FDC_STATUS(ctlr)) & (RQM | DIO))
    437 	    != (RQM | DIO) && time_out-- > 0) {
    438 		if (status == RQM) {
    439 			printf("fdc_in:error:ready for output\n");
    440 			return (FAIL);
    441 		}
    442 	}
    443 
    444 	if (time_out <= 0) {
    445 		printf("fdc_in:input ready timeout\n");
    446 		return (FAIL);
    447 	}
    448 
    449 	if (data) *data = (u_char)inb(FDC_DATA(ctlr));
    450 
    451 	return (SUCCESS);
    452 }
    453 
    454 /*===========================================================================*
    455  *                              fdc_intr_wait                                *
    456  *===========================================================================*/
    457 int
    458 fdc_intr_wait()
    459 {
    460 	return (irq_polling(FDC_IRQ, INT_TIMEOUT));	/* wait interrupt */
    461 }
    462 
    463 /*===========================================================================*
    464  *		   	     fdc command function	 	    	     *
    465  *===========================================================================*/
    466 void
    467 motor_on(ctlr, unit)
    468 	int ctlr;
    469 	int unit;
    470 {
    471 	outb(FDC_DOR(ctlr), DOR_RESET | DOR_DMAEN | unit
    472 		| (1 << (unit + 4)));	/* reset & unit motor on */
    473 	DELAY(1);		/* wait 100msec */
    474 }
    475 
    476 void
    477 motor_off(ctlr, unit)
    478 	int ctlr;
    479 	int unit;
    480 {
    481         outb(FDC_DOR(ctlr), DOR_RESET);		/* reset & motor off */
    482 	if (fdc_intr_wait() == FAIL)		/* wait interrupt */
    483 		printf("fdc: motor off failed.\n");
    484 }
    485 
    486 void
    487 fdReset(ctlr)
    488 {
    489 	outb(FDC_DOR(ctlr), 0); /* fdc reset */
    490 	DELAY(3);
    491 	outb(FDC_DOR(ctlr), DOR_RESET);
    492 	DELAY(8);
    493 }
    494 
    495 void
    496 fdRecalibrate(ctlr, unit)
    497 	int ctlr;
    498 	int unit;
    499 {
    500 	fdc_out(ctlr, CMD_RECALIBRATE);
    501 	fdc_out(ctlr, unit);
    502 
    503 	if (fdc_intr_wait() == FAIL)   /* wait interrupt */
    504 		printf("fdc: recalibrate Timeout\n");
    505 }
    506 
    507 void
    508 fdSpecify(ctlr)
    509 	int	ctlr;
    510 {
    511 	fdc_out(ctlr, CMD_SPECIFY);
    512 	fdc_out(ctlr, SPECIFY1);
    513 	fdc_out(ctlr, SPECIFY2);
    514 }
    515 
    516 void
    517 fdDriveStatus(ctlr, unit, head, stat)
    518 	int	ctlr;
    519 	register int	unit, head;
    520 	register int	*stat;
    521 {
    522 	u_char result;
    523 
    524 	fdc_out(ctlr, CMD_DRV_SENSE);
    525 	fdc_out(ctlr, (head << 2) | unit);
    526 	fdc_in(ctlr, &result);
    527 	*stat = (int)(result & 0xff);
    528 }
    529 
    530 int
    531 fdSeek(ctlr, unit, cyl)
    532 	int ctlr;
    533 	int unit;
    534 	int cyl;
    535 {
    536 	int ret_val = 0;
    537 
    538 	fdc_out(ctlr, CMD_SEEK);
    539 	fdc_out(ctlr, unit);
    540 	fdc_out(ctlr, cyl);
    541 
    542         if (fdc_intr_wait() == FAIL) {		/* wait interrupt */
    543 		printf("fdc: fdSeek Timeout\n");
    544 		ret_val = FAIL;
    545 	}
    546 
    547 	return(ret_val);
    548 }
    549 
    550 int
    551 fdSenseInt(ctlr, stat)
    552 	int ctlr;
    553 	int *stat;
    554 {
    555 	u_char result;
    556 
    557 	fdc_out(ctlr, CMD_SENSE_INT);
    558 
    559 	fdc_in(ctlr, &result);
    560 	*stat++ = (int)(result & 0xff);
    561 	fdc_in(ctlr, &result);
    562 	*stat++ = (int)(result & 0xff);
    563 
    564 	return (0);
    565 }
    566 
    567 int
    568 fdReadWrite(un, func, cyl, head, sec, adrs)
    569 	FD_UNIT	*un;
    570 	int func;
    571 	int cyl;
    572 	int head;
    573 	int sec;
    574 	u_char *adrs;
    575 {
    576 	int i;
    577 	int ctlr = un->ctlr;
    578 	int unit = un->unit;
    579 	int *stat = un->stat;
    580 	u_char result;
    581 
    582 #if 0
    583 printf("%s:", (func == F_READ ? "READ" : "WRITE"));
    584 printf("cyl = %d", cyl);
    585 printf("head = %d", head);
    586 printf("sec = %d", sec);
    587 printf("secsize = %d", un->un_type->secsize);
    588 printf("seccount = %d", un->un_type->seccount);
    589 printf("gap = %d", un->un_type->gap);
    590 printf("datalen = %d\n", un->un_type->datalen);
    591 #endif
    592 
    593 	dma_setup(adrs, FDBLK, func, FD_DMA_CHAN);
    594 	fdc_out(ctlr, (func == F_READ ? CMD_READ : CMD_WRITE));
    595 	fdc_out(ctlr, (head<<2) | unit);
    596 	fdc_out(ctlr, cyl);			/* cyl */
    597 	fdc_out(ctlr, head);			/* head */
    598 	fdc_out(ctlr, sec);			/* sec */
    599 	fdc_out(ctlr, un->un_type->secsize);	/* secsize */
    600 	fdc_out(ctlr, un->un_type->seccount);	/* EOT (end of track) */
    601 	fdc_out(ctlr, un->un_type->gap);	/* GAP3 */
    602 	fdc_out(ctlr, un->un_type->datalen);	/* DTL (data length) */
    603 
    604 	if (fdc_intr_wait() == FAIL) {  /* wait interrupt */
    605 		printf("fdc: DMA transfer Timeout\n");
    606 		return (FAIL);
    607 	}
    608 
    609 	for (i = 0; i < 7; i++) {
    610 		fdc_in(ctlr, &result);
    611 		stat[i] = (int)(result & 0xff);
    612 	}
    613 	if (stat[0] & ST0_IC_MASK) {	/* not normal terminate */
    614 		if ((stat[1] & ~ST1_EN) || stat[2])
    615 		goto bad;
    616 	}
    617 	if (!dma_finished(FD_DMA_CHAN)) {
    618 		printf("DMA not finished\n");
    619 		goto bad;
    620 	}
    621 	return (SUCCESS);
    622 
    623 bad:
    624 	printf("       func: %s\n", (func == F_READ ? "F_READ" : "F_WRITE"));
    625 	printf("	st0 = 0x%x\n", stat[0]);
    626 	printf("	st1 = 0x%x\n", stat[1]);
    627 	printf("	st2 = 0x%x\n", stat[2]);
    628 	printf("	  c = 0x%x\n", stat[3]);
    629 	printf("	  h = 0x%x\n", stat[4]);
    630 	printf("	  r = 0x%x\n", stat[5]);
    631 	printf("	  n = 0x%x\n", stat[6]);
    632 	return (FAIL);
    633 }
    634 
    635 /*-----------------------------------------------------------------------
    636  * Interrupt Controller Operation Functions
    637  *-----------------------------------------------------------------------
    638  */
    639 
    640 /* 8259A interrupt controller register */
    641 #define	INT_CTL0	0x20
    642 #define	INT_CTL1	0x21
    643 #define	INT2_CTL0	0xA0
    644 #define	INT2_CTL1	0xA1
    645 
    646 #define	CASCADE_IRQ	2
    647 
    648 #define	ICW1_AT		0x11    /* edge triggered, cascade, need ICW4 */
    649 #define	ICW4_AT		0x01    /* not SFNM, not buffered, normal EOI, 8086 */
    650 #define	OCW3_PL		0x0e	/* polling mode */
    651 #define	OCW2_CLEAR	0x20	/* interrupt clear */
    652 
    653 /*
    654  * IRC programing sequence
    655  *
    656  * after reset
    657  * 1.	ICW1 (write port:INT_CTL0 data:bit4=1)
    658  * 2.	ICW2 (write port:INT_CTL1)
    659  * 3.	ICW3 (write port:INT_CTL1)
    660  * 4.	ICW4 (write port:INT_CTL1)
    661  *
    662  * after ICW
    663  *	OCW1 (write port:INT_CTL1)
    664  *	OCW2 (write port:INT_CTL0 data:bit3=0,bit4=0)
    665  *	OCW3 (write port:INT_CTL0 data:bit3=1,bit4=0)
    666  *
    667  *	IMR  (read port:INT_CTL1)
    668  *	IRR  (read port:INT_CTL0)	OCW3(bit1=1,bit0=0)
    669  *	ISR  (read port:INT_CTL0)	OCW3(bit1=1,bit0=1)
    670  *	PL   (read port:INT_CTL0)	OCW3(bit2=1,bit1=1)
    671  */
    672 
    673 u_int INT_MASK;
    674 u_int INT2_MASK;
    675 
    676 /*===========================================================================*
    677  *                             irq initialize                                *
    678  *===========================================================================*/
    679 void
    680 irq_init()
    681 {
    682 	outb(INT_CTL0, ICW1_AT);		/* ICW1 */
    683 	outb(INT_CTL1, 0);			/* ICW2 for master */
    684 	outb(INT_CTL1, (1 << CASCADE_IRQ));	/* ICW3 tells slaves */
    685 	outb(INT_CTL1, ICW4_AT);		/* ICW4 */
    686 
    687 	outb(INT_CTL1, (INT_MASK = ~(1 << CASCADE_IRQ)));
    688 				/* IRQ mask(exclusive of cascade) */
    689 
    690 	outb(INT2_CTL0, ICW1_AT);		/* ICW1 */
    691 	outb(INT2_CTL1, 8); 			/* ICW2 for slave */
    692 	outb(INT2_CTL1, CASCADE_IRQ);		/* ICW3 is slave nr */
    693 	outb(INT2_CTL1, ICW4_AT);		/* ICW4 */
    694 
    695 	outb(INT2_CTL1, (INT2_MASK = ~0));	/* IRQ 8-15 mask */
    696 }
    697 
    698 /*===========================================================================*
    699  *                           irq polling check                               *
    700  *===========================================================================*/
    701 int
    702 irq_polling(irq_no, timeout)
    703 	int	irq_no;
    704 	int	timeout;
    705 {
    706 	int	irc_no;
    707 	int	data;
    708 	int	ret;
    709 
    710 	if (irq_no > 8) irc_no = 1;
    711 		else irc_no = 0;
    712 
    713 	outb(irc_no ? INT2_CTL1 : INT_CTL1, ~(1 << (irq_no >> (irc_no * 3))));
    714 
    715 	while (--timeout > 0) {
    716 		outb(irc_no ? INT2_CTL0 : INT_CTL0, OCW3_PL);
    717 						/* set polling mode */
    718 		data = inb(irc_no ? INT2_CTL0 : INT_CTL0);
    719 		if (data & 0x80) {	/* if interrupt request */
    720 			if ((irq_no >> (irc_no * 3)) == (data & 0x7)) {
    721 				ret = SUCCESS;
    722 				break;
    723 			}
    724 		}
    725 	}
    726 	if (!timeout) ret = FAIL;
    727 
    728 	if (irc_no) {				/* interrupt clear */
    729 		outb(INT2_CTL0, OCW2_CLEAR | (irq_no >> 3));
    730 		outb(INT_CTL0, OCW2_CLEAR | CASCADE_IRQ);
    731 	} else {
    732 		outb(INT_CTL0, OCW2_CLEAR | irq_no);
    733 	}
    734 
    735 	outb(INT_CTL1, INT_MASK);
    736 	outb(INT2_CTL1, INT2_MASK);
    737 
    738 	return (ret);
    739 }
    740 
    741 /*---------------------------------------------------------------------------*
    742  *			DMA Controller Define			 	     *
    743  *---------------------------------------------------------------------------*/
    744 /* DMA Controller Registers */
    745 #define	DMA_ADDR	0x004    /* port for low 16 bits of DMA address */
    746 #define	DMA_LTOP	0x081    /* port for top low 8bit DMA addr(ch2) */
    747 #define	DMA_HTOP	0x481    /* port for top high 8bit DMA addr(ch2) */
    748 #define	DMA_COUNT	0x005    /* port for DMA count (count =  bytes - 1) */
    749 #define	DMA_DEVCON	0x008    /* DMA device control register */
    750 #define	DMA_SR		0x008    /* DMA status register */
    751 #define	DMA_RESET	0x00D    /* DMA software reset register */
    752 #define	DMA_FLIPFLOP	0x00C    /* DMA byte pointer flip-flop */
    753 #define	DMA_MODE	0x00B    /* DMA mode port */
    754 #define	DMA_INIT	0x00A    /* DMA init port */
    755 
    756 #define	DMA_RESET_VAL	0x06
    757 /* DMA channel commands. */
    758 #define	DMA_READ	0x46    /* DMA read opcode */
    759 #define	DMA_WRITE	0x4A    /* DMA write opcode */
    760 
    761 /*===========================================================================*
    762  *				dma_setup				     *
    763  *===========================================================================*/
    764 void
    765 dma_setup(buf, size, func, chan)
    766 	u_char *buf;
    767 	int size;
    768 	int func;
    769 	int chan;
    770 {
    771 	u_long pbuf = local_to_PCI((u_long)buf);
    772 
    773 #if 0
    774 	outb(DMA_RESET, 0);
    775 	DELAY(1);
    776 	outb(DMA_DEVCON, 0x00);
    777 	outb(DMA_INIT, DMA_RESET_VAL);	/* reset the dma controller */
    778 #endif
    779 	outb(DMA_MODE, func == F_READ ? DMA_READ : DMA_WRITE);
    780 	outb(DMA_FLIPFLOP, 0);		/* write anything to reset it */
    781 
    782 	outb(DMA_ADDR, (int)pbuf >>  0);
    783 	outb(DMA_ADDR, (int)pbuf >>  8);
    784 	outb(DMA_LTOP, (int)pbuf >> 16);
    785 	outb(DMA_HTOP, (int)pbuf >> 24);
    786 
    787 	outb(DMA_COUNT, (size - 1) >> 0);
    788 	outb(DMA_COUNT, (size - 1) >> 8);
    789 	outb(DMA_INIT, chan);		/* some sort of enable */
    790 }
    791 
    792 int
    793 dma_finished(chan)
    794 	int chan;
    795 {
    796 	return ((inb(DMA_SR) & 0x0f) == (1 << chan));
    797 }
    798