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