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