xref: /netbsd-src/sys/arch/bebox/stand/boot/fd.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: fd.c,v 1.9 2009/03/18 10:22:27 cegger Exp $	*/
2 
3 /*-
4  * Copyright (C) 1997-1998 Kazuki Sakamoto (sakamoto@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 <lib/libsa/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 fdinit(FD_UNIT *);
167 int fdopen(struct open_file *, int, int, int);
168 int fdclose(struct open_file *);
169 int fdioctl(struct open_file *, u_long, void *);
170 int fdstrategy(void *, int, daddr_t, size_t, void *, size_t *);
171 int fdc_out(int, int);
172 int fdc_in(int, u_char *);
173 int fdc_intr_wait(void);
174 int fd_check(FD_UNIT *);
175 void motor_on(int, int);
176 void motor_off(int, int);
177 void fdReset(int);
178 void fdRecalibrate(int, int);
179 void fdSpecify(int);
180 void fdDriveStatus(int, int, int, int *);
181 int fdSeek(int, int, int);
182 int fdSenseInt(int, int *);
183 int fdReadWrite(FD_UNIT *, int, int, int, int, u_char *);
184 void irq_init(void);
185 int irq_polling(int, int);
186 void dma_setup(u_char *, int, int, int);
187 int dma_finished(int);
188 
189 /*===========================================================================*
190  *				   fdinit				     *
191  *===========================================================================*/
192 int
193 fdinit(FD_UNIT *un)
194 {
195 	int ctlr = un->ctlr;
196 	u_char result;
197 
198 #if 0
199 	irq_init();
200 #endif
201 	fdReset(ctlr);
202 
203 	if (fdc_out(ctlr, CMD_VERSION) != SUCCESS) {  /* version check */
204 		printf ("fdc%d:fatal error: CMD_VERSION cmd fail\n", ctlr);
205 		return (FAIL);
206 	}
207 	if (fdc_in(ctlr, &result) != SUCCESS) {
208 		printf ("fdc%d:fatal error: CMD_VERSION exec fail\n", ctlr);
209 		return (FAIL);
210 	}
211 	if (result != (u_char)RESULT_VERSION) {
212 		printf ("fdc%d:fatal error: unknown version fdc\n", ctlr);
213 		return (FAIL);
214 	}
215 
216 	un->un_flags = INT_ALIVE;
217 	return (SUCCESS);
218 }
219 
220 /*===========================================================================*
221  *				   fdopen				     *
222  *===========================================================================*/
223 int
224 fdopen(struct open_file *f, int ctlr, int unit, int part)
225 {
226 	FD_UNIT	*un;
227 	int *stat;
228 
229 	if (ctlr >= CTLR_MAX)
230 		return (ENXIO);
231 	if (unit >= UNIT_MAX)
232 		return (ENXIO);
233 	un = &fd_unit[ctlr][unit];
234 	stat = un->stat;
235 
236 	if (!(un->un_flags & INT_ALIVE)) {
237 		if (fdinit(un) != SUCCESS)
238 			return (ENXIO);
239 	}
240 
241 	motor_on(ctlr, unit);
242 
243 	fdRecalibrate(ctlr, unit);
244 	fdSenseInt(ctlr, stat);
245 	if (stat[1] != START_CYL) {
246 		printf("fdc%d: unit:%d recalibrate failed. status:0x%x cyl:%d\n",
247 			ctlr, unit, stat[0], stat[1]);
248 		motor_off(ctlr, unit);
249 		return (EIO);
250 	}
251 
252 	if (fd_check(un) != SUCCESS)	/* research disk type */
253 		return (EIO);
254 
255 	f->f_devdata = (void *)un;
256 	return (SUCCESS);
257 }
258 
259 /*===========================================================================*
260  *				   fdclose				     *
261  *===========================================================================*/
262 int
263 fdclose(struct open_file *f)
264 {
265 	FD_UNIT *un = f->f_devdata;
266 
267 	fdRecalibrate(un->ctlr, un->unit);
268 	fdSenseInt(un->ctlr, un->stat);
269 	motor_off(un->ctlr, un->unit);
270 	un->un_flags = 0;
271 	return (SUCCESS);
272 }
273 
274 /*===========================================================================*
275  *				   fdioctl				     *
276  *===========================================================================*/
277 int
278 fdioctl(struct open_file *f, u_long cmd, void *arg)
279 {
280 
281 	switch (cmd) {
282 	default:
283 		return (EIO);
284 	}
285 
286 	return (SUCCESS);
287 }
288 
289 /*===========================================================================*
290  *				   fdstrategy				     *
291  *===========================================================================*/
292 int
293 fdstrategy(void *devdata, int func, daddr_t blk, size_t size, void *buf,
294 	   size_t *rsize)
295 {
296 	int sectrac, cyl, head, sec;
297 	FD_UNIT *un = devdata;
298 	int ctlr = un->ctlr;
299 	int unit = un->unit;
300 	int *stat = un->stat;
301 	long nblock, blknum;
302 	int fd_skip = 0;
303 	u_char *cbuf = (u_char *)buf;
304 
305 	if (un->un_flags & INT_BUSY) {
306 		return (ENXIO);
307 	}
308 	fdDriveStatus(ctlr, unit, 0, stat);
309 
310 	nblock = un->un_type->maxseccount;
311 	sectrac = un->un_type->seccount;	/* sector per track */
312 	*rsize = 0;
313 
314 	while (fd_skip < size) {
315 		blknum = (u_long)blk * DEV_BSIZE/FDBLK + fd_skip/FDBLK;
316 		cyl = blknum / (sectrac * 2);
317 		fdSeek(ctlr, unit, cyl);
318 		fdSenseInt(ctlr, stat);
319 		if (!(stat[0] & RESULT_SEEK)) {
320 			printf("fdc%d: unit:%d seek failed."
321 				"status:0x%x cyl:%d pcyl:%d\n",
322 				ctlr, unit, stat[0], cyl, stat[1]);
323 			goto bad;
324 		}
325 
326 		sec = blknum % (sectrac * 2);
327 		head = sec / sectrac;
328 		sec = sec % sectrac + 1;
329 
330 		if (fdReadWrite(un, func, cyl, head, sec, cbuf) == FAIL) {
331 			printf("fdc%d: unit%d fdReadWrite error [%s]\n",
332 			    ctlr, unit, (func==F_READ?"READ":"WRITE"));
333 			goto bad;
334 		}
335 
336 		*rsize += FDBLK;
337 		cbuf += FDBLK;
338 		fd_skip += FDBLK;
339 	}
340 	return (SUCCESS);
341 
342 bad:
343 	return (FAIL);
344 }
345 
346 /*===========================================================================*
347  *				   fd_check				     *
348  *===========================================================================*/
349 /*
350  *	this function is Check floppy disk Type
351  */
352 int
353 fd_check(FD_UNIT *un)
354 {
355 	int ctlr = un->ctlr;
356 	int unit = un->unit;
357 	int *stat = un->stat;
358 	int type;
359 	static u_char sec_buff[SECTOR_MAX];
360 
361 	un->un_type = (FDDTYPE *)FAIL;
362 	for (type = 0; type < FDTYPE_MAX; type++) {
363 		un->un_type = &fdd_types[type];
364 
365 		/* try read start sector */
366 		outb(FDC_RATE(ctlr), un->un_type->rate);   /* rate set */
367 		fdSpecify(ctlr);
368 		fdSeek(ctlr, unit, START_CYL);
369 		fdSenseInt(ctlr, stat);
370 		if (!(stat[0] & RESULT_SEEK) || stat[1] != START_CYL) {
371 			printf("fdc%d: unit:%d seek failed. status:0x%x\n",
372 				ctlr, unit, stat[0]);
373 			goto bad;
374 		}
375 		if (fdReadWrite(un, F_READ,
376 		    START_CYL, 0, START_SECTOR, sec_buff) == FAIL) {
377 			continue;	/* bad disk type */
378 		}
379 		break;
380 	}
381 	if (un->un_type == (FDDTYPE *)FAIL) {
382 		printf("fdc%d: unit:%d check disk type failed.\n",
383 		ctlr, unit);
384 		goto bad;
385 	}
386 	return (SUCCESS);
387 bad:
388 	return (FAIL);
389 }
390 
391 /*
392  * for FDC routines.
393  */
394 /*===========================================================================*
395  *				fdc_out					     *
396  *===========================================================================*/
397 int
398 fdc_out(int ctlr, int cmd)
399 {
400 	volatile int status;
401 	int time_out;
402 
403 	time_out = TIMEOUT;
404 	while (((status = inb(FDC_STATUS(ctlr))) & (RQM | DIO))
405 		!= (RQM | 0) && time_out-- > 0);
406 	if (time_out <= 0) {
407 		printf("fdc_out: timeout  status = 0x%x\n", status);
408 		return (FAIL);
409 	}
410 
411 	outb(FDC_DATA(ctlr), cmd);
412 
413 	return (SUCCESS);
414 }
415 
416 /*===========================================================================*
417  *				fdc_in					     *
418  *===========================================================================*/
419 int
420 fdc_in(int ctlr, u_char *data)
421 {
422 	volatile int status;
423 	int time_out;
424 
425 	time_out = TIMEOUT;
426 	while ((status = inb(FDC_STATUS(ctlr)) & (RQM | DIO))
427 	    != (RQM | DIO) && time_out-- > 0) {
428 		if (status == RQM) {
429 			printf("fdc_in:error:ready for output\n");
430 			return (FAIL);
431 		}
432 	}
433 
434 	if (time_out <= 0) {
435 		printf("fdc_in:input ready timeout\n");
436 		return (FAIL);
437 	}
438 
439 	if (data) *data = (u_char)inb(FDC_DATA(ctlr));
440 
441 	return (SUCCESS);
442 }
443 
444 /*===========================================================================*
445  *                              fdc_intr_wait                                *
446  *===========================================================================*/
447 int
448 fdc_intr_wait(void)
449 {
450 
451 	return (irq_polling(FDC_IRQ, INT_TIMEOUT));	/* wait interrupt */
452 }
453 
454 /*===========================================================================*
455  *		   	     fdc command function	 	    	     *
456  *===========================================================================*/
457 void
458 motor_on(int ctlr, int unit)
459 {
460 
461 	outb(FDC_DOR(ctlr), DOR_RESET | DOR_DMAEN | unit
462 		| (1 << (unit + 4)));	/* reset & unit motor on */
463 	DELAY(1);		/* wait 100msec */
464 }
465 
466 void
467 motor_off(int ctlr, int unit)
468 {
469 
470 	outb(FDC_DOR(ctlr), DOR_RESET);		/* reset & motor off */
471 	if (fdc_intr_wait() == FAIL)		/* wait interrupt */
472 		printf("fdc: motor off failed.\n");
473 }
474 
475 void
476 fdReset(int ctlr)
477 {
478 
479 	outb(FDC_DOR(ctlr), 0); /* fdc reset */
480 	DELAY(3);
481 	outb(FDC_DOR(ctlr), DOR_RESET);
482 	DELAY(8);
483 }
484 
485 void
486 fdRecalibrate(int ctlr, int unit)
487 {
488 
489 	fdc_out(ctlr, CMD_RECALIBRATE);
490 	fdc_out(ctlr, unit);
491 
492 	if (fdc_intr_wait() == FAIL)   /* wait interrupt */
493 		printf("fdc: recalibrate Timeout\n");
494 }
495 
496 void
497 fdSpecify(int ctlr)
498 {
499 
500 	fdc_out(ctlr, CMD_SPECIFY);
501 	fdc_out(ctlr, SPECIFY1);
502 	fdc_out(ctlr, SPECIFY2);
503 }
504 
505 void
506 fdDriveStatus(int ctlr, register int unit, register int head,
507 	      register int *stat)
508 {
509 	u_char result;
510 
511 	fdc_out(ctlr, CMD_DRV_SENSE);
512 	fdc_out(ctlr, (head << 2) | unit);
513 	fdc_in(ctlr, &result);
514 	*stat = (int)(result & 0xff);
515 }
516 
517 int
518 fdSeek(int ctlr, int unit, int cyl)
519 {
520 	int ret_val = 0;
521 
522 	fdc_out(ctlr, CMD_SEEK);
523 	fdc_out(ctlr, unit);
524 	fdc_out(ctlr, cyl);
525 
526         if (fdc_intr_wait() == FAIL) {		/* wait interrupt */
527 		printf("fdc: fdSeek Timeout\n");
528 		ret_val = FAIL;
529 	}
530 
531 	return(ret_val);
532 }
533 
534 int
535 fdSenseInt(int ctlr, int *stat)
536 {
537 	u_char result;
538 
539 	fdc_out(ctlr, CMD_SENSE_INT);
540 
541 	fdc_in(ctlr, &result);
542 	*stat++ = (int)(result & 0xff);
543 	fdc_in(ctlr, &result);
544 	*stat++ = (int)(result & 0xff);
545 
546 	return (0);
547 }
548 
549 int
550 fdReadWrite(FD_UNIT *un, int func, int cyl, int head, int sec, u_char *adrs)
551 {
552 	int i;
553 	int ctlr = un->ctlr;
554 	int unit = un->unit;
555 	int *stat = un->stat;
556 	u_char result;
557 
558 #if 0
559 printf("%s:", (func == F_READ ? "READ" : "WRITE"));
560 printf("cyl = %d", cyl);
561 printf("head = %d", head);
562 printf("sec = %d", sec);
563 printf("secsize = %d", un->un_type->secsize);
564 printf("seccount = %d", un->un_type->seccount);
565 printf("gap = %d", un->un_type->gap);
566 printf("datalen = %d\n", un->un_type->datalen);
567 #endif
568 
569 	dma_setup(adrs, FDBLK, func, FD_DMA_CHAN);
570 	fdc_out(ctlr, (func == F_READ ? CMD_READ : CMD_WRITE));
571 	fdc_out(ctlr, (head<<2) | unit);
572 	fdc_out(ctlr, cyl);			/* cyl */
573 	fdc_out(ctlr, head);			/* head */
574 	fdc_out(ctlr, sec);			/* sec */
575 	fdc_out(ctlr, un->un_type->secsize);	/* secsize */
576 	fdc_out(ctlr, un->un_type->seccount);	/* EOT (end of track) */
577 	fdc_out(ctlr, un->un_type->gap);	/* GAP3 */
578 	fdc_out(ctlr, un->un_type->datalen);	/* DTL (data length) */
579 
580 	if (fdc_intr_wait() == FAIL) {  /* wait interrupt */
581 		printf("fdc: DMA transfer Timeout\n");
582 		return (FAIL);
583 	}
584 
585 	for (i = 0; i < 7; i++) {
586 		fdc_in(ctlr, &result);
587 		stat[i] = (int)(result & 0xff);
588 	}
589 	if (stat[0] & ST0_IC_MASK) {	/* not normal terminate */
590 		if ((stat[1] & ~ST1_EN) || stat[2])
591 		goto bad;
592 	}
593 	if (!dma_finished(FD_DMA_CHAN)) {
594 		printf("DMA not finished\n");
595 		goto bad;
596 	}
597 	return (SUCCESS);
598 
599 bad:
600 	printf("       func: %s\n", (func == F_READ ? "F_READ" : "F_WRITE"));
601 	printf("	st0 = 0x%x\n", stat[0]);
602 	printf("	st1 = 0x%x\n", stat[1]);
603 	printf("	st2 = 0x%x\n", stat[2]);
604 	printf("	  c = 0x%x\n", stat[3]);
605 	printf("	  h = 0x%x\n", stat[4]);
606 	printf("	  r = 0x%x\n", stat[5]);
607 	printf("	  n = 0x%x\n", stat[6]);
608 	return (FAIL);
609 }
610 
611 /*-----------------------------------------------------------------------
612  * Interrupt Controller Operation Functions
613  *-----------------------------------------------------------------------
614  */
615 
616 /* 8259A interrupt controller register */
617 #define	INT_CTL0	0x20
618 #define	INT_CTL1	0x21
619 #define	INT2_CTL0	0xA0
620 #define	INT2_CTL1	0xA1
621 
622 #define	CASCADE_IRQ	2
623 
624 #define	ICW1_AT		0x11    /* edge triggered, cascade, need ICW4 */
625 #define	ICW4_AT		0x01    /* not SFNM, not buffered, normal EOI, 8086 */
626 #define	OCW3_PL		0x0e	/* polling mode */
627 #define	OCW2_CLEAR	0x20	/* interrupt clear */
628 
629 /*
630  * IRC programing sequence
631  *
632  * after reset
633  * 1.	ICW1 (write port:INT_CTL0 data:bit4=1)
634  * 2.	ICW2 (write port:INT_CTL1)
635  * 3.	ICW3 (write port:INT_CTL1)
636  * 4.	ICW4 (write port:INT_CTL1)
637  *
638  * after ICW
639  *	OCW1 (write port:INT_CTL1)
640  *	OCW2 (write port:INT_CTL0 data:bit3=0,bit4=0)
641  *	OCW3 (write port:INT_CTL0 data:bit3=1,bit4=0)
642  *
643  *	IMR  (read port:INT_CTL1)
644  *	IRR  (read port:INT_CTL0)	OCW3(bit1=1,bit0=0)
645  *	ISR  (read port:INT_CTL0)	OCW3(bit1=1,bit0=1)
646  *	PL   (read port:INT_CTL0)	OCW3(bit2=1,bit1=1)
647  */
648 
649 u_int INT_MASK;
650 u_int INT2_MASK;
651 
652 /*===========================================================================*
653  *                             irq initialize                                *
654  *===========================================================================*/
655 void
656 irq_init(void)
657 {
658 	outb(INT_CTL0, ICW1_AT);		/* ICW1 */
659 	outb(INT_CTL1, 0);			/* ICW2 for master */
660 	outb(INT_CTL1, (1 << CASCADE_IRQ));	/* ICW3 tells slaves */
661 	outb(INT_CTL1, ICW4_AT);		/* ICW4 */
662 
663 	outb(INT_CTL1, (INT_MASK = ~(1 << CASCADE_IRQ)));
664 				/* IRQ mask(exclusive of cascade) */
665 
666 	outb(INT2_CTL0, ICW1_AT);		/* ICW1 */
667 	outb(INT2_CTL1, 8); 			/* ICW2 for slave */
668 	outb(INT2_CTL1, CASCADE_IRQ);		/* ICW3 is slave nr */
669 	outb(INT2_CTL1, ICW4_AT);		/* ICW4 */
670 
671 	outb(INT2_CTL1, (INT2_MASK = ~0));	/* IRQ 8-15 mask */
672 }
673 
674 /*===========================================================================*
675  *                           irq polling check                               *
676  *===========================================================================*/
677 int
678 irq_polling(int irq_no, int timeout)
679 {
680 	int	irc_no;
681 	int	data;
682 	int	ret;
683 
684 	if (irq_no > 8) irc_no = 1;
685 		else irc_no = 0;
686 
687 	outb(irc_no ? INT2_CTL1 : INT_CTL1, ~(1 << (irq_no >> (irc_no * 3))));
688 
689 	while (--timeout > 0) {
690 		outb(irc_no ? INT2_CTL0 : INT_CTL0, OCW3_PL);
691 						/* set polling mode */
692 		data = inb(irc_no ? INT2_CTL0 : INT_CTL0);
693 		if (data & 0x80) {	/* if interrupt request */
694 			if ((irq_no >> (irc_no * 3)) == (data & 0x7)) {
695 				ret = SUCCESS;
696 				break;
697 			}
698 		}
699 	}
700 	if (!timeout) ret = FAIL;
701 
702 	if (irc_no) {				/* interrupt clear */
703 		outb(INT2_CTL0, OCW2_CLEAR | (irq_no >> 3));
704 		outb(INT_CTL0, OCW2_CLEAR | CASCADE_IRQ);
705 	} else {
706 		outb(INT_CTL0, OCW2_CLEAR | irq_no);
707 	}
708 
709 	outb(INT_CTL1, INT_MASK);
710 	outb(INT2_CTL1, INT2_MASK);
711 
712 	return (ret);
713 }
714 
715 /*---------------------------------------------------------------------------*
716  *			DMA Controller Define			 	     *
717  *---------------------------------------------------------------------------*/
718 /* DMA Controller Registers */
719 #define	DMA_ADDR	0x004    /* port for low 16 bits of DMA address */
720 #define	DMA_LTOP	0x081    /* port for top low 8bit DMA addr(ch2) */
721 #define	DMA_HTOP	0x481    /* port for top high 8bit DMA addr(ch2) */
722 #define	DMA_COUNT	0x005    /* port for DMA count (count =  bytes - 1) */
723 #define	DMA_DEVCON	0x008    /* DMA device control register */
724 #define	DMA_SR		0x008    /* DMA status register */
725 #define	DMA_RESET	0x00D    /* DMA software reset register */
726 #define	DMA_FLIPFLOP	0x00C    /* DMA byte pointer flip-flop */
727 #define	DMA_MODE	0x00B    /* DMA mode port */
728 #define	DMA_INIT	0x00A    /* DMA init port */
729 
730 #define	DMA_RESET_VAL	0x06
731 /* DMA channel commands. */
732 #define	DMA_READ	0x46    /* DMA read opcode */
733 #define	DMA_WRITE	0x4A    /* DMA write opcode */
734 
735 /*===========================================================================*
736  *				dma_setup				     *
737  *===========================================================================*/
738 void
739 dma_setup(u_char *buf, int size, int func, int chan)
740 {
741 	u_long pbuf = local_to_PCI((u_long)buf);
742 
743 #if 0
744 	outb(DMA_RESET, 0);
745 	DELAY(1);
746 	outb(DMA_DEVCON, 0x00);
747 	outb(DMA_INIT, DMA_RESET_VAL);	/* reset the dma controller */
748 #endif
749 	outb(DMA_MODE, func == F_READ ? DMA_READ : DMA_WRITE);
750 	outb(DMA_FLIPFLOP, 0);		/* write anything to reset it */
751 
752 	outb(DMA_ADDR, (int)pbuf >>  0);
753 	outb(DMA_ADDR, (int)pbuf >>  8);
754 	outb(DMA_LTOP, (int)pbuf >> 16);
755 	outb(DMA_HTOP, (int)pbuf >> 24);
756 
757 	outb(DMA_COUNT, (size - 1) >> 0);
758 	outb(DMA_COUNT, (size - 1) >> 8);
759 	outb(DMA_INIT, chan);		/* some sort of enable */
760 }
761 
762 int
763 dma_finished(int chan)
764 {
765 
766 	return ((inb(DMA_SR) & 0x0f) == (1 << chan));
767 }
768