1 /*- 2 * Copyright (c) 1999 Doug Rabson 3 * All rights reserved. 4 * 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. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 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 * 26 * $Id: isa_common.c,v 1.4 1999/07/29 01:02:56 mdodd Exp $ 27 */ 28 /* 29 * Modifications for Intel architecture by Garrett A. Wollman. 30 * Copyright 1998 Massachusetts Institute of Technology 31 * 32 * Permission to use, copy, modify, and distribute this software and 33 * its documentation for any purpose and without fee is hereby 34 * granted, provided that both the above copyright notice and this 35 * permission notice appear in all copies, that both the above 36 * copyright notice and this permission notice appear in all 37 * supporting documentation, and that the name of M.I.T. not be used 38 * in advertising or publicity pertaining to distribution of the 39 * software without specific, written prior permission. M.I.T. makes 40 * no representations about the suitability of this software for any 41 * purpose. It is provided "as is" without express or implied 42 * warranty. 43 * 44 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 45 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 46 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 47 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 48 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 50 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 51 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 52 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 53 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 54 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 /* 59 * Parts of the ISA bus implementation common to all architectures. 60 */ 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/kernel.h> 65 #include <sys/bus.h> 66 #include <sys/malloc.h> 67 #include <sys/module.h> 68 #include <machine/bus.h> 69 #include <sys/rman.h> 70 71 #include <machine/resource.h> 72 73 #include <isa/isavar.h> 74 #include <isa/isa_common.h> 75 #ifdef __alpha__ /* XXX workaround a stupid warning */ 76 #include <alpha/isa/isavar.h> 77 #endif 78 79 MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device"); 80 81 static devclass_t isa_devclass; 82 83 /* 84 * At 'probe' time, we add all the devices which we know about to the 85 * bus. The generic attach routine will probe and attach them if they 86 * are alive. 87 */ 88 static int 89 isa_probe(device_t dev) 90 { 91 device_set_desc(dev, "ISA bus"); 92 isa_init(); /* Allow machdep code to initialise */ 93 return bus_generic_probe(dev); 94 } 95 96 extern device_t isa_bus_device; 97 98 static int 99 isa_attach(device_t dev) 100 { 101 /* 102 * Arrange for bus_generic_attach(dev) to be called later. 103 */ 104 isa_bus_device = dev; 105 return 0; 106 } 107 108 /* 109 * Add a new child with default ivars. 110 */ 111 static device_t 112 isa_add_child(device_t dev, int order, const char *name, int unit) 113 { 114 struct isa_device *idev; 115 116 idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT); 117 if (!idev) 118 return 0; 119 bzero(idev, sizeof *idev); 120 121 resource_list_init(&idev->id_resources); 122 idev->id_flags = 0; 123 124 return device_add_child_ordered(dev, order, name, unit, idev); 125 } 126 127 static void 128 isa_print_resources(struct resource_list *rl, const char *name, int type, 129 const char *format) 130 { 131 struct resource_list_entry *rle0 = resource_list_find(rl, type, 0); 132 struct resource_list_entry *rle1 = resource_list_find(rl, type, 1); 133 134 if (rle0 || rle1) { 135 printf(" %s ", name); 136 if (rle0) { 137 printf(format, rle0->start); 138 if (rle0->count > 1) { 139 printf("-"); 140 printf(format, rle0->start + rle0->count - 1); 141 } 142 } 143 if (rle1) { 144 if (rle0) 145 printf(","); 146 printf(format, rle1->start); 147 if (rle1->count > 1) { 148 printf("-"); 149 printf(format, rle1->start + rle1->count - 1); 150 } 151 } 152 } 153 } 154 155 static int 156 isa_print_child(device_t bus, device_t dev) 157 { 158 struct isa_device *idev = DEVTOISA(dev); 159 struct resource_list *rl = &idev->id_resources; 160 int retval = 0; 161 162 retval += bus_print_child_header(bus, dev); 163 164 if (SLIST_FIRST(rl) || idev->id_flags) 165 retval += printf(" at"); 166 167 isa_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx"); 168 isa_print_resources(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 169 isa_print_resources(rl, "irq", SYS_RES_IRQ, "%ld"); 170 isa_print_resources(rl, "drq", SYS_RES_DRQ, "%ld"); 171 if (idev->id_flags) 172 retval += printf(" flags %#x", idev->id_flags); 173 174 retval += bus_print_child_footer(bus, dev); 175 176 return (retval); 177 } 178 179 static int 180 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 181 { 182 struct isa_device* idev = DEVTOISA(dev); 183 struct resource_list *rl = &idev->id_resources; 184 struct resource_list_entry *rle; 185 186 switch (index) { 187 case ISA_IVAR_PORT_0: 188 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 189 if (rle) 190 *result = rle->start; 191 else 192 *result = -1; 193 break; 194 195 case ISA_IVAR_PORT_1: 196 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 197 if (rle) 198 *result = rle->start; 199 else 200 *result = -1; 201 break; 202 203 case ISA_IVAR_PORTSIZE_0: 204 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 205 if (rle) 206 *result = rle->count; 207 else 208 *result = 0; 209 break; 210 211 case ISA_IVAR_PORTSIZE_1: 212 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 213 if (rle) 214 *result = rle->count; 215 else 216 *result = 0; 217 break; 218 219 case ISA_IVAR_MADDR_0: 220 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 221 if (rle) 222 *result = rle->start; 223 else 224 *result = -1; 225 break; 226 227 case ISA_IVAR_MADDR_1: 228 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 229 if (rle) 230 *result = rle->start; 231 else 232 *result = -1; 233 break; 234 235 case ISA_IVAR_MSIZE_0: 236 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 237 if (rle) 238 *result = rle->count; 239 else 240 *result = 0; 241 break; 242 243 case ISA_IVAR_MSIZE_1: 244 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 245 if (rle) 246 *result = rle->count; 247 else 248 *result = 0; 249 break; 250 251 case ISA_IVAR_IRQ_0: 252 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 253 if (rle) 254 *result = rle->start; 255 else 256 *result = -1; 257 break; 258 259 case ISA_IVAR_IRQ_1: 260 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 261 if (rle) 262 *result = rle->start; 263 else 264 *result = -1; 265 break; 266 267 case ISA_IVAR_DRQ_0: 268 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 269 if (rle) 270 *result = rle->start; 271 else 272 *result = -1; 273 break; 274 275 case ISA_IVAR_DRQ_1: 276 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 277 if (rle) 278 *result = rle->start; 279 else 280 *result = -1; 281 break; 282 283 case ISA_IVAR_FLAGS: 284 *result = idev->id_flags; 285 break; 286 287 case ISA_IVAR_VENDORID: 288 *result = idev->id_vendorid; 289 break; 290 291 case ISA_IVAR_SERIAL: 292 *result = idev->id_serial; 293 break; 294 295 case ISA_IVAR_LOGICALID: 296 *result = idev->id_logicalid; 297 break; 298 299 case ISA_IVAR_COMPATID: 300 *result = idev->id_compatid; 301 break; 302 303 default: 304 return ENOENT; 305 } 306 307 return 0; 308 } 309 310 static int 311 isa_write_ivar(device_t bus, device_t dev, 312 int index, uintptr_t value) 313 { 314 struct isa_device* idev = DEVTOISA(dev); 315 316 switch (index) { 317 case ISA_IVAR_PORT_0: 318 case ISA_IVAR_PORT_1: 319 case ISA_IVAR_PORTSIZE_0: 320 case ISA_IVAR_PORTSIZE_1: 321 case ISA_IVAR_MADDR_0: 322 case ISA_IVAR_MADDR_1: 323 case ISA_IVAR_MSIZE_0: 324 case ISA_IVAR_MSIZE_1: 325 case ISA_IVAR_IRQ_0: 326 case ISA_IVAR_IRQ_1: 327 case ISA_IVAR_DRQ_0: 328 case ISA_IVAR_DRQ_1: 329 return EINVAL; 330 331 case ISA_IVAR_FLAGS: 332 idev->id_flags = value; 333 break; 334 335 case ISA_IVAR_VENDORID: 336 idev->id_vendorid = value; 337 break; 338 339 case ISA_IVAR_SERIAL: 340 idev->id_serial = value; 341 break; 342 343 case ISA_IVAR_LOGICALID: 344 idev->id_logicalid = value; 345 break; 346 347 case ISA_IVAR_COMPATID: 348 idev->id_compatid = value; 349 break; 350 351 default: 352 return (ENOENT); 353 } 354 355 return (0); 356 } 357 358 static int 359 isa_set_resource(device_t dev, device_t child, int type, int rid, 360 u_long start, u_long count) 361 { 362 struct isa_device* idev = DEVTOISA(child); 363 struct resource_list *rl = &idev->id_resources; 364 365 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 366 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 367 return EINVAL; 368 if (rid < 0 || rid > 1) 369 return EINVAL; 370 371 resource_list_add(rl, type, rid, start, start + count - 1, count); 372 373 return 0; 374 } 375 376 static int 377 isa_get_resource(device_t dev, device_t child, int type, int rid, 378 u_long *startp, u_long *countp) 379 { 380 struct isa_device* idev = DEVTOISA(child); 381 struct resource_list *rl = &idev->id_resources; 382 struct resource_list_entry *rle; 383 384 rle = resource_list_find(rl, type, rid); 385 if (!rle) 386 return ENOENT; 387 388 *startp = rle->start; 389 *countp = rle->count; 390 391 return 0; 392 } 393 394 static void 395 isa_delete_resource(device_t dev, device_t child, int type, int rid) 396 { 397 struct isa_device* idev = DEVTOISA(child); 398 struct resource_list *rl = &idev->id_resources; 399 resource_list_delete(rl, type, rid); 400 } 401 402 static device_method_t isa_methods[] = { 403 /* Device interface */ 404 DEVMETHOD(device_probe, isa_probe), 405 DEVMETHOD(device_attach, isa_attach), 406 DEVMETHOD(device_detach, bus_generic_detach), 407 DEVMETHOD(device_shutdown, bus_generic_shutdown), 408 DEVMETHOD(device_suspend, bus_generic_suspend), 409 DEVMETHOD(device_resume, bus_generic_resume), 410 411 /* Bus interface */ 412 DEVMETHOD(bus_add_child, isa_add_child), 413 DEVMETHOD(bus_print_child, isa_print_child), 414 DEVMETHOD(bus_read_ivar, isa_read_ivar), 415 DEVMETHOD(bus_write_ivar, isa_write_ivar), 416 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 417 DEVMETHOD(bus_release_resource, isa_release_resource), 418 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 419 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 420 DEVMETHOD(bus_setup_intr, isa_setup_intr), 421 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 422 423 /* ISA interface */ 424 DEVMETHOD(isa_set_resource, isa_set_resource), 425 DEVMETHOD(isa_get_resource, isa_get_resource), 426 DEVMETHOD(isa_delete_resource, isa_delete_resource), 427 428 { 0, 0 } 429 }; 430 431 static driver_t isa_driver = { 432 "isa", 433 isa_methods, 434 1, /* no softc */ 435 }; 436 437 /* 438 * ISA can be attached to a PCI-ISA bridge or directly to the nexus. 439 */ 440 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 441 #ifdef __i386__ 442 DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0); 443 #endif 444