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.1 1999/05/22 15:18:23 dfr 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 void 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 161 if (SLIST_FIRST(rl) || idev->id_flags) 162 printf(" at"); 163 164 isa_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx"); 165 isa_print_resources(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 166 isa_print_resources(rl, "irq", SYS_RES_IRQ, "%ld"); 167 isa_print_resources(rl, "drq", SYS_RES_DRQ, "%ld"); 168 if (idev->id_flags) 169 printf(" flags %#x", idev->id_flags); 170 171 printf(" on %s%d", 172 device_get_name(bus), device_get_unit(bus)); 173 } 174 175 static int 176 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 177 { 178 struct isa_device* idev = DEVTOISA(dev); 179 struct resource_list *rl = &idev->id_resources; 180 struct resource_list_entry *rle; 181 182 switch (index) { 183 case ISA_IVAR_PORT_0: 184 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 185 if (rle) 186 *result = rle->start; 187 else 188 *result = -1; 189 break; 190 191 case ISA_IVAR_PORT_1: 192 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 193 if (rle) 194 *result = rle->start; 195 else 196 *result = -1; 197 break; 198 199 case ISA_IVAR_PORTSIZE_0: 200 rle = resource_list_find(rl, SYS_RES_IOPORT, 0); 201 if (rle) 202 *result = rle->count; 203 else 204 *result = 0; 205 break; 206 207 case ISA_IVAR_PORTSIZE_1: 208 rle = resource_list_find(rl, SYS_RES_IOPORT, 1); 209 if (rle) 210 *result = rle->count; 211 else 212 *result = 0; 213 break; 214 215 case ISA_IVAR_MADDR_0: 216 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 217 if (rle) 218 *result = rle->start; 219 else 220 *result = -1; 221 break; 222 223 case ISA_IVAR_MADDR_1: 224 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 225 if (rle) 226 *result = rle->start; 227 else 228 *result = -1; 229 break; 230 231 case ISA_IVAR_MSIZE_0: 232 rle = resource_list_find(rl, SYS_RES_MEMORY, 0); 233 if (rle) 234 *result = rle->count; 235 else 236 *result = 0; 237 break; 238 239 case ISA_IVAR_MSIZE_1: 240 rle = resource_list_find(rl, SYS_RES_MEMORY, 1); 241 if (rle) 242 *result = rle->count; 243 else 244 *result = 0; 245 break; 246 247 case ISA_IVAR_IRQ_0: 248 rle = resource_list_find(rl, SYS_RES_IRQ, 0); 249 if (rle) 250 *result = rle->start; 251 else 252 *result = -1; 253 break; 254 255 case ISA_IVAR_IRQ_1: 256 rle = resource_list_find(rl, SYS_RES_IRQ, 1); 257 if (rle) 258 *result = rle->start; 259 else 260 *result = -1; 261 break; 262 263 case ISA_IVAR_DRQ_0: 264 rle = resource_list_find(rl, SYS_RES_DRQ, 0); 265 if (rle) 266 *result = rle->start; 267 else 268 *result = -1; 269 break; 270 271 case ISA_IVAR_DRQ_1: 272 rle = resource_list_find(rl, SYS_RES_DRQ, 1); 273 if (rle) 274 *result = rle->start; 275 else 276 *result = -1; 277 break; 278 279 case ISA_IVAR_FLAGS: 280 *result = idev->id_flags; 281 break; 282 } 283 return ENOENT; 284 } 285 286 static int 287 isa_write_ivar(device_t bus, device_t dev, 288 int index, uintptr_t value) 289 { 290 struct isa_device* idev = DEVTOISA(dev); 291 292 switch (index) { 293 case ISA_IVAR_PORT_0: 294 case ISA_IVAR_PORT_1: 295 case ISA_IVAR_PORTSIZE_0: 296 case ISA_IVAR_PORTSIZE_1: 297 case ISA_IVAR_MADDR_0: 298 case ISA_IVAR_MADDR_1: 299 case ISA_IVAR_MSIZE_0: 300 case ISA_IVAR_MSIZE_1: 301 case ISA_IVAR_IRQ_0: 302 case ISA_IVAR_IRQ_1: 303 case ISA_IVAR_DRQ_0: 304 case ISA_IVAR_DRQ_1: 305 return EINVAL; 306 307 case ISA_IVAR_FLAGS: 308 idev->id_flags = value; 309 break; 310 default: 311 return (ENOENT); 312 } 313 return (0); 314 } 315 316 static int 317 isa_set_resource(device_t dev, device_t child, int type, int rid, 318 u_long start, u_long count) 319 { 320 struct isa_device* idev = DEVTOISA(child); 321 struct resource_list *rl = &idev->id_resources; 322 323 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 324 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 325 return EINVAL; 326 if (rid < 0 || rid > 1) 327 return EINVAL; 328 329 resource_list_add(rl, type, rid, start, start + count - 1, count); 330 331 return 0; 332 } 333 334 static int 335 isa_get_resource(device_t dev, device_t child, int type, int rid, 336 u_long *startp, u_long *countp) 337 { 338 struct isa_device* idev = DEVTOISA(child); 339 struct resource_list *rl = &idev->id_resources; 340 struct resource_list_entry *rle; 341 342 rle = resource_list_find(rl, type, rid); 343 if (!rle) 344 return ENOENT; 345 346 *startp = rle->start; 347 *countp = rle->count; 348 349 return 0; 350 } 351 352 static device_method_t isa_methods[] = { 353 /* Device interface */ 354 DEVMETHOD(device_probe, isa_probe), 355 DEVMETHOD(device_attach, isa_attach), 356 DEVMETHOD(device_detach, bus_generic_detach), 357 DEVMETHOD(device_shutdown, bus_generic_shutdown), 358 DEVMETHOD(device_suspend, bus_generic_suspend), 359 DEVMETHOD(device_resume, bus_generic_resume), 360 361 /* Bus interface */ 362 DEVMETHOD(bus_add_child, isa_add_child), 363 DEVMETHOD(bus_print_child, isa_print_child), 364 DEVMETHOD(bus_read_ivar, isa_read_ivar), 365 DEVMETHOD(bus_write_ivar, isa_write_ivar), 366 DEVMETHOD(bus_alloc_resource, isa_alloc_resource), 367 DEVMETHOD(bus_release_resource, isa_release_resource), 368 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 369 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 370 DEVMETHOD(bus_setup_intr, isa_setup_intr), 371 DEVMETHOD(bus_teardown_intr, isa_teardown_intr), 372 373 /* ISA interface */ 374 DEVMETHOD(isa_set_resource, isa_set_resource), 375 DEVMETHOD(isa_get_resource, isa_get_resource), 376 377 { 0, 0 } 378 }; 379 380 static driver_t isa_driver = { 381 "isa", 382 isa_methods, 383 1, /* no softc */ 384 }; 385 386 /* 387 * ISA can be attached to a PCI-ISA bridge or directly to the nexus. 388 */ 389 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); 390 #ifdef __i386__ 391 DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0); 392 #endif 393