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