pccard.c revision 55720
1/* $NetBSD: pcmcia.c,v 1.13 1998/12/24 04:51:59 marc Exp $ */ 2/* $FreeBSD: head/sys/dev/pccard/pccard.c 55720 2000-01-10 06:58:17Z imp $ */ 3 4/* 5 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Marc Horowitz. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/malloc.h> 36#include <sys/module.h> 37#include <sys/kernel.h> 38#include <sys/queue.h> 39#include <sys/types.h> 40 41#include <sys/bus.h> 42#include <machine/bus.h> 43#include <sys/rman.h> 44#include <machine/resource.h> 45 46#include <dev/pccard/pccardreg.h> 47#include <dev/pccard/pccardchip.h> 48#include <dev/pccard/pccardvar.h> 49 50#include "power_if.h" 51 52#define PCCARDDEBUG 53 54#ifdef PCCARDDEBUG 55int pccard_debug = 1; 56#define DPRINTF(arg) if (pccard_debug) printf arg 57#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 58int pccardintr_debug = 0; 59/* this is done this way to avoid doing lots of conditionals 60 at interrupt level. */ 61#define PCCARD_CARD_INTR (pccardintr_debug?pccard_card_intrdebug:pccard_card_intr) 62#else 63#define DPRINTF(arg) 64#define DEVPRINTF(arg) 65#define PCCARD_CARD_INTR (pccard_card_intr) 66#endif 67 68#ifdef PCCARDVERBOSE 69int pccard_verbose = 1; 70#else 71int pccard_verbose = 0; 72#endif 73 74int pccard_print(void *, const char *); 75 76int pccard_card_intr(void *); 77#ifdef PCCARDDEBUG 78int pccard_card_intrdebug(void *); 79#endif 80 81int 82pccard_ccr_read(pf, ccr) 83 struct pccard_function *pf; 84 int ccr; 85{ 86 return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 87 pf->pf_ccr_offset + ccr)); 88} 89 90void 91pccard_ccr_write(pf, ccr, val) 92 struct pccard_function *pf; 93 int ccr; 94 int val; 95{ 96 97 if ((pf->ccr_mask) & (1 << (ccr / 2))) { 98 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 99 pf->pf_ccr_offset + ccr, val); 100 } 101} 102 103int 104pccard_card_attach(device_t dev) 105{ 106 struct pccard_softc *sc = (struct pccard_softc *) 107 device_get_softc(dev); 108 struct pccard_function *pf; 109 int attached; 110 111 DEVPRINTF((dev, "pccard_card_attach\n")); 112 /* 113 * this is here so that when socket_enable calls gettype, trt happens 114 */ 115 STAILQ_INIT(&sc->card.pf_head); 116 117 DEVPRINTF((dev, "chip_socket_enable\n")); 118 POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 119 120 DEVPRINTF((dev, "read_cis\n")); 121 pccard_read_cis(sc); 122 123 DEVPRINTF((dev, "chip_socket_disable\n")); 124 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 125 126 DEVPRINTF((dev, "check_cis_quirks\n")); 127 pccard_check_cis_quirks(dev); 128 129 /* 130 * bail now if the card has no functions, or if there was an error in 131 * the cis. 132 */ 133 134 if (sc->card.error) 135 return (1); 136 if (STAILQ_EMPTY(&sc->card.pf_head)) 137 return (1); 138 139 if (pccard_verbose) 140 pccard_print_cis(dev); 141 142 attached = 0; 143 144 DEVPRINTF((dev, "functions scanning\n")); 145 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 146 if (STAILQ_EMPTY(&pf->cfe_head)) 147 continue; 148 149#ifdef DIAGNOSTIC 150 if (pf->child != NULL) { 151 device_printf(sc->dev, 152 "%s still attached to function %d!\n", 153 device_get_name(pf->child), pf->number); 154 panic("pccard_card_attach"); 155 } 156#endif 157 pf->sc = sc; 158 pf->child = NULL; 159 pf->cfe = NULL; 160 pf->ih_fct = NULL; 161 pf->ih_arg = NULL; 162 } 163 164 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 165 if (STAILQ_EMPTY(&pf->cfe_head)) 166 continue; 167 168#if XXX 169 if (attach_child()) { 170 attached++; 171 172 DEVPRINTF((sc->dev, "function %d CCR at %d " 173 "offset %lx: %x %x %x %x, %x %x %x %x, %x\n", 174 pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 175 pccard_ccr_read(pf, 0x00), 176 pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 177 pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 178 pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 179 pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 180 } 181#endif 182 } 183 184 return (attached ? 0 : 1); 185} 186 187void 188pccard_card_detach(device_t dev, int flags) 189{ 190 struct pccard_softc *sc = (struct pccard_softc *) 191 device_get_softc(dev); 192 struct pccard_function *pf; 193#if XXX 194 int error; 195#endif 196 197 /* 198 * We are running on either the PCCARD socket's event thread 199 * or in user context detaching a device by user request. 200 */ 201 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 202 if (STAILQ_FIRST(&pf->cfe_head) == NULL) 203 continue; 204 if (pf->child == NULL) 205 continue; 206 DEVPRINTF((sc->dev, "detaching %s (function %d)\n", 207 device_get_name(pf->child), pf->number)); 208#if XXX 209 if ((error = config_detach(pf->child, flags)) != 0) { 210 device_printf(sc->dev, 211 "error %d detaching %s (function %d)\n", 212 error, device_get_name(pf->child), pf->number); 213 } else 214 pf->child = NULL; 215#endif 216 } 217} 218 219void 220pccard_card_deactivate(device_t dev) 221{ 222 struct pccard_softc *sc = (struct pccard_softc *) 223 device_get_softc(dev); 224 struct pccard_function *pf; 225 226 /* 227 * We're in the chip's card removal interrupt handler. 228 * Deactivate the child driver. The PCCARD socket's 229 * event thread will run later to finish the detach. 230 */ 231 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 232 if (STAILQ_FIRST(&pf->cfe_head) == NULL) 233 continue; 234 if (pf->child == NULL) 235 continue; 236 DEVPRINTF((sc->dev, "deactivating %s (function %d)\n", 237 device_get_name(pf->child), pf->number)); 238#if XXX 239 config_deactivate(pf->child); 240#endif 241 } 242} 243 244int 245pccard_card_gettype(device_t dev) 246{ 247 struct pccard_softc *sc = (struct pccard_softc *) 248 device_get_softc(dev); 249 struct pccard_function *pf; 250 251 /* 252 * set the iftype to memory if this card has no functions (not yet 253 * probed), or only one function, and that is not initialized yet or 254 * that is memory. 255 */ 256 pf = STAILQ_FIRST(&sc->card.pf_head); 257 if (pf == NULL || 258 (STAILQ_NEXT(pf, pf_list) == NULL && 259 (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 260 return (PCCARD_IFTYPE_MEMORY); 261 else 262 return (PCCARD_IFTYPE_IO); 263} 264 265/* 266 * Initialize a PCCARD function. May be called as long as the function is 267 * disabled. 268 */ 269void 270pccard_function_init(struct pccard_function *pf, 271 struct pccard_config_entry *cfe) 272{ 273 if (pf->pf_flags & PFF_ENABLED) 274 panic("pccard_function_init: function is enabled"); 275 276 /* Remember which configuration entry we are using. */ 277 pf->cfe = cfe; 278} 279 280/* Enable a PCCARD function */ 281int 282pccard_function_enable(struct pccard_function *pf) 283{ 284 struct pccard_function *tmp; 285 int reg; 286 device_t dev = pf->sc->dev; 287 288 if (pf->cfe == NULL) 289 panic("pccard_function_enable: function not initialized"); 290 291 /* 292 * Increase the reference count on the socket, enabling power, if 293 * necessary. 294 */ 295 if (pf->sc->sc_enabled_count++ == 0) 296 POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 297 DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); 298 299 if (pf->pf_flags & PFF_ENABLED) { 300 /* 301 * Don't do anything if we're already enabled. 302 */ 303 return (0); 304 } 305 306 /* 307 * it's possible for different functions' CCRs to be in the same 308 * underlying page. Check for that. 309 */ 310 311 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 312 if ((tmp->pf_flags & PFF_ENABLED) && 313 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 314 ((pf->ccr_base + PCCARD_CCR_SIZE) <= 315 (tmp->ccr_base - tmp->pf_ccr_offset + 316 tmp->pf_ccr_realsize))) { 317 pf->pf_ccrt = tmp->pf_ccrt; 318 pf->pf_ccrh = tmp->pf_ccrh; 319 pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 320 321 /* 322 * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 323 * tmp->ccr_base) + pf->ccr_base; 324 */ 325 pf->pf_ccr_offset = 326 (tmp->pf_ccr_offset + pf->ccr_base) - 327 tmp->ccr_base; 328 pf->pf_ccr_window = tmp->pf_ccr_window; 329 break; 330 } 331 } 332 333 if (tmp == NULL) { 334 pf->ccr_rid = 0; 335 pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 336 &pf->ccr_rid, pf->ccr_base, pf->ccr_base + PCCARD_CCR_SIZE, 337 PCCARD_CCR_SIZE, RF_ACTIVE | RF_PCCARD_ATTR); 338 if (!pf->ccr_res) 339 goto bad; 340 pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 341 pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 342 pf->pf_ccr_offset = rman_get_start(pf->ccr_res); 343 pf->pf_ccr_realsize = 1; 344 } 345 346 reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 347 reg |= PCCARD_CCR_OPTION_LEVIREQ; 348 if (pccard_mfc(pf->sc)) { 349 reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 350 PCCARD_CCR_OPTION_ADDR_DECODE); 351 if (pf->ih_fct) 352 reg |= PCCARD_CCR_OPTION_IREQ_ENABLE; 353 354 } 355 pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 356 357 reg = 0; 358 359 if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 360 reg |= PCCARD_CCR_STATUS_IOIS8; 361 if (pf->cfe->flags & PCCARD_CFE_AUDIO) 362 reg |= PCCARD_CCR_STATUS_AUDIO; 363 pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 364 365 pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 366 367 if (pccard_mfc(pf->sc)) { 368 long tmp, iosize; 369 370 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 371 /* round up to nearest (2^n)-1 */ 372 for (iosize = 1; iosize < tmp; iosize <<= 1) 373 ; 374 iosize--; 375 376 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 377 pf->pf_mfc_iobase & 0xff); 378 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 379 (pf->pf_mfc_iobase >> 8) & 0xff); 380 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 381 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 382 383 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 384 } 385 386#ifdef PCCARDDEBUG 387 if (pccard_debug) { 388 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 389 device_printf(tmp->sc->dev, 390 "function %d CCR at %d offset %x: " 391 "%x %x %x %x, %x %x %x %x, %x\n", 392 tmp->number, tmp->pf_ccr_window, 393 tmp->pf_ccr_offset, 394 pccard_ccr_read(tmp, 0x00), 395 pccard_ccr_read(tmp, 0x02), 396 pccard_ccr_read(tmp, 0x04), 397 pccard_ccr_read(tmp, 0x06), 398 pccard_ccr_read(tmp, 0x0A), 399 pccard_ccr_read(tmp, 0x0C), 400 pccard_ccr_read(tmp, 0x0E), 401 pccard_ccr_read(tmp, 0x10), 402 pccard_ccr_read(tmp, 0x12)); 403 } 404 } 405#endif 406 pf->pf_flags |= PFF_ENABLED; 407 return (0); 408 409 bad: 410 /* 411 * Decrement the reference count, and power down the socket, if 412 * necessary. 413 */ 414 if (--pf->sc->sc_enabled_count == 0) 415 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 416 DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 417 418 return (1); 419} 420 421/* Disable PCCARD function. */ 422void 423pccard_function_disable(struct pccard_function *pf) 424{ 425 struct pccard_function *tmp; 426 device_t dev = pf->sc->dev; 427 428 if (pf->cfe == NULL) 429 panic("pccard_function_enable: function not initialized"); 430 431 if ((pf->pf_flags & PFF_ENABLED) == 0) { 432 /* 433 * Don't do anything if we're already disabled. 434 */ 435 return; 436 } 437 438 /* 439 * it's possible for different functions' CCRs to be in the same 440 * underlying page. Check for that. Note we mark us as disabled 441 * first to avoid matching ourself. 442 */ 443 444 pf->pf_flags &= ~PFF_ENABLED; 445 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 446 if ((tmp->pf_flags & PFF_ENABLED) && 447 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 448 ((pf->ccr_base + PCCARD_CCR_SIZE) <= 449 (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) 450 break; 451 } 452 453 /* Not used by anyone else; unmap the CCR. */ 454 if (tmp == NULL) { 455 bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 456 pf->ccr_res); 457 pf->ccr_res = NULL; 458 } 459 460 /* 461 * Decrement the reference count, and power down the socket, if 462 * necessary. 463 */ 464 if (--pf->sc->sc_enabled_count == 0) 465 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 466 DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 467} 468 469#if 0 470/* XXX These functions are needed, but not like this XXX */ 471int 472pccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset, 473 bus_size_t size, struct pccard_io_handle *pcihp, int *windowp) 474{ 475 int reg; 476 477 if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, 478 width, offset, size, pcihp, windowp)) 479 return (1); 480 481 /* 482 * XXX in the multifunction multi-iospace-per-function case, this 483 * needs to cooperate with io_alloc to make sure that the spaces 484 * don't overlap, and that the ccr's are set correctly 485 */ 486 487 if (pccard_mfc(pf->sc)) { 488 long tmp, iosize; 489 490 if (pf->pf_mfc_iomax == 0) { 491 pf->pf_mfc_iobase = pcihp->addr + offset; 492 pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 493 } else { 494 /* this makes the assumption that nothing overlaps */ 495 if (pf->pf_mfc_iobase > pcihp->addr + offset) 496 pf->pf_mfc_iobase = pcihp->addr + offset; 497 if (pf->pf_mfc_iomax < pcihp->addr + offset + size) 498 pf->pf_mfc_iomax = pcihp->addr + offset + size; 499 } 500 501 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 502 /* round up to nearest (2^n)-1 */ 503 for (iosize = 1; iosize >= tmp; iosize <<= 1) 504 ; 505 iosize--; 506 507 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 508 pf->pf_mfc_iobase & 0xff); 509 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 510 (pf->pf_mfc_iobase >> 8) & 0xff); 511 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 512 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 513 514 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 515 516 reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION); 517 reg |= PCCARD_CCR_OPTION_ADDR_DECODE; 518 pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 519 } 520 return (0); 521} 522 523void 524pccard_io_unmap(struct pccard_function *pf, int window) 525{ 526 527 pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window); 528 529 /* XXX Anything for multi-function cards? */ 530} 531#endif 532 533/* I don't think FreeBSD needs the next two functions at all */ 534/* XXX */ 535int 536pccard_card_intr(void *arg) 537{ 538 struct pccard_softc *sc = arg; 539 struct pccard_function *pf; 540 int reg, ret, ret2; 541 542 ret = 0; 543 544 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 545 if (pf->ih_fct != NULL && 546 (pf->ccr_mask & (1 << (PCCARD_CCR_STATUS / 2)))) { 547 reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 548 if (reg & PCCARD_CCR_STATUS_INTR) { 549 ret2 = (*pf->ih_fct)(pf->ih_arg); 550 if (ret2 != 0 && ret == 0) 551 ret = ret2; 552 reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 553 pccard_ccr_write(pf, PCCARD_CCR_STATUS, 554 reg & ~PCCARD_CCR_STATUS_INTR); 555 } 556 } 557 } 558 559 return (ret); 560} 561 562#ifdef PCCARDDEBUG 563int 564pccard_card_intrdebug(arg) 565 void *arg; 566{ 567 struct pccard_softc *sc = arg; 568 struct pccard_function *pf; 569 int reg, ret, ret2; 570 571 ret = 0; 572 573 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 574 device_printf(sc->dev, 575 "intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x", 576 pf->pf_flags, pf->number, 577 pccard_ccr_read(pf, PCCARD_CCR_OPTION), 578 pccard_ccr_read(pf, PCCARD_CCR_STATUS), 579 pccard_ccr_read(pf, PCCARD_CCR_PIN)); 580 if (pf->ih_fct != NULL && 581 (pf->ccr_mask & (1 << (PCCARD_CCR_STATUS / 2)))) { 582 reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 583 if (reg & PCCARD_CCR_STATUS_INTR) { 584 ret2 = (*pf->ih_fct)(pf->ih_arg); 585 if (ret2 != 0 && ret == 0) 586 ret = ret2; 587 reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 588 printf("; csr %02x->%02x", 589 reg, reg & ~PCCARD_CCR_STATUS_INTR); 590 pccard_ccr_write(pf, PCCARD_CCR_STATUS, 591 reg & ~PCCARD_CCR_STATUS_INTR); 592 } 593 } 594 printf("\n"); 595 } 596 597 return (ret); 598} 599#endif 600 601#define PCCARD_NPORT 2 602#define PCCARD_NMEM 5 603#define PCCARD_NIRQ 1 604#define PCCARD_NDRQ 0 605 606static int 607pccard_add_children(device_t dev, int busno) 608{ 609 return 0; 610} 611 612static int 613pccard_probe(device_t dev) 614{ 615 device_set_desc(dev, "PC Card bus -- newconfig version"); 616 return pccard_add_children(dev, device_get_unit(dev)); 617} 618 619static void 620pccard_print_resources(struct resource_list *rl, const char *name, int type, 621 int count, const char *format) 622{ 623 struct resource_list_entry *rle; 624 int printed; 625 int i; 626 627 printed = 0; 628 for (i = 0; i < count; i++) { 629 rle = resource_list_find(rl, type, i); 630 if (rle) { 631 if (printed == 0) 632 printf(" %s ", name); 633 else if (printed > 0) 634 printf(","); 635 printed++; 636 printf(format, rle->start); 637 if (rle->count > 1) { 638 printf("-"); 639 printf(format, rle->start + rle->count - 1); 640 } 641 } else if (i > 3) { 642 /* check the first few regardless */ 643 break; 644 } 645 } 646} 647 648static int 649pccard_print_child(device_t dev, device_t child) 650{ 651 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 652 struct resource_list *rl = &devi->resources; 653 int retval = 0; 654 655 retval += bus_print_child_header(dev, child); 656 retval += printf(" at"); 657 658 if (devi) { 659 pccard_print_resources(rl, "port", SYS_RES_IOPORT, 660 PCCARD_NPORT, "%#lx"); 661 pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 662 PCCARD_NMEM, "%#lx"); 663 pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 664 "%ld"); 665 pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 666 "%ld"); 667 retval += printf(" slot %d", devi->slotnum); 668 } 669 670 retval += bus_print_child_footer(dev, child); 671 672 return (retval); 673} 674 675static int 676pccard_set_resource(device_t dev, device_t child, int type, int rid, 677 u_long start, u_long count) 678{ 679 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 680 struct resource_list *rl = &devi->resources; 681 682 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 683 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 684 return EINVAL; 685 if (rid < 0) 686 return EINVAL; 687 if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 688 return EINVAL; 689 if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 690 return EINVAL; 691 if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 692 return EINVAL; 693 if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 694 return EINVAL; 695 696 resource_list_add(rl, type, rid, start, start + count - 1, count); 697 698 return 0; 699} 700 701static int 702pccard_get_resource(device_t dev, device_t child, int type, int rid, 703 u_long *startp, u_long *countp) 704{ 705 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 706 struct resource_list *rl = &devi->resources; 707 struct resource_list_entry *rle; 708 709 rle = resource_list_find(rl, type, rid); 710 if (!rle) 711 return ENOENT; 712 713 if (startp) 714 *startp = rle->start; 715 if (countp) 716 *countp = rle->count; 717 718 return 0; 719} 720 721static void 722pccard_delete_resource(device_t dev, device_t child, int type, int rid) 723{ 724 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 725 struct resource_list *rl = &devi->resources; 726 resource_list_delete(rl, type, rid); 727} 728 729static device_method_t pccard_methods[] = { 730 /* Device interface */ 731 DEVMETHOD(device_probe, pccard_probe), 732 DEVMETHOD(device_attach, bus_generic_attach), 733 DEVMETHOD(device_shutdown, bus_generic_shutdown), 734 DEVMETHOD(device_suspend, bus_generic_suspend), 735 DEVMETHOD(device_resume, bus_generic_resume), 736 737 /* Bus interface */ 738 DEVMETHOD(bus_print_child, pccard_print_child), 739 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 740 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 741 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 742 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 743 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 744 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 745 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 746 DEVMETHOD(bus_set_resource, pccard_set_resource), 747 DEVMETHOD(bus_get_resource, pccard_get_resource), 748 DEVMETHOD(bus_delete_resource, pccard_delete_resource), 749 750 { 0, 0 } 751}; 752 753static driver_t pccard_driver = { 754 "pccard", 755 pccard_methods, 756 1, /* no softc */ 757}; 758 759devclass_t pccard_devclass; 760 761DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 762DRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 763DRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0); 764DRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 765