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