1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * ISA bus nexus driver 28 */ 29 30 #include <sys/types.h> 31 #include <sys/cmn_err.h> 32 #include <sys/conf.h> 33 #include <sys/modctl.h> 34 #include <sys/autoconf.h> 35 #include <sys/errno.h> 36 #include <sys/debug.h> 37 #include <sys/kmem.h> 38 #include <sys/psm.h> 39 #include <sys/ddidmareq.h> 40 #include <sys/ddi_impldefs.h> 41 #include <sys/dma_engine.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/sunndi.h> 45 #include <sys/acpi/acpi_enum.h> 46 #include <sys/mach_intr.h> 47 #include <sys/pci.h> 48 #include <sys/note.h> 49 #if defined(__xpv) 50 #include <sys/hypervisor.h> 51 #include <sys/evtchn_impl.h> 52 #endif 53 54 extern int pseudo_isa; 55 extern int isa_resource_setup(void); 56 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 57 psm_intr_op_t, int *); 58 extern void pci_register_isa_resources(int, uint32_t, uint32_t); 59 static char USED_RESOURCES[] = "used-resources"; 60 static void isa_alloc_nodes(dev_info_t *); 61 static void enumerate_BIOS_serial(dev_info_t *); 62 static void adjust_prtsz(dev_info_t *isa_dip); 63 static void isa_postattach(dev_info_t *); 64 65 /* 66 * The following typedef is used to represent an entry in the "ranges" 67 * property of a pci-isa bridge device node. 68 */ 69 typedef struct { 70 uint32_t child_high; 71 uint32_t child_low; 72 uint32_t parent_high; 73 uint32_t parent_mid; 74 uint32_t parent_low; 75 uint32_t size; 76 } pib_ranges_t; 77 78 typedef struct { 79 uint32_t base; 80 uint32_t len; 81 } used_ranges_t; 82 83 #define USED_CELL_SIZE 2 /* 1 byte addr, 1 byte size */ 84 #define ISA_ADDR_IO 1 /* IO address space */ 85 #define ISA_ADDR_MEM 0 /* memory adress space */ 86 #define BIOS_DATA_AREA 0x400 87 /* 88 * #define ISA_DEBUG 1 89 */ 90 91 /* 92 * For serial ports not enumerated by ACPI, and parallel ports with 93 * illegal size. Typically, a system can have as many as 4 serial 94 * ports and 3 parallel ports. 95 */ 96 #define MAX_EXTRA_RESOURCE 7 97 static struct regspec isa_extra_resource[MAX_EXTRA_RESOURCE]; 98 static int isa_extra_count = 0; 99 100 /* 101 * Local data 102 */ 103 static ddi_dma_lim_t ISA_dma_limits = { 104 0, /* address low */ 105 0x00ffffff, /* address high */ 106 0, /* counter max */ 107 1, /* burstsize */ 108 DMA_UNIT_8, /* minimum xfer */ 109 0, /* dma speed */ 110 (uint_t)DMALIM_VER0, /* version */ 111 0x0000ffff, /* address register */ 112 0x0000ffff, /* counter register */ 113 1, /* sector size */ 114 0x00000001, /* scatter/gather list length */ 115 (uint_t)0xffffffff /* request size */ 116 }; 117 118 static ddi_dma_attr_t ISA_dma_attr = { 119 DMA_ATTR_V0, 120 (unsigned long long)0, 121 (unsigned long long)0x00ffffff, 122 0x0000ffff, 123 1, 124 1, 125 1, 126 (unsigned long long)0xffffffff, 127 (unsigned long long)0x0000ffff, 128 1, 129 1, 130 0 131 }; 132 133 134 /* 135 * Config information 136 */ 137 138 static int 139 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 140 off_t offset, off_t len, caddr_t *vaddrp); 141 142 static int 143 isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 144 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *); 145 146 static int 147 isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops, 148 off_t *, size_t *, caddr_t *, uint_t); 149 150 static int 151 isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 152 153 static int 154 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 155 ddi_intr_handle_impl_t *hdlp, void *result); 156 157 struct bus_ops isa_bus_ops = { 158 BUSO_REV, 159 isa_bus_map, 160 NULL, 161 NULL, 162 NULL, 163 i_ddi_map_fault, 164 ddi_dma_map, 165 isa_dma_allochdl, 166 ddi_dma_freehdl, 167 ddi_dma_bindhdl, 168 ddi_dma_unbindhdl, 169 ddi_dma_flush, 170 ddi_dma_win, 171 isa_dma_mctl, 172 isa_ctlops, 173 ddi_bus_prop_op, 174 NULL, /* (*bus_get_eventcookie)(); */ 175 NULL, /* (*bus_add_eventcall)(); */ 176 NULL, /* (*bus_remove_eventcall)(); */ 177 NULL, /* (*bus_post_event)(); */ 178 NULL, /* (*bus_intr_ctl)(); */ 179 NULL, /* (*bus_config)(); */ 180 NULL, /* (*bus_unconfig)(); */ 181 NULL, /* (*bus_fm_init)(); */ 182 NULL, /* (*bus_fm_fini)(); */ 183 NULL, /* (*bus_fm_access_enter)(); */ 184 NULL, /* (*bus_fm_access_exit)(); */ 185 NULL, /* (*bus_power)(); */ 186 isa_intr_ops /* (*bus_intr_op)(); */ 187 }; 188 189 190 static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 191 192 /* 193 * Internal isa ctlops support routines 194 */ 195 static int isa_initchild(dev_info_t *child); 196 197 struct dev_ops isa_ops = { 198 DEVO_REV, /* devo_rev, */ 199 0, /* refcnt */ 200 ddi_no_info, /* info */ 201 nulldev, /* identify */ 202 nulldev, /* probe */ 203 isa_attach, /* attach */ 204 nulldev, /* detach */ 205 nodev, /* reset */ 206 (struct cb_ops *)0, /* driver operations */ 207 &isa_bus_ops, /* bus operations */ 208 NULL, /* power */ 209 ddi_quiesce_not_needed, /* quiesce */ 210 }; 211 212 /* 213 * Module linkage information for the kernel. 214 */ 215 216 static struct modldrv modldrv = { 217 &mod_driverops, /* Type of module. This is ISA bus driver */ 218 "isa nexus driver for 'ISA'", 219 &isa_ops, /* driver ops */ 220 }; 221 222 static struct modlinkage modlinkage = { 223 MODREV_1, 224 &modldrv, 225 NULL 226 }; 227 228 int 229 _init(void) 230 { 231 return (mod_install(&modlinkage)); 232 } 233 234 int 235 _fini(void) 236 { 237 return (mod_remove(&modlinkage)); 238 } 239 240 int 241 _info(struct modinfo *modinfop) 242 { 243 return (mod_info(&modlinkage, modinfop)); 244 } 245 246 static int 247 isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 248 { 249 int rval; 250 251 #if defined(__xpv) 252 /* 253 * don't allow isa to attach in domU. this can happen if someone sets 254 * the console wrong, etc. ISA devices assume the H/W is there and 255 * will cause the domU to panic. 256 */ 257 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 258 return (DDI_FAILURE); 259 } 260 #endif 261 262 switch (cmd) { 263 case DDI_ATTACH: 264 break; 265 case DDI_RESUME: 266 return (DDI_SUCCESS); 267 default: 268 return (DDI_FAILURE); 269 } 270 271 bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec)); 272 273 if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) { 274 ddi_report_dev(devi); 275 /* 276 * Enumerate children -- invoking ACPICA 277 * This is normally in bus_config(), but we need this 278 * to happen earlier to boot. 279 */ 280 isa_alloc_nodes(devi); 281 } 282 283 isa_postattach(devi); 284 285 return (rval); 286 } 287 288 #define SET_RNGS(rng_p, used_p, ctyp, ptyp) do { \ 289 (rng_p)->child_high = (ctyp); \ 290 (rng_p)->child_low = (rng_p)->parent_low = (used_p)->base; \ 291 (rng_p)->parent_high = (ptyp); \ 292 (rng_p)->parent_mid = 0; \ 293 (rng_p)->size = (used_p)->len; \ 294 _NOTE(CONSTCOND) } while (0) 295 static uint_t 296 isa_used_to_ranges(int ctype, int *array, uint_t size, pib_ranges_t *ranges) 297 { 298 used_ranges_t *used_p; 299 pib_ranges_t *rng_p = ranges; 300 uint_t i, ptype; 301 302 ptype = (ctype == ISA_ADDR_IO) ? PCI_ADDR_IO : PCI_ADDR_MEM32; 303 ptype |= PCI_REG_REL_M; 304 size /= USED_CELL_SIZE; 305 used_p = (used_ranges_t *)array; 306 SET_RNGS(rng_p, used_p, ctype, ptype); 307 for (i = 1, used_p++; i < size; i++, used_p++) { 308 /* merge ranges record if applicable */ 309 if (rng_p->child_low + rng_p->size == used_p->base) 310 rng_p->size += used_p->len; 311 else { 312 rng_p++; 313 SET_RNGS(rng_p, used_p, ctype, ptype); 314 } 315 } 316 return (rng_p - ranges + 1); 317 } 318 319 void 320 isa_remove_res_from_pci(int type, int *array, uint_t size) 321 { 322 int i; 323 used_ranges_t *used_p; 324 325 size /= USED_CELL_SIZE; 326 used_p = (used_ranges_t *)array; 327 for (i = 0; i < size; i++, used_p++) 328 pci_register_isa_resources(type, used_p->base, used_p->len); 329 } 330 331 static void 332 isa_postattach(dev_info_t *dip) 333 { 334 dev_info_t *used; 335 int *ioarray, *memarray, status; 336 uint_t nio = 0, nmem = 0, nrng = 0, n; 337 pib_ranges_t *ranges; 338 339 used = ddi_find_devinfo("used-resources", -1, 0); 340 if (used == NULL) { 341 cmn_err(CE_WARN, "Failed to find used-resources <%s>\n", 342 ddi_get_name(dip)); 343 return; 344 } 345 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used, 346 DDI_PROP_DONTPASS, "io-space", &ioarray, &nio); 347 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) { 348 cmn_err(CE_WARN, "io-space property failure for %s (%x)\n", 349 ddi_get_name(used), status); 350 return; 351 } 352 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used, 353 DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem); 354 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) { 355 cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n", 356 ddi_get_name(used), status); 357 return; 358 } 359 n = (nio + nmem) / USED_CELL_SIZE; 360 ranges = (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n, 361 KM_SLEEP); 362 363 if (nio != 0) { 364 nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges); 365 isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio); 366 ddi_prop_free(ioarray); 367 } 368 if (nmem != 0) { 369 nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem, 370 ranges + nrng); 371 isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem); 372 ddi_prop_free(memarray); 373 } 374 375 if (!pseudo_isa) 376 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", 377 (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int)); 378 kmem_free(ranges, sizeof (pib_ranges_t) * n); 379 } 380 381 /*ARGSUSED*/ 382 static int 383 isa_apply_range(dev_info_t *dip, struct regspec *isa_reg_p, 384 pci_regspec_t *pci_reg_p) 385 { 386 pib_ranges_t *ranges, *rng_p; 387 int len, i, offset, nrange; 388 389 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 390 "ranges", (caddr_t)&ranges, &len) != DDI_SUCCESS) { 391 cmn_err(CE_WARN, "Can't get %s ranges property", 392 ddi_get_name(dip)); 393 return (DDI_ME_REGSPEC_RANGE); 394 } 395 nrange = len / sizeof (pib_ranges_t); 396 rng_p = ranges; 397 for (i = 0; i < nrange; i++, rng_p++) { 398 /* Check for correct space */ 399 if (isa_reg_p->regspec_bustype != rng_p->child_high) 400 continue; 401 402 /* Detect whether request entirely fits within a range */ 403 if (isa_reg_p->regspec_addr < rng_p->child_low) 404 continue; 405 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) > 406 (rng_p->child_low + rng_p->size)) 407 continue; 408 409 offset = isa_reg_p->regspec_addr - rng_p->child_low; 410 411 pci_reg_p->pci_phys_hi = rng_p->parent_high; 412 pci_reg_p->pci_phys_mid = 0; 413 pci_reg_p->pci_phys_low = rng_p->parent_low + offset; 414 pci_reg_p->pci_size_hi = 0; 415 pci_reg_p->pci_size_low = isa_reg_p->regspec_size; 416 417 break; 418 } 419 kmem_free(ranges, len); 420 421 if (i < nrange) 422 return (DDI_SUCCESS); 423 424 /* 425 * Check extra resource range specially for serial and parallel 426 * devices, which are treated differently from all other ISA 427 * devices. On some machines, serial ports are not enumerated 428 * by ACPI but by BIOS, with io base addresses noted in legacy 429 * BIOS data area. Parallel port on some machines comes with 430 * illegal size. 431 */ 432 if (isa_reg_p->regspec_bustype != ISA_ADDR_IO) 433 goto out_of_range; 434 435 for (i = 0; i < isa_extra_count; i++) { 436 struct regspec *reg_p = &isa_extra_resource[i]; 437 438 if (isa_reg_p->regspec_addr < reg_p->regspec_addr) 439 continue; 440 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) > 441 (reg_p->regspec_addr + reg_p->regspec_size)) 442 continue; 443 444 pci_reg_p->pci_phys_hi = PCI_ADDR_IO | PCI_REG_REL_M; 445 pci_reg_p->pci_phys_mid = 0; 446 pci_reg_p->pci_phys_low = isa_reg_p->regspec_addr; 447 pci_reg_p->pci_size_hi = 0; 448 pci_reg_p->pci_size_low = isa_reg_p->regspec_size; 449 break; 450 } 451 if (i < isa_extra_count) 452 return (DDI_SUCCESS); 453 454 out_of_range: 455 cmn_err(CE_WARN, "isa_apply_range: Out of range base <0x%x>, size <%d>", 456 isa_reg_p->regspec_addr, isa_reg_p->regspec_size); 457 return (DDI_ME_REGSPEC_RANGE); 458 } 459 460 static int 461 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 462 off_t offset, off_t len, caddr_t *vaddrp) 463 { 464 struct regspec tmp_reg, *rp; 465 pci_regspec_t vreg; 466 ddi_map_req_t mr = *mp; /* Get private copy of request */ 467 int error; 468 469 if (pseudo_isa) 470 return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp)); 471 472 mp = &mr; 473 474 /* 475 * First, if given an rnumber, convert it to a regspec... 476 */ 477 if (mp->map_type == DDI_MT_RNUMBER) { 478 479 int rnumber = mp->map_obj.rnumber; 480 481 rp = i_ddi_rnumber_to_regspec(rdip, rnumber); 482 if (rp == (struct regspec *)0) 483 return (DDI_ME_RNUMBER_RANGE); 484 485 /* 486 * Convert the given ddi_map_req_t from rnumber to regspec... 487 */ 488 mp->map_type = DDI_MT_REGSPEC; 489 mp->map_obj.rp = rp; 490 } 491 492 /* 493 * Adjust offset and length correspnding to called values... 494 * XXX: A non-zero length means override the one in the regspec. 495 * XXX: (Regardless of what's in the parent's range) 496 */ 497 498 tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */ 499 rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */ 500 501 rp->regspec_addr += (uint_t)offset; 502 if (len != 0) 503 rp->regspec_size = (uint_t)len; 504 505 if ((error = isa_apply_range(dip, rp, &vreg)) != 0) 506 return (error); 507 mp->map_obj.rp = (struct regspec *)&vreg; 508 509 /* 510 * Call my parents bus_map function with modified values... 511 */ 512 513 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 514 } 515 516 static int 517 isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr, 518 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 519 { 520 ddi_dma_attr_merge(dma_attr, &ISA_dma_attr); 521 return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep)); 522 } 523 524 static int 525 isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 526 ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 527 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 528 { 529 int rval; 530 ddi_dma_lim_t defalt; 531 int arg = (int)(uintptr_t)objp; 532 533 switch (request) { 534 535 case DDI_DMA_E_PROG: 536 return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp, 537 (ddi_dma_cookie_t *)lenp, arg)); 538 539 case DDI_DMA_E_ACQUIRE: 540 return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp, 541 (caddr_t)lenp)); 542 543 case DDI_DMA_E_FREE: 544 return (i_dmae_free(rdip, arg)); 545 546 case DDI_DMA_E_STOP: 547 i_dmae_stop(rdip, arg); 548 return (DDI_SUCCESS); 549 550 case DDI_DMA_E_ENABLE: 551 i_dmae_enable(rdip, arg); 552 return (DDI_SUCCESS); 553 554 case DDI_DMA_E_DISABLE: 555 i_dmae_disable(rdip, arg); 556 return (DDI_SUCCESS); 557 558 case DDI_DMA_E_GETCNT: 559 i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp); 560 return (DDI_SUCCESS); 561 562 case DDI_DMA_E_SWSETUP: 563 return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp, 564 (ddi_dma_cookie_t *)lenp, arg)); 565 566 case DDI_DMA_E_SWSTART: 567 i_dmae_swstart(rdip, arg); 568 return (DDI_SUCCESS); 569 570 case DDI_DMA_E_GETLIM: 571 bcopy(&ISA_dma_limits, objp, sizeof (ddi_dma_lim_t)); 572 return (DDI_SUCCESS); 573 574 case DDI_DMA_E_GETATTR: 575 bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t)); 576 return (DDI_SUCCESS); 577 578 case DDI_DMA_E_1STPTY: 579 { 580 struct ddi_dmae_req req1stpty = 581 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 582 if (arg == 0) { 583 req1stpty.der_command = DMAE_CMD_TRAN; 584 req1stpty.der_trans = DMAE_TRANS_DMND; 585 } else { 586 req1stpty.der_trans = DMAE_TRANS_CSCD; 587 } 588 return (i_dmae_prog(rdip, &req1stpty, NULL, arg)); 589 } 590 591 case DDI_DMA_IOPB_ALLOC: /* get contiguous DMA-able memory */ 592 case DDI_DMA_SMEM_ALLOC: 593 if (!offp) { 594 defalt = ISA_dma_limits; 595 offp = (off_t *)&defalt; 596 } 597 /*FALLTHROUGH*/ 598 default: 599 rval = ddi_dma_mctl(dip, rdip, handle, request, offp, 600 lenp, objp, flags); 601 } 602 return (rval); 603 } 604 605 /* 606 * Check if driver should be treated as an old pre 2.6 driver 607 */ 608 static int 609 old_driver(dev_info_t *dip) 610 { 611 extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */ 612 613 if (ndi_dev_is_persistent_node(dip)) { 614 if (ignore_hardware_nodes) 615 return (1); 616 if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 617 "ignore-hardware-nodes", -1) != -1) 618 return (1); 619 } 620 return (0); 621 } 622 623 typedef struct { 624 uint32_t phys_hi; 625 uint32_t phys_lo; 626 uint32_t size; 627 } isa_regs_t; 628 629 /* 630 * Return non-zero if device in tree is a PnP isa device 631 */ 632 static int 633 is_pnpisa(dev_info_t *dip) 634 { 635 isa_regs_t *isa_regs; 636 int proplen, pnpisa; 637 638 if (ndi_dev_is_persistent_node(dip) == 0) 639 return (0); 640 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 641 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 642 return (0); 643 } 644 pnpisa = isa_regs[0].phys_hi & 0x80000000; 645 /* 646 * free the memory allocated by ddi_getlongprop(). 647 */ 648 kmem_free(isa_regs, proplen); 649 if (pnpisa) 650 return (1); 651 else 652 return (0); 653 } 654 655 /*ARGSUSED*/ 656 static int 657 isa_ctlops(dev_info_t *dip, dev_info_t *rdip, 658 ddi_ctl_enum_t ctlop, void *arg, void *result) 659 { 660 int rn; 661 struct ddi_parent_private_data *pdp; 662 663 switch (ctlop) { 664 case DDI_CTLOPS_REPORTDEV: 665 if (rdip == (dev_info_t *)0) 666 return (DDI_FAILURE); 667 cmn_err(CE_CONT, "?ISA-device: %s%d\n", 668 ddi_driver_name(rdip), ddi_get_instance(rdip)); 669 return (DDI_SUCCESS); 670 671 case DDI_CTLOPS_INITCHILD: 672 /* 673 * older drivers aren't expecting the "standard" device 674 * node format used by the hardware nodes. these drivers 675 * only expect their own properties set in their driver.conf 676 * files. so they tell us not to call them with hardware 677 * nodes by setting the property "ignore-hardware-nodes". 678 */ 679 if (old_driver((dev_info_t *)arg)) { 680 return (DDI_NOT_WELL_FORMED); 681 } 682 683 return (isa_initchild((dev_info_t *)arg)); 684 685 case DDI_CTLOPS_UNINITCHILD: 686 impl_ddi_sunbus_removechild((dev_info_t *)arg); 687 return (DDI_SUCCESS); 688 689 case DDI_CTLOPS_SIDDEV: 690 /* 691 * All ISA devices need to do confirming probes 692 * unless they are PnP ISA. 693 */ 694 if (is_pnpisa(dip)) 695 return (DDI_SUCCESS); 696 else 697 return (DDI_FAILURE); 698 699 case DDI_CTLOPS_REGSIZE: 700 case DDI_CTLOPS_NREGS: 701 if (rdip == (dev_info_t *)0) 702 return (DDI_FAILURE); 703 704 if ((pdp = ddi_get_parent_data(rdip)) == NULL) 705 return (DDI_FAILURE); 706 707 if (ctlop == DDI_CTLOPS_NREGS) { 708 *(int *)result = pdp->par_nreg; 709 } else { 710 rn = *(int *)arg; 711 if (rn >= pdp->par_nreg) 712 return (DDI_FAILURE); 713 *(off_t *)result = (off_t)pdp->par_reg[rn].regspec_size; 714 } 715 return (DDI_SUCCESS); 716 717 case DDI_CTLOPS_ATTACH: 718 case DDI_CTLOPS_DETACH: 719 case DDI_CTLOPS_PEEK: 720 case DDI_CTLOPS_POKE: 721 return (DDI_FAILURE); 722 723 default: 724 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 725 } 726 } 727 728 static struct intrspec * 729 isa_get_ispec(dev_info_t *rdip, int inum) 730 { 731 struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip); 732 733 /* Validate the interrupt number */ 734 if (inum >= pdp->par_nintr) 735 return (NULL); 736 737 /* Get the interrupt structure pointer and return that */ 738 return ((struct intrspec *)&pdp->par_intr[inum]); 739 } 740 741 static int 742 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 743 ddi_intr_handle_impl_t *hdlp, void *result) 744 { 745 struct intrspec *ispec; 746 747 if (pseudo_isa) 748 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 749 750 751 /* Process the interrupt operation */ 752 switch (intr_op) { 753 case DDI_INTROP_GETCAP: 754 /* First check with pcplusmp */ 755 if (psm_intr_ops == NULL) 756 return (DDI_FAILURE); 757 758 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) { 759 *(int *)result = 0; 760 return (DDI_FAILURE); 761 } 762 break; 763 case DDI_INTROP_SETCAP: 764 if (psm_intr_ops == NULL) 765 return (DDI_FAILURE); 766 767 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) 768 return (DDI_FAILURE); 769 break; 770 case DDI_INTROP_ALLOC: 771 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 772 return (DDI_FAILURE); 773 hdlp->ih_pri = ispec->intrspec_pri; 774 *(int *)result = hdlp->ih_scratch1; 775 break; 776 case DDI_INTROP_FREE: 777 break; 778 case DDI_INTROP_GETPRI: 779 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 780 return (DDI_FAILURE); 781 *(int *)result = ispec->intrspec_pri; 782 break; 783 case DDI_INTROP_SETPRI: 784 /* Validate the interrupt priority passed to us */ 785 if (*(int *)result > LOCK_LEVEL) 786 return (DDI_FAILURE); 787 788 /* Ensure that PSM is all initialized and ispec is ok */ 789 if ((psm_intr_ops == NULL) || 790 ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)) 791 return (DDI_FAILURE); 792 793 /* update the ispec with the new priority */ 794 ispec->intrspec_pri = *(int *)result; 795 break; 796 case DDI_INTROP_ADDISR: 797 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 798 return (DDI_FAILURE); 799 ispec->intrspec_func = hdlp->ih_cb_func; 800 break; 801 case DDI_INTROP_REMISR: 802 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 803 return (DDI_FAILURE); 804 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 805 return (DDI_FAILURE); 806 ispec->intrspec_func = (uint_t (*)()) 0; 807 break; 808 case DDI_INTROP_ENABLE: 809 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 810 return (DDI_FAILURE); 811 812 /* Call psmi to translate irq with the dip */ 813 if (psm_intr_ops == NULL) 814 return (DDI_FAILURE); 815 816 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 817 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, 818 (int *)&hdlp->ih_vector); 819 820 /* Add the interrupt handler */ 821 if (!add_avintr((void *)hdlp, ispec->intrspec_pri, 822 hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector, 823 hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, NULL, rdip)) 824 return (DDI_FAILURE); 825 break; 826 case DDI_INTROP_DISABLE: 827 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 828 return (DDI_FAILURE); 829 830 /* Call psm_ops() to translate irq with the dip */ 831 if (psm_intr_ops == NULL) 832 return (DDI_FAILURE); 833 834 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 835 (void) (*psm_intr_ops)(rdip, hdlp, 836 PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector); 837 838 /* Remove the interrupt handler */ 839 rem_avintr((void *)hdlp, ispec->intrspec_pri, 840 hdlp->ih_cb_func, hdlp->ih_vector); 841 break; 842 case DDI_INTROP_SETMASK: 843 if (psm_intr_ops == NULL) 844 return (DDI_FAILURE); 845 846 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL)) 847 return (DDI_FAILURE); 848 break; 849 case DDI_INTROP_CLRMASK: 850 if (psm_intr_ops == NULL) 851 return (DDI_FAILURE); 852 853 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL)) 854 return (DDI_FAILURE); 855 break; 856 case DDI_INTROP_GETPENDING: 857 if (psm_intr_ops == NULL) 858 return (DDI_FAILURE); 859 860 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING, 861 result)) { 862 *(int *)result = 0; 863 return (DDI_FAILURE); 864 } 865 break; 866 case DDI_INTROP_NAVAIL: 867 case DDI_INTROP_NINTRS: 868 *(int *)result = i_ddi_get_intx_nintrs(rdip); 869 if (*(int *)result == 0) { 870 return (DDI_FAILURE); 871 } 872 break; 873 case DDI_INTROP_SUPPORTED_TYPES: 874 *(int *)result = DDI_INTR_TYPE_FIXED; /* Always ... */ 875 break; 876 default: 877 return (DDI_FAILURE); 878 } 879 880 return (DDI_SUCCESS); 881 } 882 883 static void 884 isa_vendor(uint32_t id, char *vendor) 885 { 886 vendor[0] = '@' + ((id >> 26) & 0x1f); 887 vendor[1] = '@' + ((id >> 21) & 0x1f); 888 vendor[2] = '@' + ((id >> 16) & 0x1f); 889 vendor[3] = 0; 890 } 891 892 /* 893 * Name a child 894 */ 895 static int 896 isa_name_child(dev_info_t *child, char *name, int namelen) 897 { 898 char vendor[8]; 899 int device; 900 uint32_t serial; 901 int func; 902 int bustype; 903 uint32_t base; 904 int proplen; 905 int pnpisa = 0; 906 isa_regs_t *isa_regs; 907 908 void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **); 909 910 /* 911 * older drivers aren't expecting the "standard" device 912 * node format used by the hardware nodes. these drivers 913 * only expect their own properties set in their driver.conf 914 * files. so they tell us not to call them with hardware 915 * nodes by setting the property "ignore-hardware-nodes". 916 */ 917 if (old_driver(child)) 918 return (DDI_FAILURE); 919 920 /* 921 * Fill in parent-private data 922 */ 923 if (ddi_get_parent_data(child) == NULL) { 924 struct ddi_parent_private_data *pdptr; 925 make_ddi_ppd(child, &pdptr); 926 ddi_set_parent_data(child, pdptr); 927 } 928 929 if (ndi_dev_is_persistent_node(child) == 0) { 930 /* 931 * For .conf nodes, generate name from parent private data 932 */ 933 name[0] = '\0'; 934 if (sparc_pd_getnreg(child) > 0) { 935 (void) snprintf(name, namelen, "%x,%x", 936 (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype, 937 (uint_t)sparc_pd_getreg(child, 0)->regspec_addr); 938 } 939 return (DDI_SUCCESS); 940 } 941 942 /* 943 * For hw nodes, look up "reg" property 944 */ 945 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 946 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 947 return (DDI_FAILURE); 948 } 949 950 /* 951 * extract the device identifications 952 */ 953 pnpisa = isa_regs[0].phys_hi & 0x80000000; 954 if (pnpisa) { 955 isa_vendor(isa_regs[0].phys_hi, vendor); 956 device = isa_regs[0].phys_hi & 0xffff; 957 serial = isa_regs[0].phys_lo; 958 func = (isa_regs[0].size >> 24) & 0xff; 959 if (func != 0) 960 (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x", 961 vendor, device, serial, func); 962 else 963 (void) snprintf(name, namelen, "pnp%s,%04x,%x", 964 vendor, device, serial); 965 } else { 966 bustype = isa_regs[0].phys_hi; 967 base = isa_regs[0].phys_lo; 968 (void) sprintf(name, "%x,%x", bustype, base); 969 } 970 971 /* 972 * free the memory allocated by ddi_getlongprop(). 973 */ 974 kmem_free(isa_regs, proplen); 975 976 return (DDI_SUCCESS); 977 } 978 979 static int 980 isa_initchild(dev_info_t *child) 981 { 982 char name[80]; 983 984 if (isa_name_child(child, name, 80) != DDI_SUCCESS) 985 return (DDI_FAILURE); 986 ddi_set_name_addr(child, name); 987 988 if (ndi_dev_is_persistent_node(child) != 0) 989 return (DDI_SUCCESS); 990 991 /* 992 * This is a .conf node, try merge properties onto a 993 * hw node with the same name. 994 */ 995 if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) { 996 /* 997 * Return failure to remove node 998 */ 999 impl_ddi_sunbus_removechild(child); 1000 return (DDI_FAILURE); 1001 } 1002 /* 1003 * Cannot merge node, permit pseudo children 1004 */ 1005 return (DDI_SUCCESS); 1006 } 1007 1008 /* 1009 * called when ACPI enumeration is not used 1010 */ 1011 static void 1012 add_known_used_resources(void) 1013 { 1014 /* needs to be in increasing order */ 1015 int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc}; 1016 int dma[] = {0x2}; 1017 int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10, 1018 0x778, 0x4}; 1019 dev_info_t *usedrdip; 1020 1021 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 1022 1023 if (usedrdip == NULL) { 1024 (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 1025 (pnode_t)DEVI_SID_NODEID, &usedrdip); 1026 } 1027 1028 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1029 "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int))); 1030 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1031 "io-space", (int *)io, (int)(sizeof (io) / sizeof (int))); 1032 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1033 "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int))); 1034 (void) ndi_devi_bind_driver(usedrdip, 0); 1035 1036 } 1037 1038 static void 1039 isa_alloc_nodes(dev_info_t *isa_dip) 1040 { 1041 static int alloced = 0; 1042 int circ, i; 1043 dev_info_t *xdip; 1044 1045 /* hard coded isa stuff */ 1046 struct regspec asy_regs[] = { 1047 {1, 0x3f8, 0x8}, 1048 {1, 0x2f8, 0x8} 1049 }; 1050 int asy_intrs[] = {0x4, 0x3}; 1051 1052 struct regspec i8042_regs[] = { 1053 {1, 0x60, 0x1}, 1054 {1, 0x64, 0x1} 1055 }; 1056 int i8042_intrs[] = {0x1, 0xc}; 1057 char *acpi_prop; 1058 int acpi_enum = 1; /* ACPI is default to be on */ 1059 1060 if (alloced) 1061 return; 1062 1063 ndi_devi_enter(isa_dip, &circ); 1064 if (alloced) { /* just in case we are multi-threaded */ 1065 ndi_devi_exit(isa_dip, circ); 1066 return; 1067 } 1068 alloced = 1; 1069 1070 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1071 DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 1072 acpi_enum = strcmp("off", acpi_prop); 1073 ddi_prop_free(acpi_prop); 1074 } 1075 1076 if (acpi_enum) { 1077 if (acpi_isa_device_enum(isa_dip)) { 1078 ndi_devi_exit(isa_dip, circ); 1079 if (isa_resource_setup() != NDI_SUCCESS) { 1080 cmn_err(CE_WARN, "isa nexus: isa " 1081 "resource setup failed"); 1082 } 1083 1084 /* serial ports? */ 1085 enumerate_BIOS_serial(isa_dip); 1086 1087 /* adjust parallel port size */ 1088 adjust_prtsz(isa_dip); 1089 return; 1090 } 1091 cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS"); 1092 } 1093 cmn_err(CE_NOTE, "!ACPI is off"); 1094 1095 /* serial ports */ 1096 for (i = 0; i < 2; i++) { 1097 #if defined(__xpv) 1098 /* 1099 * the hypervisor may be reserving the serial ports for console 1100 * and/or debug use. Probe the irqs to see if they are 1101 * available. 1102 */ 1103 if (ec_probe_pirq(asy_intrs[i]) == 0) 1104 continue; /* in use */ 1105 #endif 1106 ndi_devi_alloc_sleep(isa_dip, "asy", 1107 (pnode_t)DEVI_SID_NODEID, &xdip); 1108 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1109 "reg", (int *)&asy_regs[i], 3); 1110 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1111 "interrupts", asy_intrs[i]); 1112 (void) ndi_devi_bind_driver(xdip, 0); 1113 } 1114 1115 /* i8042 node */ 1116 ndi_devi_alloc_sleep(isa_dip, "i8042", 1117 (pnode_t)DEVI_SID_NODEID, &xdip); 1118 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1119 "reg", (int *)i8042_regs, 6); 1120 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1121 "interrupts", (int *)i8042_intrs, 2); 1122 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1123 "unit-address", "1,60"); 1124 (void) ndi_devi_bind_driver(xdip, 0); 1125 1126 add_known_used_resources(); 1127 1128 ndi_devi_exit(isa_dip, circ); 1129 1130 } 1131 1132 /* 1133 * On some machines, serial port 2 isn't listed in the ACPI table. 1134 * This function goes through the BIOS data area and makes sure all 1135 * the serial ports there are in the dev_info tree. If any are missing, 1136 * this function will add them. 1137 */ 1138 1139 static int num_BIOS_serial = 2; /* number of BIOS serial ports to look at */ 1140 1141 static void 1142 enumerate_BIOS_serial(dev_info_t *isa_dip) 1143 { 1144 ushort_t *bios_data; 1145 int i; 1146 dev_info_t *xdip; 1147 int found; 1148 int ret; 1149 struct regspec *tmpregs; 1150 int tmpregs_len; 1151 static struct regspec tmp_asy_regs[] = { 1152 {1, 0x3f8, 0x8}, 1153 }; 1154 static int default_asy_intrs[] = { 4, 3, 4, 3 }; 1155 static size_t size = 4; 1156 1157 /* 1158 * The first four 2-byte quantities of the BIOS data area contain 1159 * the base I/O addresses of the first four serial ports. 1160 */ 1161 bios_data = (ushort_t *)psm_map_new((paddr_t)BIOS_DATA_AREA, size, 1162 PSM_PROT_READ); 1163 for (i = 0; i < num_BIOS_serial; i++) { 1164 if (bios_data[i] == 0) { 1165 /* no COM[i]: port */ 1166 continue; 1167 } 1168 1169 /* Look for it in the dev_info tree */ 1170 found = 0; 1171 for (xdip = ddi_get_child(isa_dip); xdip != NULL; 1172 xdip = ddi_get_next_sibling(xdip)) { 1173 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) { 1174 /* skip non asy */ 1175 continue; 1176 } 1177 1178 /* Match by addr */ 1179 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip, 1180 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs, 1181 (uint_t *)&tmpregs_len); 1182 if (ret != DDI_PROP_SUCCESS) { 1183 /* error */ 1184 continue; 1185 } 1186 1187 if (tmpregs->regspec_addr == bios_data[i]) 1188 found = 1; 1189 /* 1190 * Free the memory allocated by 1191 * ddi_prop_lookup_int_array(). 1192 */ 1193 ddi_prop_free(tmpregs); 1194 1195 } 1196 1197 /* If not found, then add it */ 1198 if (!found) { 1199 ndi_devi_alloc_sleep(isa_dip, "asy", 1200 (pnode_t)DEVI_SID_NODEID, &xdip); 1201 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1202 "compatible", "PNP0500"); 1203 /* This should be gotten from master file: */ 1204 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1205 "model", "Standard PC COM port"); 1206 tmp_asy_regs[0].regspec_addr = bios_data[i]; 1207 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1208 "reg", (int *)&tmp_asy_regs[0], 3); 1209 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1210 "interrupts", default_asy_intrs[i]); 1211 (void) ndi_devi_bind_driver(xdip, 0); 1212 1213 ASSERT(isa_extra_count < MAX_EXTRA_RESOURCE); 1214 bcopy(tmp_asy_regs, 1215 isa_extra_resource + isa_extra_count, 1216 sizeof (struct regspec)); 1217 isa_extra_count++; 1218 } 1219 } 1220 #if defined(__xpv) 1221 /* 1222 * Check each serial port to see if it is in use by the hypervisor. 1223 * If it is in use, then remove the node from the device tree. 1224 */ 1225 i = 0; 1226 for (xdip = ddi_get_child(isa_dip); xdip != NULL; ) { 1227 int asy_intr; 1228 dev_info_t *curdip; 1229 1230 curdip = xdip; 1231 xdip = ddi_get_next_sibling(xdip); 1232 if (strncmp(ddi_node_name(curdip), "asy", 3) != 0) { 1233 /* skip non asy */ 1234 continue; 1235 } 1236 /* 1237 * Check if the hypervisor is using the serial port by probing 1238 * the irq and if it is using it remove the node 1239 * from the device tree 1240 */ 1241 asy_intr = ddi_prop_get_int(DDI_DEV_T_ANY, curdip, 1242 DDI_PROP_DONTPASS, "interrupts", -1); 1243 if (asy_intr == -1) { 1244 /* error */ 1245 continue; 1246 } 1247 1248 if (ec_probe_pirq(asy_intr)) { 1249 continue; 1250 } 1251 ret = ndi_devi_free(curdip); 1252 if (ret != DDI_SUCCESS) 1253 cmn_err(CE_WARN, 1254 "could not remove asy%d node", i); 1255 else 1256 cmn_err(CE_NOTE, "!asy%d unavailable, reserved" 1257 " to hypervisor", i); 1258 i++; 1259 } 1260 #endif /* __xpv */ 1261 1262 psm_unmap((caddr_t)bios_data, size); 1263 } 1264 1265 /* 1266 * Some machine comes with an illegal parallel port size of 3 1267 * bytes in ACPI, even parallel port mode is ECP. 1268 */ 1269 #define DEFAULT_PRT_SIZE 8 1270 static void 1271 adjust_prtsz(dev_info_t *isa_dip) 1272 { 1273 dev_info_t *cdip; 1274 struct regspec *regs_p, *extreg_p; 1275 int regs_len, nreg, i; 1276 char *name; 1277 1278 for (cdip = ddi_get_child(isa_dip); cdip != NULL; 1279 cdip = ddi_get_next_sibling(cdip)) { 1280 name = ddi_node_name(cdip); 1281 if ((strncmp(name, "lp", 2) != 0) || (strnlen(name, 3) != 2)) 1282 continue; /* skip non parallel */ 1283 1284 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, 1285 DDI_PROP_DONTPASS, "reg", (int **)®s_p, 1286 (uint_t *)®s_len) != DDI_PROP_SUCCESS) 1287 continue; 1288 1289 nreg = regs_len / (sizeof (struct regspec) / sizeof (int)); 1290 for (i = 0; i < nreg; i++) { 1291 if (regs_p[i].regspec_size == DEFAULT_PRT_SIZE) 1292 continue; 1293 1294 ASSERT(isa_extra_count < MAX_EXTRA_RESOURCE); 1295 extreg_p = &isa_extra_resource[isa_extra_count++]; 1296 extreg_p->regspec_bustype = ISA_ADDR_IO; 1297 extreg_p->regspec_addr = regs_p[i].regspec_addr; 1298 extreg_p->regspec_size = DEFAULT_PRT_SIZE; 1299 } 1300 1301 ddi_prop_free(regs_p); 1302 } 1303 } 1304