1 /*- 2 * Copyright (c) 2006 Marcel Moolenaar 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 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/bus.h> 34 #include <sys/conf.h> 35 #include <sys/malloc.h> 36 #include <sys/mutex.h> 37 38 #include <machine/bus.h> 39 #include <machine/resource.h> 40 #include <sys/rman.h> 41 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 45 #include <dev/puc/puc_bus.h> 46 #include <dev/puc/puc_cfg.h> 47 #include <dev/puc/puc_bfe.h> 48 49 #define PUC_ISRCCNT 5 50 51 struct puc_port { 52 struct puc_bar *p_bar; 53 struct resource *p_rres; 54 struct resource *p_ires; 55 device_t p_dev; 56 int p_nr; 57 int p_type; 58 int p_rclk; 59 60 int p_hasintr:1; 61 62 serdev_intr_t *p_ihsrc[PUC_ISRCCNT]; 63 void *p_iharg; 64 65 int p_ipend; 66 }; 67 68 devclass_t puc_devclass; 69 const char puc_driver_name[] = "puc"; 70 71 MALLOC_DEFINE(M_PUC, "PUC", "PUC driver"); 72 73 struct puc_bar * 74 puc_get_bar(struct puc_softc *sc, int rid) 75 { 76 struct puc_bar *bar; 77 struct rman *rm; 78 u_long end, start; 79 int error, i; 80 81 /* Find the BAR entry with the given RID. */ 82 i = 0; 83 while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid) 84 i++; 85 if (i < PUC_PCI_BARS) 86 return (&sc->sc_bar[i]); 87 88 /* Not found. If we're looking for an unused entry, return NULL. */ 89 if (rid == -1) 90 return (NULL); 91 92 /* Get an unused entry for us to fill. */ 93 bar = puc_get_bar(sc, -1); 94 if (bar == NULL) 95 return (NULL); 96 bar->b_rid = rid; 97 bar->b_type = SYS_RES_IOPORT; 98 bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type, 99 &bar->b_rid, RF_ACTIVE); 100 if (bar->b_res == NULL) { 101 bar->b_rid = rid; 102 bar->b_type = SYS_RES_MEMORY; 103 bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type, 104 &bar->b_rid, RF_ACTIVE); 105 if (bar->b_res == NULL) { 106 bar->b_rid = -1; 107 return (NULL); 108 } 109 } 110 111 /* Update our managed space. */ 112 rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem; 113 start = rman_get_start(bar->b_res); 114 end = rman_get_end(bar->b_res); 115 error = rman_manage_region(rm, start, end); 116 if (error) { 117 bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid, 118 bar->b_res); 119 bar->b_res = NULL; 120 bar->b_rid = -1; 121 bar = NULL; 122 } 123 124 return (bar); 125 } 126 127 static int 128 puc_intr(void *arg) 129 { 130 struct puc_port *port; 131 struct puc_softc *sc = arg; 132 u_long dev, devs; 133 int i, idx, ipend, isrc; 134 uint8_t ilr; 135 136 devs = sc->sc_serdevs; 137 if (sc->sc_ilr == PUC_ILR_DIGI) { 138 idx = 0; 139 while (devs & (0xfful << idx)) { 140 ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7); 141 devs &= ~0ul ^ ((u_long)ilr << idx); 142 idx += 8; 143 } 144 } else if (sc->sc_ilr == PUC_ILR_QUATECH) { 145 /* 146 * Don't trust the value if it's the same as the option 147 * register. It may mean that the ILR is not active and 148 * we're reading the option register instead. This may 149 * lead to false positives on 8-port boards. 150 */ 151 ilr = bus_read_1(sc->sc_port[0].p_rres, 7); 152 if (ilr != (sc->sc_cfg_data & 0xff)) 153 devs &= (u_long)ilr; 154 } 155 156 ipend = 0; 157 idx = 0, dev = 1UL; 158 while (devs != 0UL) { 159 while ((devs & dev) == 0UL) 160 idx++, dev <<= 1; 161 devs &= ~dev; 162 port = &sc->sc_port[idx]; 163 port->p_ipend = SERDEV_IPEND(port->p_dev); 164 ipend |= port->p_ipend; 165 } 166 167 i = 0, isrc = SER_INT_OVERRUN; 168 while (ipend) { 169 while (i < PUC_ISRCCNT && !(ipend & isrc)) 170 i++, isrc <<= 1; 171 KASSERT(i < PUC_ISRCCNT, ("%s", __func__)); 172 ipend &= ~isrc; 173 idx = 0, dev = 1UL; 174 devs = sc->sc_serdevs; 175 while (devs != 0UL) { 176 while ((devs & dev) == 0UL) 177 idx++, dev <<= 1; 178 devs &= ~dev; 179 port = &sc->sc_port[idx]; 180 if (!(port->p_ipend & isrc)) 181 continue; 182 if (port->p_ihsrc[i] != NULL) 183 (*port->p_ihsrc[i])(port->p_iharg); 184 } 185 return (FILTER_HANDLED); 186 } 187 return (FILTER_STRAY); 188 } 189 190 int 191 puc_bfe_attach(device_t dev) 192 { 193 char buffer[64]; 194 struct puc_bar *bar; 195 struct puc_port *port; 196 struct puc_softc *sc; 197 struct rman *rm; 198 intptr_t res; 199 bus_addr_t ofs, start; 200 bus_size_t size; 201 bus_space_handle_t bsh; 202 bus_space_tag_t bst; 203 int error, idx; 204 205 sc = device_get_softc(dev); 206 207 for (idx = 0; idx < PUC_PCI_BARS; idx++) 208 sc->sc_bar[idx].b_rid = -1; 209 210 do { 211 sc->sc_ioport.rm_type = RMAN_ARRAY; 212 error = rman_init(&sc->sc_ioport); 213 if (!error) { 214 sc->sc_iomem.rm_type = RMAN_ARRAY; 215 error = rman_init(&sc->sc_iomem); 216 if (!error) { 217 sc->sc_irq.rm_type = RMAN_ARRAY; 218 error = rman_init(&sc->sc_irq); 219 if (!error) 220 break; 221 rman_fini(&sc->sc_iomem); 222 } 223 rman_fini(&sc->sc_ioport); 224 } 225 return (error); 226 } while (0); 227 228 snprintf(buffer, sizeof(buffer), "%s I/O port mapping", 229 device_get_nameunit(dev)); 230 sc->sc_ioport.rm_descr = strdup(buffer, M_PUC); 231 snprintf(buffer, sizeof(buffer), "%s I/O memory mapping", 232 device_get_nameunit(dev)); 233 sc->sc_iomem.rm_descr = strdup(buffer, M_PUC); 234 snprintf(buffer, sizeof(buffer), "%s port numbers", 235 device_get_nameunit(dev)); 236 sc->sc_irq.rm_descr = strdup(buffer, M_PUC); 237 238 error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res); 239 KASSERT(error == 0, ("%s %d", __func__, __LINE__)); 240 sc->sc_nports = (int)res; 241 sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port), 242 M_PUC, M_WAITOK|M_ZERO); 243 244 error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports); 245 if (error) 246 goto fail; 247 248 error = puc_config(sc, PUC_CFG_SETUP, 0, &res); 249 if (error) 250 goto fail; 251 252 for (idx = 0; idx < sc->sc_nports; idx++) { 253 port = &sc->sc_port[idx]; 254 port->p_nr = idx + 1; 255 error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res); 256 if (error) 257 goto fail; 258 port->p_type = res; 259 error = puc_config(sc, PUC_CFG_GET_RID, idx, &res); 260 if (error) 261 goto fail; 262 bar = puc_get_bar(sc, res); 263 if (bar == NULL) { 264 error = ENXIO; 265 goto fail; 266 } 267 port->p_bar = bar; 268 start = rman_get_start(bar->b_res); 269 error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res); 270 if (error) 271 goto fail; 272 ofs = res; 273 error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res); 274 if (error) 275 goto fail; 276 size = res; 277 rm = (bar->b_type == SYS_RES_IOPORT) 278 ? &sc->sc_ioport: &sc->sc_iomem; 279 port->p_rres = rman_reserve_resource(rm, start + ofs, 280 start + ofs + size - 1, size, 0, NULL); 281 if (port->p_rres != NULL) { 282 bsh = rman_get_bushandle(bar->b_res); 283 bst = rman_get_bustag(bar->b_res); 284 bus_space_subregion(bst, bsh, ofs, size, &bsh); 285 rman_set_bushandle(port->p_rres, bsh); 286 rman_set_bustag(port->p_rres, bst); 287 } 288 port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr, 289 port->p_nr, 1, 0, NULL); 290 if (port->p_ires == NULL) { 291 error = ENXIO; 292 goto fail; 293 } 294 error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res); 295 if (error) 296 goto fail; 297 port->p_rclk = res; 298 299 port->p_dev = device_add_child(dev, NULL, -1); 300 if (port->p_dev != NULL) 301 device_set_ivars(port->p_dev, (void *)port); 302 } 303 304 error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res); 305 if (error) 306 goto fail; 307 sc->sc_ilr = res; 308 if (bootverbose && sc->sc_ilr != 0) 309 device_printf(dev, "using interrupt latch register\n"); 310 311 sc->sc_irid = 0; 312 sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, 313 RF_ACTIVE|RF_SHAREABLE); 314 if (sc->sc_ires != NULL) { 315 error = bus_setup_intr(dev, sc->sc_ires, 316 INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie); 317 if (error) 318 error = bus_setup_intr(dev, sc->sc_ires, 319 INTR_TYPE_TTY | INTR_MPSAFE, NULL, 320 (driver_intr_t *)puc_intr, sc, &sc->sc_icookie); 321 else 322 sc->sc_fastintr = 1; 323 324 if (error) { 325 device_printf(dev, "could not activate interrupt\n"); 326 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 327 sc->sc_ires); 328 sc->sc_ires = NULL; 329 } 330 } 331 if (sc->sc_ires == NULL) { 332 /* XXX no interrupt resource. Force polled mode. */ 333 sc->sc_polled = 1; 334 } 335 336 /* Probe and attach our children. */ 337 for (idx = 0; idx < sc->sc_nports; idx++) { 338 port = &sc->sc_port[idx]; 339 if (port->p_dev == NULL) 340 continue; 341 error = device_probe_and_attach(port->p_dev); 342 if (error) { 343 device_delete_child(dev, port->p_dev); 344 port->p_dev = NULL; 345 } 346 } 347 348 /* 349 * If there are no serdev devices, then our interrupt handler 350 * will do nothing. Tear it down. 351 */ 352 if (sc->sc_serdevs == 0UL) 353 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); 354 355 return (0); 356 357 fail: 358 for (idx = 0; idx < sc->sc_nports; idx++) { 359 port = &sc->sc_port[idx]; 360 if (port->p_dev != NULL) 361 device_delete_child(dev, port->p_dev); 362 if (port->p_rres != NULL) 363 rman_release_resource(port->p_rres); 364 if (port->p_ires != NULL) 365 rman_release_resource(port->p_ires); 366 } 367 for (idx = 0; idx < PUC_PCI_BARS; idx++) { 368 bar = &sc->sc_bar[idx]; 369 if (bar->b_res != NULL) 370 bus_release_resource(sc->sc_dev, bar->b_type, 371 bar->b_rid, bar->b_res); 372 } 373 rman_fini(&sc->sc_irq); 374 free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC); 375 rman_fini(&sc->sc_iomem); 376 free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC); 377 rman_fini(&sc->sc_ioport); 378 free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC); 379 free(sc->sc_port, M_PUC); 380 return (error); 381 } 382 383 int 384 puc_bfe_detach(device_t dev) 385 { 386 struct puc_bar *bar; 387 struct puc_port *port; 388 struct puc_softc *sc; 389 int error, idx; 390 391 sc = device_get_softc(dev); 392 393 /* Detach our children. */ 394 error = 0; 395 for (idx = 0; idx < sc->sc_nports; idx++) { 396 port = &sc->sc_port[idx]; 397 if (port->p_dev == NULL) 398 continue; 399 if (device_detach(port->p_dev) == 0) { 400 device_delete_child(dev, port->p_dev); 401 if (port->p_rres != NULL) 402 rman_release_resource(port->p_rres); 403 if (port->p_ires != NULL) 404 rman_release_resource(port->p_ires); 405 } else 406 error = ENXIO; 407 } 408 if (error) 409 return (error); 410 411 if (sc->sc_serdevs != 0UL) 412 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); 413 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); 414 415 for (idx = 0; idx < PUC_PCI_BARS; idx++) { 416 bar = &sc->sc_bar[idx]; 417 if (bar->b_res != NULL) 418 bus_release_resource(sc->sc_dev, bar->b_type, 419 bar->b_rid, bar->b_res); 420 } 421 422 rman_fini(&sc->sc_irq); 423 free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC); 424 rman_fini(&sc->sc_iomem); 425 free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC); 426 rman_fini(&sc->sc_ioport); 427 free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC); 428 free(sc->sc_port, M_PUC); 429 return (0); 430 } 431 432 int 433 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg) 434 { 435 struct puc_softc *sc; 436 intptr_t res; 437 int error; 438 439 sc = device_get_softc(dev); 440 sc->sc_dev = dev; 441 sc->sc_cfg = cfg; 442 443 /* We don't attach to single-port serial cards. */ 444 if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P) 445 return (EDOOFUS); 446 error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res); 447 if (error) 448 return (error); 449 error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res); 450 if (error) 451 return (error); 452 if (res != 0) 453 device_set_desc(dev, (const char *)res); 454 return (BUS_PROBE_DEFAULT); 455 } 456 457 struct resource * 458 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid, 459 u_long start, u_long end, u_long count, u_int flags) 460 { 461 struct puc_port *port; 462 struct resource *res; 463 device_t assigned, originator; 464 int error; 465 466 /* Get our immediate child. */ 467 originator = child; 468 while (child != NULL && device_get_parent(child) != dev) 469 child = device_get_parent(child); 470 if (child == NULL) 471 return (NULL); 472 473 port = device_get_ivars(child); 474 KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); 475 476 if (rid == NULL || *rid != 0) 477 return (NULL); 478 479 /* We only support default allocations. */ 480 if (start != 0UL || end != ~0UL) 481 return (NULL); 482 483 if (type == port->p_bar->b_type) 484 res = port->p_rres; 485 else if (type == SYS_RES_IRQ) 486 res = port->p_ires; 487 else 488 return (NULL); 489 490 if (res == NULL) 491 return (NULL); 492 493 assigned = rman_get_device(res); 494 if (assigned == NULL) /* Not allocated */ 495 rman_set_device(res, originator); 496 else if (assigned != originator) 497 return (NULL); 498 499 if (flags & RF_ACTIVE) { 500 error = rman_activate_resource(res); 501 if (error) { 502 if (assigned == NULL) 503 rman_set_device(res, NULL); 504 return (NULL); 505 } 506 } 507 508 return (res); 509 } 510 511 int 512 puc_bus_release_resource(device_t dev, device_t child, int type, int rid, 513 struct resource *res) 514 { 515 struct puc_port *port; 516 device_t originator; 517 518 /* Get our immediate child. */ 519 originator = child; 520 while (child != NULL && device_get_parent(child) != dev) 521 child = device_get_parent(child); 522 if (child == NULL) 523 return (EINVAL); 524 525 port = device_get_ivars(child); 526 KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); 527 528 if (rid != 0 || res == NULL) 529 return (EINVAL); 530 531 if (type == port->p_bar->b_type) { 532 if (res != port->p_rres) 533 return (EINVAL); 534 } else if (type == SYS_RES_IRQ) { 535 if (res != port->p_ires) 536 return (EINVAL); 537 if (port->p_hasintr) 538 return (EBUSY); 539 } else 540 return (EINVAL); 541 542 if (rman_get_device(res) != originator) 543 return (ENXIO); 544 if (rman_get_flags(res) & RF_ACTIVE) 545 rman_deactivate_resource(res); 546 rman_set_device(res, NULL); 547 return (0); 548 } 549 550 int 551 puc_bus_get_resource(device_t dev, device_t child, int type, int rid, 552 u_long *startp, u_long *countp) 553 { 554 struct puc_port *port; 555 struct resource *res; 556 u_long start; 557 558 /* Get our immediate child. */ 559 while (child != NULL && device_get_parent(child) != dev) 560 child = device_get_parent(child); 561 if (child == NULL) 562 return (EINVAL); 563 564 port = device_get_ivars(child); 565 KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); 566 567 if (type == port->p_bar->b_type) 568 res = port->p_rres; 569 else if (type == SYS_RES_IRQ) 570 res = port->p_ires; 571 else 572 return (ENXIO); 573 574 if (rid != 0 || res == NULL) 575 return (ENXIO); 576 577 start = rman_get_start(res); 578 if (startp != NULL) 579 *startp = start; 580 if (countp != NULL) 581 *countp = rman_get_end(res) - start + 1; 582 return (0); 583 } 584 585 int 586 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res, 587 int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) 588 { 589 struct puc_port *port; 590 struct puc_softc *sc; 591 device_t originator; 592 int i, isrc, serdev; 593 594 sc = device_get_softc(dev); 595 596 /* Get our immediate child. */ 597 originator = child; 598 while (child != NULL && device_get_parent(child) != dev) 599 child = device_get_parent(child); 600 if (child == NULL) 601 return (EINVAL); 602 603 port = device_get_ivars(child); 604 KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); 605 606 if (cookiep == NULL || res != port->p_ires) 607 return (EINVAL); 608 /* We demand that serdev devices use filter_only interrupts. */ 609 if (ihand != NULL) 610 return (ENXIO); 611 if (rman_get_device(port->p_ires) != originator) 612 return (ENXIO); 613 614 /* 615 * Have non-serdev ports handled by the bus implementation. It 616 * supports multiple handlers for a single interrupt as it is, 617 * so we wouldn't add value if we did it ourselves. 618 */ 619 serdev = 0; 620 if (port->p_type == PUC_TYPE_SERIAL) { 621 i = 0, isrc = SER_INT_OVERRUN; 622 while (i < PUC_ISRCCNT) { 623 port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc); 624 if (port->p_ihsrc[i] != NULL) 625 serdev = 1; 626 i++, isrc <<= 1; 627 } 628 } 629 if (!serdev) 630 return (BUS_SETUP_INTR(device_get_parent(dev), originator, 631 sc->sc_ires, flags, filt, ihand, arg, cookiep)); 632 633 sc->sc_serdevs |= 1UL << (port->p_nr - 1); 634 635 port->p_hasintr = 1; 636 port->p_iharg = arg; 637 638 *cookiep = port; 639 return (0); 640 } 641 642 int 643 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res, 644 void *cookie) 645 { 646 struct puc_port *port; 647 struct puc_softc *sc; 648 device_t originator; 649 int i; 650 651 sc = device_get_softc(dev); 652 653 /* Get our immediate child. */ 654 originator = child; 655 while (child != NULL && device_get_parent(child) != dev) 656 child = device_get_parent(child); 657 if (child == NULL) 658 return (EINVAL); 659 660 port = device_get_ivars(child); 661 KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); 662 663 if (res != port->p_ires) 664 return (EINVAL); 665 if (rman_get_device(port->p_ires) != originator) 666 return (ENXIO); 667 668 if (!port->p_hasintr) 669 return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator, 670 sc->sc_ires, cookie)); 671 672 if (cookie != port) 673 return (EINVAL); 674 675 port->p_hasintr = 0; 676 port->p_iharg = NULL; 677 678 for (i = 0; i < PUC_ISRCCNT; i++) 679 port->p_ihsrc[i] = NULL; 680 681 return (0); 682 } 683 684 int 685 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 686 { 687 struct puc_port *port; 688 689 /* Get our immediate child. */ 690 while (child != NULL && device_get_parent(child) != dev) 691 child = device_get_parent(child); 692 if (child == NULL) 693 return (EINVAL); 694 695 port = device_get_ivars(child); 696 KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); 697 698 if (result == NULL) 699 return (EINVAL); 700 701 switch(index) { 702 case PUC_IVAR_CLOCK: 703 *result = port->p_rclk; 704 break; 705 case PUC_IVAR_TYPE: 706 *result = port->p_type; 707 break; 708 default: 709 return (ENOENT); 710 } 711 return (0); 712 } 713