]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/isa/isa.c
Initialize isa_devtab entries for interrupt handlers in individual
[FreeBSD/FreeBSD.git] / sys / amd64 / isa / isa.c
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *      from: @(#)isa.c 7.2 (Berkeley) 5/13/91
37  *      $Id: isa.c,v 1.115 1998/10/13 08:24:38 dg Exp $
38  */
39
40 /*
41  * code to manage AT bus
42  *
43  * 92/08/18  Frank P. MacLachlan (fpm@crash.cts.com):
44  * Fixed uninitialized variable problem and added code to deal
45  * with DMA page boundaries in isa_dmarangecheck().  Fixed word
46  * mode DMA count compution and reorganized DMA setup code in
47  * isa_dmastart()
48  */
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/buf.h>
53 #include <sys/malloc.h>
54 #include <machine/ipl.h>
55 #include <machine/md_var.h>
56 #ifdef APIC_IO
57 #include <machine/smp.h>
58 #endif /* APIC_IO */
59 #include <vm/vm.h>
60 #include <vm/vm_param.h>
61 #include <vm/pmap.h>
62 #include <i386/isa/isa_device.h>
63 #include <i386/isa/intr_machdep.h>
64 #include <i386/isa/isa.h>
65 #include <i386/isa/ic/i8237.h>
66
67 #include <sys/interrupt.h>
68
69 #include "pnp.h"
70 #if NPNP > 0
71 #include <i386/isa/pnp.h>
72 #endif
73
74 /*
75 **  Register definitions for DMA controller 1 (channels 0..3):
76 */
77 #define DMA1_CHN(c)     (IO_DMA1 + 1*(2*(c)))   /* addr reg for channel c */
78 #define DMA1_SMSK       (IO_DMA1 + 1*10)        /* single mask register */
79 #define DMA1_MODE       (IO_DMA1 + 1*11)        /* mode register */
80 #define DMA1_FFC        (IO_DMA1 + 1*12)        /* clear first/last FF */
81
82 /*
83 **  Register definitions for DMA controller 2 (channels 4..7):
84 */
85 #define DMA2_CHN(c)     (IO_DMA2 + 2*(2*(c)))   /* addr reg for channel c */
86 #define DMA2_SMSK       (IO_DMA2 + 2*10)        /* single mask register */
87 #define DMA2_MODE       (IO_DMA2 + 2*11)        /* mode register */
88 #define DMA2_FFC        (IO_DMA2 + 2*12)        /* clear first/last FF */
89
90 static void config_isadev __P((struct isa_device *isdp, u_int *mp));
91 static void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
92                                  int reconfig));
93 static void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
94                           int item, char const *whatnot, char const *reason,
95                           char const *format));
96 static int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
97                          u_int checkbits));
98 static int isa_dmarangecheck __P((caddr_t va, u_int length, int chan));
99
100 /*
101  * print a conflict message
102  */
103 static void
104 conflict(dvp, tmpdvp, item, whatnot, reason, format)
105         struct isa_device       *dvp;
106         struct isa_device       *tmpdvp;
107         int                     item;
108         char const              *whatnot;
109         char const              *reason;
110         char const              *format;
111 {
112         printf("%s%d not %sed due to %s conflict with %s%d at ",
113                 dvp->id_driver->name, dvp->id_unit, whatnot, reason,
114                 tmpdvp->id_driver->name, tmpdvp->id_unit);
115         printf(format, item);
116         printf("\n");
117 }
118
119 /*
120  * Check to see if things are already in use, like IRQ's, I/O addresses
121  * and Memory addresses.
122  */
123 static int
124 haveseen(dvp, tmpdvp, checkbits)
125         struct isa_device *dvp;
126         struct isa_device *tmpdvp;
127         u_int   checkbits;
128 {
129         /*
130          * Ignore all conflicts except IRQ ones if conflicts are allowed.
131          */
132         if (dvp->id_conflicts)
133                 checkbits &= ~(CC_DRQ | CC_IOADDR | CC_MEMADDR);
134         /*
135          * Only check against devices that have already been found.
136          */
137         if (tmpdvp->id_alive) {
138                 char const *whatnot;
139
140                 /*
141                  * Check for device driver & unit conflict; just drop probing
142                  * a device which has already probed true.  This is usually
143                  * not strictly a conflict, but rather the case of somebody
144                  * having specified several mutually exclusive configurations
145                  * for a single device.
146                  */
147                 if (tmpdvp->id_driver == dvp->id_driver &&
148                     tmpdvp->id_unit == dvp->id_unit) {
149                         return 1;
150                 }
151
152                 whatnot = checkbits & CC_ATTACH ? "attach" : "prob";
153                 /*
154                  * Check for I/O address conflict.  We can only check the
155                  * starting address of the device against the range of the
156                  * device that has already been probed since we do not
157                  * know how many I/O addresses this device uses.
158                  */
159                 if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) {
160                         if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
161                             (dvp->id_iobase <=
162                                   (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
163                                 if (!(checkbits & CC_QUIET))
164                                         conflict(dvp, tmpdvp, dvp->id_iobase,
165                                             whatnot, "I/O address", "0x%x");
166                                 return 1;
167                         }
168                 }
169                 /*
170                  * Check for Memory address conflict.  We can check for
171                  * range overlap, but it will not catch all cases since the
172                  * driver may adjust the msize paramater during probe, for
173                  * now we just check that the starting address does not
174                  * fall within any allocated region.
175                  * XXX could add a second check after the probe for overlap,
176                  * since at that time we would know the full range.
177                  * XXX KERNBASE is a hack, we should have vaddr in the table!
178                  */
179                 if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) {
180                         if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
181                             (KERNBASE + dvp->id_maddr <=
182                              (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
183                                 if (!(checkbits & CC_QUIET))
184                                         conflict(dvp, tmpdvp,
185                                             (int)dvp->id_maddr, whatnot,
186                                             "maddr", "0x%x");
187                                 return 1;
188                         }
189                 }
190                 /*
191                  * Check for IRQ conflicts.
192                  */
193                 if (checkbits & CC_IRQ && tmpdvp->id_irq) {
194                         if (tmpdvp->id_irq == dvp->id_irq) {
195                                 if (!(checkbits & CC_QUIET))
196                                         conflict(dvp, tmpdvp,
197                                             ffs(dvp->id_irq) - 1, whatnot,
198                                             "irq", "%d");
199                                 return 1;
200                         }
201                 }
202                 /*
203                  * Check for DRQ conflicts.
204                  */
205                 if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) {
206                         if (tmpdvp->id_drq == dvp->id_drq) {
207                                 if (!(checkbits & CC_QUIET))
208                                         conflict(dvp, tmpdvp, dvp->id_drq,
209                                             whatnot, "drq", "%d");
210                                 return 1;
211                         }
212                 }
213         }
214         return 0;
215 }
216
217 #ifdef RESOURCE_CHECK
218 #include <sys/drvresource.h>
219
220 static int
221 checkone (struct isa_device *dvp, int type, addr_t low, addr_t high, 
222           char *resname, char *resfmt, int attaching)
223 {
224         int result = 0;
225         if (bootverbose) {
226                 if (low == high)
227                         printf("\tcheck %s: 0x%x\n", resname, low);
228                 else
229                         printf("\tcheck %s: 0x%x to 0x%x\n", 
230                                resname, low, high);
231         }
232         if (resource_check(type, RESF_NONE, low, high) != NULL) {
233                 char *whatnot = attaching ? "attach" : "prob";
234                 static struct isa_device dummydev;
235                 static struct isa_driver dummydrv;
236                 struct isa_device *tmpdvp = &dummydev;
237
238                 dummydev.id_driver = &dummydrv;
239                 dummydev.id_unit = 0;
240                 dummydrv.name = "pci";
241                 conflict(dvp, tmpdvp, low, whatnot, resname, resfmt);
242                 result = 1;
243         } else if (attaching) {
244                 if (low == high)
245                         printf("\tregister %s: 0x%x\n", resname, low);
246                 else
247                         printf("\tregister %s: 0x%x to 0x%x\n",
248                                resname, low, high);
249                 resource_claim(dvp, type, RESF_NONE, low, high);
250         }
251         return (result);
252 }
253
254 static int 
255 check_pciconflict(struct isa_device *dvp, int checkbits)
256 {
257         int result = 0;
258         int attaching = (checkbits & CC_ATTACH) != 0;
259
260         if (checkbits & CC_MEMADDR) {
261                 long maddr = dvp->id_maddr;
262                 long msize = dvp->id_msize;
263                 if (msize > 0) {
264                         if (checkone(dvp, REST_MEM, maddr, maddr + msize - 1,
265                                      "maddr", "0x%x", attaching) != 0) {
266                                 result = 1;
267                                 attaching = 0;
268                         }
269                 }
270         }
271         if (checkbits & CC_IOADDR) {
272                 unsigned iobase = dvp->id_iobase;
273                 unsigned iosize = dvp->id_alive;
274                 if (iosize == -1)
275                         iosize = 1; /* XXX can't do much about this ... */
276                 if (iosize > 0) {
277                         if (checkone(dvp, REST_PORT, iobase, iobase + iosize -1,
278                                      "I/O address", "0x%x", attaching) != 0) {
279                                 result = 1;
280                                 attaching = 0;
281                         }
282                 }
283         }
284         if (checkbits & CC_IRQ) {
285                 int irq = ffs(dvp->id_irq) - 1;
286                 if (irq >= 0) {
287                         if (checkone(dvp, REST_INT, irq, irq, 
288                                      "irq", "%d", attaching) != 0) {
289                                 result = 1;
290                                 attaching = 0;
291                         }
292                 }
293         }
294         if (checkbits & CC_DRQ) {
295                 int drq = dvp->id_drq;
296                 if (drq >= 0) {
297                         if (checkone(dvp, REST_DMA, drq, drq, 
298                                      "drq", "%d", attaching) != 0) {
299                                 result = 1;
300                                 attaching = 0;
301                         }
302                 }
303         }
304         if (result != 0)
305                 resource_free (dvp);
306         return (result);
307 }
308 #endif /* RESOURCE_CHECK */
309
310 /*
311  * Search through all the isa_devtab_* tables looking for anything that
312  * conflicts with the current device.
313  */
314 int
315 haveseen_isadev(dvp, checkbits)
316         struct isa_device *dvp;
317         u_int   checkbits;
318 {
319 #if NPNP > 0
320         struct pnp_dlist_node *nod;
321 #endif
322         struct isa_device *tmpdvp;
323         int     status = 0;
324
325         for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
326                 status |= haveseen(dvp, tmpdvp, checkbits);
327                 if (status)
328                         return status;
329         }
330         for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
331                 status |= haveseen(dvp, tmpdvp, checkbits);
332                 if (status)
333                         return status;
334         }
335         for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
336                 status |= haveseen(dvp, tmpdvp, checkbits);
337                 if (status)
338                         return status;
339         }
340         for (tmpdvp = isa_devtab_cam; tmpdvp->id_driver; tmpdvp++) {
341                 status |= haveseen(dvp, tmpdvp, checkbits);
342                 if (status)
343                         return status;
344         }
345         for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
346                 status |= haveseen(dvp, tmpdvp, checkbits);
347                 if (status)
348                         return status;
349         }
350 #if NPNP > 0
351         for (nod = pnp_device_list; nod != NULL; nod = nod->next)
352                 if (status |= haveseen(dvp, &(nod->dev), checkbits))
353                         return status;
354 #endif
355 #ifdef RESOURCE_CHECK
356         if (!dvp->id_conflicts)
357                 status = check_pciconflict(dvp, checkbits);
358         else if (bootverbose)
359                 printf("\tnot checking for resource conflicts ...\n");
360 #endif /* RESOURCE_CHECK */
361         return(status);
362 }
363
364 /*
365  * Configure all ISA devices
366  */
367 void
368 isa_configure()
369 {
370         struct isa_device *dvp;
371
372         printf("Probing for devices on the ISA bus:\n");
373         /* First probe all the sensitive probes */
374         for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
375                 if (dvp->id_driver->sensitive_hw)
376                         config_isadev(dvp, &tty_imask);
377         for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
378                 if (dvp->id_driver->sensitive_hw)
379                         config_isadev(dvp, &bio_imask);
380         for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
381                 if (dvp->id_driver->sensitive_hw)
382                         config_isadev(dvp, &net_imask);
383         for (dvp = isa_devtab_cam; dvp->id_driver; dvp++)
384                 if (dvp->id_driver->sensitive_hw)
385                         config_isadev(dvp, &cam_imask);
386         for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
387                 if (dvp->id_driver->sensitive_hw)
388                         config_isadev(dvp, (u_int *)NULL);
389
390         /* Then all the bad ones */
391         for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
392                 if (!dvp->id_driver->sensitive_hw)
393                         config_isadev(dvp, &tty_imask);
394         for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
395                 if (!dvp->id_driver->sensitive_hw)
396                         config_isadev(dvp, &bio_imask);
397         for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
398                 if (!dvp->id_driver->sensitive_hw)
399                         config_isadev(dvp, &net_imask);
400         for (dvp = isa_devtab_cam; dvp->id_driver; dvp++)
401                 if (!dvp->id_driver->sensitive_hw)
402                         config_isadev(dvp, &cam_imask);
403         for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
404                 if (!dvp->id_driver->sensitive_hw)
405                         config_isadev(dvp, (u_int *)NULL);
406
407         bio_imask |= SWI_CLOCK_MASK;
408         net_imask |= SWI_NET_MASK;
409         tty_imask |= SWI_TTY_MASK;
410
411 /*
412  * XXX we should really add the tty device to net_imask when the line is
413  * switched to SLIPDISC, and then remove it when it is switched away from
414  * SLIPDISC.  No need to block out ALL ttys during a splimp when only one
415  * of them is running slip.
416  *
417  * XXX actually, blocking all ttys during a splimp doesn't matter so much
418  * with sio because the serial interrupt layer doesn't use tty_imask.  Only
419  * non-serial ttys suffer.  It's more stupid that ALL 'net's are blocked
420  * during spltty.
421  */
422 #include "sl.h"
423 #if NSL > 0
424         net_imask |= tty_imask;
425         tty_imask = net_imask;
426 #endif
427
428         /* bio_imask |= tty_imask ;  can some tty devices use buffers? */
429
430         if (bootverbose)
431                 printf("imasks: bio %x, tty %x, net %x\n",
432                        bio_imask, tty_imask, net_imask);
433
434         /*
435          * Finish initializing intr_mask[].  Note that the partly
436          * constructed masks aren't actually used since we're at splhigh.
437          * For fully dynamic initialization, register_intr() and
438          * icu_unset() will have to adjust the masks for _all_
439          * interrupts and for tty_imask, etc.
440          */
441         for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
442                 register_imask(dvp, tty_imask);
443         for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
444                 register_imask(dvp, bio_imask);
445         for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
446                 register_imask(dvp, net_imask);
447         for (dvp = isa_devtab_cam; dvp->id_driver; dvp++)
448                 register_imask(dvp, cam_imask);
449         for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
450                 register_imask(dvp, SWI_CLOCK_MASK);
451 }
452
453 /*
454  * Configure an ISA device.
455  */
456 static void
457 config_isadev(isdp, mp)
458         struct isa_device *isdp;
459         u_int *mp;
460 {
461         config_isadev_c(isdp, mp, 0);
462 }
463
464 void
465 reconfig_isadev(isdp, mp)
466         struct isa_device *isdp;
467         u_int *mp;
468 {
469         config_isadev_c(isdp, mp, 1);
470 }
471
472 static void
473 config_isadev_c(isdp, mp, reconfig)
474         struct isa_device *isdp;
475         u_int *mp;
476         int reconfig;
477 {
478         u_int checkbits;
479         int id_alive;
480         int last_alive;
481         struct isa_driver *dp = isdp->id_driver;
482
483         if (!isdp->id_enabled) {
484             if (bootverbose)
485                 printf("%s%d: disabled, not probed.\n", dp->name, isdp->id_unit);
486             return;
487         }
488         checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR;
489         if (!reconfig && haveseen_isadev(isdp, checkbits))
490                 return;
491         if (!reconfig && isdp->id_maddr) {
492                 isdp->id_maddr -= ISA_HOLE_START;
493                 isdp->id_maddr += atdevbase;
494         }
495         if (reconfig) {
496                 last_alive = isdp->id_alive;
497                 isdp->id_reconfig = 1;
498         }
499         else {
500                 last_alive = 0;
501                 isdp->id_reconfig = 0;
502         }
503         id_alive = (*dp->probe)(isdp);
504         if (id_alive) {
505                 /*
506                  * Only print the I/O address range if id_alive != -1
507                  * Right now this is a temporary fix just for the new
508                  * NPX code so that if it finds a 486 that can use trap
509                  * 16 it will not report I/O addresses.
510                  * Rod Grimes 04/26/94
511                  */
512                 if (!isdp->id_reconfig) {
513                         printf("%s%d", dp->name, isdp->id_unit);
514                         if (id_alive != -1) {
515                                 if (isdp->id_iobase == -1)
516                                         printf(" at ?");
517                                 else {
518                                         printf(" at 0x%x", isdp->id_iobase);
519                                         if (isdp->id_iobase + id_alive - 1 !=
520                                             isdp->id_iobase) {
521                                                 printf("-0x%x",
522                                                        isdp->id_iobase + id_alive - 1);
523                                         }
524                                 }
525                         }
526                         if (isdp->id_irq)
527                                 printf(" irq %d", ffs(isdp->id_irq) - 1);
528                         if (isdp->id_drq != -1)
529                                 printf(" drq %d", isdp->id_drq);
530                         if (isdp->id_maddr)
531                                 printf(" maddr 0x%lx", kvtop(isdp->id_maddr));
532                         if (isdp->id_msize)
533                                 printf(" msize %d", isdp->id_msize);
534                         if (isdp->id_flags)
535                                 printf(" flags 0x%x", isdp->id_flags);
536                         if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) {
537                                 printf(" on motherboard");
538                         } else if (isdp->id_iobase >= 0x1000 &&
539                                     !(isdp->id_iobase & 0x300)) {
540                                 printf (" on eisa slot %d",
541                                         isdp->id_iobase >> 12);
542                         } else {
543                                 printf (" on isa");
544                         }
545                         printf("\n");
546                         /*
547                          * Check for conflicts again.  The driver may have
548                          * changed *dvp.  We should weaken the early check
549                          * since the driver may have been able to change
550                          * *dvp to avoid conflicts if given a chance.  We
551                          * already skip the early check for IRQs and force
552                          * a check for IRQs in the next group of checks.
553                          */
554                         checkbits |= CC_ATTACH | CC_IRQ;
555                         if (haveseen_isadev(isdp, checkbits))
556                                 return;
557                         isdp->id_alive = id_alive;
558                 }
559                 (*dp->attach)(isdp);
560                 if (isdp->id_irq != 0 && isdp->id_intr == NULL)
561                         printf("%s%d: irq with no handler\n",
562                             dp->name, isdp->id_unit);
563                 if (isdp->id_irq != 0 && isdp->id_intr != NULL) {
564 #ifdef APIC_IO
565                         /*
566                          * Some motherboards use upper IRQs for traditional
567                          * ISA INTerrupt sources.  In particular we have
568                          * seen the secondary IDE connected to IRQ20.
569                          * This code detects and fixes this situation.
570                          */
571                         u_int   apic_mask;
572                         int     rirq;
573
574                         apic_mask = isa_apic_mask(isdp->id_irq);
575                         if (apic_mask != isdp->id_irq) {
576                                 rirq = ffs(isdp->id_irq) - 1;
577                                 isdp->id_irq = apic_mask;
578                                 undirect_isa_irq(rirq); /* free for ISA */
579                         }
580 #endif /* APIC_IO */
581                         register_intr(ffs(isdp->id_irq) - 1, isdp->id_id,
582                                       isdp->id_ri_flags, isdp->id_intr,
583                                       mp, isdp->id_unit);
584                 }
585         } else {
586                 if (isdp->id_reconfig) {
587                         (*dp->attach)(isdp); /* reconfiguration attach */
588                 }
589                 if (!last_alive) {
590                         if (!isdp->id_reconfig) {
591                                 printf("%s%d not found",
592                                        dp->name, isdp->id_unit);
593                                 if (isdp->id_iobase != -1)
594                                         printf(" at 0x%x", isdp->id_iobase);
595                                 printf("\n");
596                         }
597                 } else {
598 #if 0
599                         /* This code has not been tested.... */
600                         if (isdp->id_irq != 0 && isdp->id_intr != NULL) {
601                                 icu_unset(ffs(isdp->id_irq) - 1,
602                                                 isdp->id_intr);
603                                 if (mp)
604                                         INTRUNMASK(*mp, isdp->id_irq);
605                         }
606 #else
607                         printf ("icu_unset() not supported here ...\n");
608 #endif
609                 }
610         }
611 }
612
613 static caddr_t  dma_bouncebuf[8];
614 static u_int    dma_bouncebufsize[8];
615 static u_int8_t dma_bounced = 0;
616 static u_int8_t dma_busy = 0;           /* Used in isa_dmastart() */
617 static u_int8_t dma_inuse = 0;          /* User for acquire/release */
618 static u_int8_t dma_auto_mode = 0;
619
620 #define VALID_DMA_MASK (7)
621
622 /* high byte of address is stored in this port for i-th dma channel */
623 static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
624
625 /*
626  * Setup a DMA channel's bounce buffer.
627  */
628 void
629 isa_dmainit(chan, bouncebufsize)
630         int chan;
631         u_int bouncebufsize;
632 {
633         void *buf;
634
635 #ifdef DIAGNOSTIC
636         if (chan & ~VALID_DMA_MASK)
637                 panic("isa_dmainit: channel out of range");
638
639         if (dma_bouncebuf[chan] != NULL)
640                 panic("isa_dmainit: impossible request"); 
641 #endif
642
643         dma_bouncebufsize[chan] = bouncebufsize;
644
645         /* Try malloc() first.  It works better if it works. */
646         buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT);
647         if (buf != NULL) {
648                 if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
649                         dma_bouncebuf[chan] = buf;
650                         return;
651                 }
652                 free(buf, M_DEVBUF);
653         }
654         buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
655                            1ul, chan & 4 ? 0x20000ul : 0x10000ul);
656         if (buf == NULL)
657                 printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize);
658         else
659                 dma_bouncebuf[chan] = buf;
660 }
661
662 /*
663  * Register a DMA channel's usage.  Usually called from a device driver
664  * in open() or during its initialization.
665  */
666 int
667 isa_dma_acquire(chan)
668         int chan;
669 {
670 #ifdef DIAGNOSTIC
671         if (chan & ~VALID_DMA_MASK)
672                 panic("isa_dma_acquire: channel out of range");
673 #endif
674
675         if (dma_inuse & (1 << chan)) {
676                 printf("isa_dma_acquire: channel %d already in use\n", chan);
677                 return (EBUSY);
678         }
679         dma_inuse |= (1 << chan);
680         dma_auto_mode &= ~(1 << chan);
681
682         return (0);
683 }
684
685 /*
686  * Unregister a DMA channel's usage.  Usually called from a device driver
687  * during close() or during its shutdown.
688  */
689 void
690 isa_dma_release(chan)
691         int chan;
692 {
693 #ifdef DIAGNOSTIC
694         if (chan & ~VALID_DMA_MASK)
695                 panic("isa_dma_release: channel out of range");
696
697         if ((dma_inuse & (1 << chan)) == 0)
698                 printf("isa_dma_release: channel %d not in use\n", chan);
699 #endif
700
701         if (dma_busy & (1 << chan)) {
702                 dma_busy &= ~(1 << chan);
703                 /* 
704                  * XXX We should also do "dma_bounced &= (1 << chan);"
705                  * because we are acting on behalf of isa_dmadone() which
706                  * was not called to end the last DMA operation.  This does
707                  * not matter now, but it may in the future.
708                  */
709         }
710
711         dma_inuse &= ~(1 << chan);
712         dma_auto_mode &= ~(1 << chan);
713 }
714
715 /*
716  * isa_dmacascade(): program 8237 DMA controller channel to accept
717  * external dma control by a board.
718  */
719 void
720 isa_dmacascade(chan)
721         int chan;
722 {
723 #ifdef DIAGNOSTIC
724         if (chan & ~VALID_DMA_MASK)
725                 panic("isa_dmacascade: channel out of range");
726 #endif
727
728         /* set dma channel mode, and set dma channel mode */
729         if ((chan & 4) == 0) {
730                 outb(DMA1_MODE, DMA37MD_CASCADE | chan);
731                 outb(DMA1_SMSK, chan);
732         } else {
733                 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
734                 outb(DMA2_SMSK, chan & 3);
735         }
736 }
737
738 /*
739  * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
740  * problems by using a bounce buffer.
741  */
742 void
743 isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
744 {
745         vm_offset_t phys;
746         int waport;
747         caddr_t newaddr;
748
749 #ifdef DIAGNOSTIC
750         if (chan & ~VALID_DMA_MASK)
751                 panic("isa_dmastart: channel out of range");
752
753         if ((chan < 4 && nbytes > (1<<16))
754             || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
755                 panic("isa_dmastart: impossible request");
756
757         if ((dma_inuse & (1 << chan)) == 0)
758                 printf("isa_dmastart: channel %d not acquired\n", chan);
759 #endif
760
761 #if 0
762         /*
763          * XXX This should be checked, but drivers like ad1848 only call
764          * isa_dmastart() once because they use Auto DMA mode.  If we
765          * leave this in, drivers that do this will print this continuously.
766          */
767         if (dma_busy & (1 << chan))
768                 printf("isa_dmastart: channel %d busy\n", chan);
769 #endif
770
771         dma_busy |= (1 << chan);
772
773         if (isa_dmarangecheck(addr, nbytes, chan)) {
774                 if (dma_bouncebuf[chan] == NULL
775                     || dma_bouncebufsize[chan] < nbytes)
776                         panic("isa_dmastart: bad bounce buffer"); 
777                 dma_bounced |= (1 << chan);
778                 newaddr = dma_bouncebuf[chan];
779
780                 /* copy bounce buffer on write */
781                 if (!(flags & B_READ))
782                         bcopy(addr, newaddr, nbytes);
783                 addr = newaddr;
784         }
785
786         /* translate to physical */
787         phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
788
789         if (flags & B_RAW) {
790             dma_auto_mode |= (1 << chan);
791         } else { 
792             dma_auto_mode &= ~(1 << chan);
793         }
794
795         if ((chan & 4) == 0) {
796                 /*
797                  * Program one of DMA channels 0..3.  These are
798                  * byte mode channels.
799                  */
800                 /* set dma channel mode, and reset address ff */
801
802                 /* If B_RAW flag is set, then use autoinitialise mode */
803                 if (flags & B_RAW) {
804                   if (flags & B_READ)
805                         outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
806                   else
807                         outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
808                 }
809                 else
810                 if (flags & B_READ)
811                         outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
812                 else
813                         outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
814                 outb(DMA1_FFC, 0);
815
816                 /* send start address */
817                 waport =  DMA1_CHN(chan);
818                 outb(waport, phys);
819                 outb(waport, phys>>8);
820                 outb(dmapageport[chan], phys>>16);
821
822                 /* send count */
823                 outb(waport + 1, --nbytes);
824                 outb(waport + 1, nbytes>>8);
825
826                 /* unmask channel */
827                 outb(DMA1_SMSK, chan);
828         } else {
829                 /*
830                  * Program one of DMA channels 4..7.  These are
831                  * word mode channels.
832                  */
833                 /* set dma channel mode, and reset address ff */
834
835                 /* If B_RAW flag is set, then use autoinitialise mode */
836                 if (flags & B_RAW) {
837                   if (flags & B_READ)
838                         outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
839                   else
840                         outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
841                 }
842                 else
843                 if (flags & B_READ)
844                         outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
845                 else
846                         outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
847                 outb(DMA2_FFC, 0);
848
849                 /* send start address */
850                 waport = DMA2_CHN(chan - 4);
851                 outb(waport, phys>>1);
852                 outb(waport, phys>>9);
853                 outb(dmapageport[chan], phys>>16);
854
855                 /* send count */
856                 nbytes >>= 1;
857                 outb(waport + 2, --nbytes);
858                 outb(waport + 2, nbytes>>8);
859
860                 /* unmask channel */
861                 outb(DMA2_SMSK, chan & 3);
862         }
863 }
864
865 void
866 isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
867 {  
868 #ifdef DIAGNOSTIC
869         if (chan & ~VALID_DMA_MASK)
870                 panic("isa_dmadone: channel out of range");
871
872         if ((dma_inuse & (1 << chan)) == 0)
873                 printf("isa_dmadone: channel %d not acquired\n", chan);
874 #endif
875
876         if (((dma_busy & (1 << chan)) == 0) && 
877             (dma_auto_mode & (1 << chan)) == 0 )
878                 printf("isa_dmadone: channel %d not busy\n", chan);
879
880         if ((dma_auto_mode & (1 << chan)) == 0)
881                 outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4);
882
883         if (dma_bounced & (1 << chan)) {
884                 /* copy bounce buffer on read */
885                 if (flags & B_READ)
886                         bcopy(dma_bouncebuf[chan], addr, nbytes);
887
888                 dma_bounced &= ~(1 << chan);
889         }
890         dma_busy &= ~(1 << chan);
891 }
892
893 /*
894  * Check for problems with the address range of a DMA transfer
895  * (non-contiguous physical pages, outside of bus address space,
896  * crossing DMA page boundaries).
897  * Return true if special handling needed.
898  */
899
900 static int
901 isa_dmarangecheck(caddr_t va, u_int length, int chan)
902 {
903         vm_offset_t phys, priorpage = 0, endva;
904         u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
905
906         endva = (vm_offset_t)round_page((vm_offset_t)va + length);
907         for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
908                 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
909 #define ISARAM_END      RAM_END
910                 if (phys == 0)
911                         panic("isa_dmacheck: no physical page present");
912                 if (phys >= ISARAM_END)
913                         return (1);
914                 if (priorpage) {
915                         if (priorpage + PAGE_SIZE != phys)
916                                 return (1);
917                         /* check if crossing a DMA page boundary */
918                         if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
919                                 return (1);
920                 }
921                 priorpage = phys;
922         }
923         return (0);
924 }
925
926 /*
927  * Query the progress of a transfer on a DMA channel.
928  *
929  * To avoid having to interrupt a transfer in progress, we sample
930  * each of the high and low databytes twice, and apply the following
931  * logic to determine the correct count.
932  *
933  * Reads are performed with interrupts disabled, thus it is to be
934  * expected that the time between reads is very small.  At most
935  * one rollover in the low count byte can be expected within the
936  * four reads that are performed.
937  *
938  * There are three gaps in which a rollover can occur :
939  *
940  * - read low1
941  *              gap1
942  * - read high1
943  *              gap2
944  * - read low2
945  *              gap3
946  * - read high2
947  *
948  * If a rollover occurs in gap1 or gap2, the low2 value will be
949  * greater than the low1 value.  In this case, low2 and high2 are a
950  * corresponding pair. 
951  *
952  * In any other case, low1 and high1 can be considered to be correct.
953  *
954  * The function returns the number of bytes remaining in the transfer,
955  * or -1 if the channel requested is not active.
956  *
957  */
958 int
959 isa_dmastatus(int chan)
960 {
961         u_long  cnt = 0;
962         int     ffport, waport;
963         u_long  low1, high1, low2, high2;
964
965         /* channel active? */
966         if ((dma_inuse & (1 << chan)) == 0) {
967                 printf("isa_dmastatus: channel %d not active\n", chan);
968                 return(-1);
969         }
970         /* channel busy? */
971
972         if (((dma_busy & (1 << chan)) == 0) &&
973             (dma_auto_mode & (1 << chan)) == 0 ) {
974             printf("chan %d not busy\n", chan);
975             return -2 ;
976         }       
977         if (chan < 4) {                 /* low DMA controller */
978                 ffport = DMA1_FFC;
979                 waport = DMA1_CHN(chan) + 1;
980         } else {                        /* high DMA controller */
981                 ffport = DMA2_FFC;
982                 waport = DMA2_CHN(chan - 4) + 2;
983         }
984
985         disable_intr();                 /* no interrupts Mr Jones! */
986         outb(ffport, 0);                /* clear register LSB flipflop */
987         low1 = inb(waport);
988         high1 = inb(waport);
989         outb(ffport, 0);                /* clear again */
990         low2 = inb(waport);
991         high2 = inb(waport);
992         enable_intr();                  /* enable interrupts again */
993
994         /* 
995          * Now decide if a wrap has tried to skew our results.
996          * Note that after TC, the count will read 0xffff, while we want 
997          * to return zero, so we add and then mask to compensate.
998          */
999         if (low1 >= low2) {
1000                 cnt = (low1 + (high1 << 8) + 1) & 0xffff;
1001         } else {
1002                 cnt = (low2 + (high2 << 8) + 1) & 0xffff;
1003         }
1004
1005         if (chan >= 4)                  /* high channels move words */
1006                 cnt *= 2;
1007         return(cnt);
1008 }
1009
1010 /*
1011  * Stop a DMA transfer currently in progress.
1012  */
1013 int
1014 isa_dmastop(int chan) 
1015 {
1016         if ((dma_inuse & (1 << chan)) == 0)
1017                 printf("isa_dmastop: channel %d not acquired\n", chan);  
1018
1019         if (((dma_busy & (1 << chan)) == 0) &&
1020             ((dma_auto_mode & (1 << chan)) == 0)) {
1021                 printf("chan %d not busy\n", chan);
1022                 return -2 ;
1023         }
1024     
1025         if ((chan & 4) == 0) {
1026                 outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */);
1027         } else {
1028                 outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */);
1029         }
1030         return(isa_dmastatus(chan));
1031 }
1032
1033 /*
1034  * Find the highest priority enabled display device.  Since we can't
1035  * distinguish display devices from ttys, depend on display devices
1036  * being sensitive and before sensitive non-display devices (if any)
1037  * in isa_devtab_tty.
1038  *
1039  * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES.
1040  */
1041 struct isa_device *
1042 find_display()
1043 {
1044         struct isa_device *dvp;
1045
1046         for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
1047                 if (dvp->id_driver->sensitive_hw && dvp->id_enabled)
1048                         return (dvp);
1049         return (NULL);
1050 }
1051
1052 /*
1053  * find an ISA device in a given isa_devtab_* table, given
1054  * the table to search, the expected id_driver entry, and the unit number.
1055  *
1056  * this function is defined in isa_device.h, and this location is debatable;
1057  * i put it there because it's useless w/o, and directly operates on
1058  * the other stuff in that file.
1059  *
1060  */
1061
1062 struct isa_device *
1063 find_isadev(table, driverp, unit)
1064         struct isa_device *table;
1065         struct isa_driver *driverp;
1066         int unit;
1067 {
1068         if (driverp == NULL) /* sanity check */
1069                 return (NULL);
1070
1071         while ((table->id_driver != driverp) || (table->id_unit != unit)) {
1072                 if (table->id_driver == 0)
1073                         return NULL;
1074
1075                 table++;
1076         }
1077
1078         return (table);
1079 }