pccard.c revision 59389
1/* $NetBSD: pcmcia.c,v 1.13 1998/12/24 04:51:59 marc Exp $ */ 2/* $FreeBSD: head/sys/dev/pccard/pccard.c 59389 2000-04-19 08:31:21Z 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/pccardvar.h> 48 49#include "power_if.h" 50#include "card_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 58#else 59#define DPRINTF(arg) 60#define DEVPRINTF(arg) 61#endif 62 63#ifdef PCCARDVERBOSE 64int pccard_verbose = 1; 65#else 66int pccard_verbose = 0; 67#endif 68 69int pccard_print(void *, const char *); 70 71int 72pccard_ccr_read(pf, ccr) 73 struct pccard_function *pf; 74 int ccr; 75{ 76 return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 77 pf->pf_ccr_offset + ccr)); 78} 79 80void 81pccard_ccr_write(pf, ccr, val) 82 struct pccard_function *pf; 83 int ccr; 84 int val; 85{ 86 87 if ((pf->ccr_mask) & (1 << (ccr / 2))) { 88 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 89 pf->pf_ccr_offset + ccr, val); 90 } 91} 92 93static int 94pccard_attach_card(device_t dev) 95{ 96 struct pccard_softc *sc = (struct pccard_softc *) 97 device_get_softc(dev); 98 struct pccard_function *pf; 99 int attached; 100 101 DEVPRINTF((dev, "pccard_card_attach\n")); 102 /* 103 * this is here so that when socket_enable calls gettype, trt happens 104 */ 105 STAILQ_INIT(&sc->card.pf_head); 106 107 DEVPRINTF((dev, "chip_socket_enable\n")); 108 POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 109 110 DEVPRINTF((dev, "read_cis\n")); 111 pccard_read_cis(sc); 112 113 DEVPRINTF((dev, "chip_socket_disable\n")); 114 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 115 116 DEVPRINTF((dev, "check_cis_quirks\n")); 117 pccard_check_cis_quirks(dev); 118 119 /* 120 * bail now if the card has no functions, or if there was an error in 121 * the cis. 122 */ 123 124 if (sc->card.error) 125 return (1); 126 if (STAILQ_EMPTY(&sc->card.pf_head)) 127 return (1); 128 129 if (pccard_verbose) 130 pccard_print_cis(dev); 131 132 attached = 0; 133 134 DEVPRINTF((dev, "functions scanning\n")); 135 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 136 if (STAILQ_EMPTY(&pf->cfe_head)) 137 continue; 138 139 pf->sc = sc; 140 pf->cfe = NULL; 141 pf->ih_fct = NULL; 142 pf->ih_arg = NULL; 143 } 144 145 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 146 if (STAILQ_EMPTY(&pf->cfe_head)) 147 continue; 148 149#if XXX 150 if (attach_child()) { 151 attached++; 152 153 DEVPRINTF((sc->dev, "function %d CCR at %d " 154 "offset %lx: %x %x %x %x, %x %x %x %x, %x\n", 155 pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 156 pccard_ccr_read(pf, 0x00), 157 pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 158 pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 159 pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 160 pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 161 } 162#endif 163 } 164 165 return (attached ? 0 : 1); 166} 167 168static int 169pccard_detach_card(device_t dev, int flags) 170{ 171 struct pccard_softc *sc = (struct pccard_softc *) 172 device_get_softc(dev); 173 struct pccard_function *pf; 174#if XXX 175 int error; 176#endif 177 178 /* 179 * We are running on either the PCCARD socket's event thread 180 * or in user context detaching a device by user request. 181 */ 182 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 183 if (STAILQ_FIRST(&pf->cfe_head) == NULL) 184 continue; 185#if XXX 186 DEVPRINTF((sc->dev, "detaching %s (function %d)\n", 187 device_get_name(pf->child), pf->number)); 188 if ((error = config_detach(pf->child, flags)) != 0) { 189 device_printf(sc->dev, 190 "error %d detaching %s (function %d)\n", 191 error, device_get_name(pf->child), pf->number); 192 } else 193 pf->child = NULL; 194#endif 195 } 196 return 0; 197} 198 199static int 200pccard_card_gettype(device_t dev, int *type) 201{ 202 struct pccard_softc *sc = (struct pccard_softc *) 203 device_get_softc(dev); 204 struct pccard_function *pf; 205 206 /* 207 * set the iftype to memory if this card has no functions (not yet 208 * probed), or only one function, and that is not initialized yet or 209 * that is memory. 210 */ 211 pf = STAILQ_FIRST(&sc->card.pf_head); 212 if (pf == NULL || 213 (STAILQ_NEXT(pf, pf_list) == NULL && 214 (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 215 *type = PCCARD_IFTYPE_MEMORY; 216 else 217 *type = PCCARD_IFTYPE_IO; 218 return 0; 219} 220 221/* 222 * Initialize a PCCARD function. May be called as long as the function is 223 * disabled. 224 */ 225void 226pccard_function_init(struct pccard_function *pf, 227 struct pccard_config_entry *cfe) 228{ 229 if (pf->pf_flags & PFF_ENABLED) 230 panic("pccard_function_init: function is enabled"); 231 232 /* Remember which configuration entry we are using. */ 233 pf->cfe = cfe; 234} 235 236/* Enable a PCCARD function */ 237int 238pccard_function_enable(struct pccard_function *pf) 239{ 240 struct pccard_function *tmp; 241 int reg; 242 device_t dev = pf->sc->dev; 243 244 if (pf->cfe == NULL) 245 panic("pccard_function_enable: function not initialized"); 246 247 /* 248 * Increase the reference count on the socket, enabling power, if 249 * necessary. 250 */ 251 if (pf->sc->sc_enabled_count++ == 0) 252 POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 253 DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); 254 255 if (pf->pf_flags & PFF_ENABLED) { 256 /* 257 * Don't do anything if we're already enabled. 258 */ 259 return (0); 260 } 261 262 /* 263 * it's possible for different functions' CCRs to be in the same 264 * underlying page. Check for that. 265 */ 266 267 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 268 if ((tmp->pf_flags & PFF_ENABLED) && 269 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 270 ((pf->ccr_base + PCCARD_CCR_SIZE) <= 271 (tmp->ccr_base - tmp->pf_ccr_offset + 272 tmp->pf_ccr_realsize))) { 273 pf->pf_ccrt = tmp->pf_ccrt; 274 pf->pf_ccrh = tmp->pf_ccrh; 275 pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 276 277 /* 278 * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 279 * tmp->ccr_base) + pf->ccr_base; 280 */ 281 pf->pf_ccr_offset = 282 (tmp->pf_ccr_offset + pf->ccr_base) - 283 tmp->ccr_base; 284 pf->pf_ccr_window = tmp->pf_ccr_window; 285 break; 286 } 287 } 288 289 if (tmp == NULL) { 290 pf->ccr_rid = 0; 291 pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 292 &pf->ccr_rid, pf->ccr_base, pf->ccr_base + PCCARD_CCR_SIZE, 293 PCCARD_CCR_SIZE, RF_ACTIVE); 294 /* XXX SET MEM_ATTR */ 295 if (!pf->ccr_res) 296 goto bad; 297 pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 298 pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 299 pf->pf_ccr_offset = rman_get_start(pf->ccr_res); 300 pf->pf_ccr_realsize = 1; 301 } 302 303 reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 304 reg |= PCCARD_CCR_OPTION_LEVIREQ; 305 if (pccard_mfc(pf->sc)) { 306 reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 307 PCCARD_CCR_OPTION_ADDR_DECODE); 308 if (pf->ih_fct) 309 reg |= PCCARD_CCR_OPTION_IREQ_ENABLE; 310 311 } 312 pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 313 314 reg = 0; 315 316 if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 317 reg |= PCCARD_CCR_STATUS_IOIS8; 318 if (pf->cfe->flags & PCCARD_CFE_AUDIO) 319 reg |= PCCARD_CCR_STATUS_AUDIO; 320 pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 321 322 pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 323 324 if (pccard_mfc(pf->sc)) { 325 long tmp, iosize; 326 327 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 328 /* round up to nearest (2^n)-1 */ 329 for (iosize = 1; iosize < tmp; iosize <<= 1) 330 ; 331 iosize--; 332 333 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 334 pf->pf_mfc_iobase & 0xff); 335 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 336 (pf->pf_mfc_iobase >> 8) & 0xff); 337 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 338 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 339 340 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 341 } 342 343#ifdef PCCARDDEBUG 344 if (pccard_debug) { 345 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 346 device_printf(tmp->sc->dev, 347 "function %d CCR at %d offset %x: " 348 "%x %x %x %x, %x %x %x %x, %x\n", 349 tmp->number, tmp->pf_ccr_window, 350 tmp->pf_ccr_offset, 351 pccard_ccr_read(tmp, 0x00), 352 pccard_ccr_read(tmp, 0x02), 353 pccard_ccr_read(tmp, 0x04), 354 pccard_ccr_read(tmp, 0x06), 355 pccard_ccr_read(tmp, 0x0A), 356 pccard_ccr_read(tmp, 0x0C), 357 pccard_ccr_read(tmp, 0x0E), 358 pccard_ccr_read(tmp, 0x10), 359 pccard_ccr_read(tmp, 0x12)); 360 } 361 } 362#endif 363 pf->pf_flags |= PFF_ENABLED; 364 return (0); 365 366 bad: 367 /* 368 * Decrement the reference count, and power down the socket, if 369 * necessary. 370 */ 371 if (--pf->sc->sc_enabled_count == 0) 372 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 373 DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 374 375 return (1); 376} 377 378/* Disable PCCARD function. */ 379void 380pccard_function_disable(struct pccard_function *pf) 381{ 382 struct pccard_function *tmp; 383 device_t dev = pf->sc->dev; 384 385 if (pf->cfe == NULL) 386 panic("pccard_function_enable: function not initialized"); 387 388 if ((pf->pf_flags & PFF_ENABLED) == 0) { 389 /* 390 * Don't do anything if we're already disabled. 391 */ 392 return; 393 } 394 395 /* 396 * it's possible for different functions' CCRs to be in the same 397 * underlying page. Check for that. Note we mark us as disabled 398 * first to avoid matching ourself. 399 */ 400 401 pf->pf_flags &= ~PFF_ENABLED; 402 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 403 if ((tmp->pf_flags & PFF_ENABLED) && 404 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 405 ((pf->ccr_base + PCCARD_CCR_SIZE) <= 406 (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) 407 break; 408 } 409 410 /* Not used by anyone else; unmap the CCR. */ 411 if (tmp == NULL) { 412 bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 413 pf->ccr_res); 414 pf->ccr_res = NULL; 415 } 416 417 /* 418 * Decrement the reference count, and power down the socket, if 419 * necessary. 420 */ 421 if (--pf->sc->sc_enabled_count == 0) 422 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 423 DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 424} 425 426#if 0 427/* XXX These functions are needed, but not like this XXX */ 428int 429pccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset, 430 bus_size_t size, struct pccard_io_handle *pcihp, int *windowp) 431{ 432 int reg; 433 434 if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, 435 width, offset, size, pcihp, windowp)) 436 return (1); 437 438 /* 439 * XXX in the multifunction multi-iospace-per-function case, this 440 * needs to cooperate with io_alloc to make sure that the spaces 441 * don't overlap, and that the ccr's are set correctly 442 */ 443 444 if (pccard_mfc(pf->sc)) { 445 long tmp, iosize; 446 447 if (pf->pf_mfc_iomax == 0) { 448 pf->pf_mfc_iobase = pcihp->addr + offset; 449 pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 450 } else { 451 /* this makes the assumption that nothing overlaps */ 452 if (pf->pf_mfc_iobase > pcihp->addr + offset) 453 pf->pf_mfc_iobase = pcihp->addr + offset; 454 if (pf->pf_mfc_iomax < pcihp->addr + offset + size) 455 pf->pf_mfc_iomax = pcihp->addr + offset + size; 456 } 457 458 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 459 /* round up to nearest (2^n)-1 */ 460 for (iosize = 1; iosize >= tmp; iosize <<= 1) 461 ; 462 iosize--; 463 464 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 465 pf->pf_mfc_iobase & 0xff); 466 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 467 (pf->pf_mfc_iobase >> 8) & 0xff); 468 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 469 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 470 471 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 472 473 reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION); 474 reg |= PCCARD_CCR_OPTION_ADDR_DECODE; 475 pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 476 } 477 return (0); 478} 479 480void 481pccard_io_unmap(struct pccard_function *pf, int window) 482{ 483 484 pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window); 485 486 /* XXX Anything for multi-function cards? */ 487} 488#endif 489 490#define PCCARD_NPORT 2 491#define PCCARD_NMEM 5 492#define PCCARD_NIRQ 1 493#define PCCARD_NDRQ 0 494 495static int 496pccard_add_children(device_t dev, int busno) 497{ 498 /* Call parent to scan for any current children */ 499 return 0; 500} 501 502static int 503pccard_probe(device_t dev) 504{ 505 device_set_desc(dev, "PC Card bus -- newconfig version"); 506 return pccard_add_children(dev, device_get_unit(dev)); 507} 508 509static int 510pccard_attach(device_t dev) 511{ 512 struct pccard_softc *sc; 513 514 sc = (struct pccard_softc *) device_get_softc(dev); 515 sc->dev = dev; 516 517 return bus_generic_attach(dev); 518} 519 520static void 521pccard_print_resources(struct resource_list *rl, const char *name, int type, 522 int count, const char *format) 523{ 524 struct resource_list_entry *rle; 525 int printed; 526 int i; 527 528 printed = 0; 529 for (i = 0; i < count; i++) { 530 rle = resource_list_find(rl, type, i); 531 if (rle) { 532 if (printed == 0) 533 printf(" %s ", name); 534 else if (printed > 0) 535 printf(","); 536 printed++; 537 printf(format, rle->start); 538 if (rle->count > 1) { 539 printf("-"); 540 printf(format, rle->start + rle->count - 1); 541 } 542 } else if (i > 3) { 543 /* check the first few regardless */ 544 break; 545 } 546 } 547} 548 549static int 550pccard_print_child(device_t dev, device_t child) 551{ 552 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 553 struct resource_list *rl = &devi->resources; 554 int retval = 0; 555 556 retval += bus_print_child_header(dev, child); 557 retval += printf(" at"); 558 559 if (devi) { 560 pccard_print_resources(rl, "port", SYS_RES_IOPORT, 561 PCCARD_NPORT, "%#lx"); 562 pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 563 PCCARD_NMEM, "%#lx"); 564 pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 565 "%ld"); 566 pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 567 "%ld"); 568 retval += printf(" slot %d", devi->slotnum); 569 } 570 571 retval += bus_print_child_footer(dev, child); 572 573 return (retval); 574} 575 576static int 577pccard_set_resource(device_t dev, device_t child, int type, int rid, 578 u_long start, u_long count) 579{ 580 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 581 struct resource_list *rl = &devi->resources; 582 583 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 584 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 585 return EINVAL; 586 if (rid < 0) 587 return EINVAL; 588 if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 589 return EINVAL; 590 if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 591 return EINVAL; 592 if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 593 return EINVAL; 594 if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 595 return EINVAL; 596 597 resource_list_add(rl, type, rid, start, start + count - 1, count); 598 599 return 0; 600} 601 602static int 603pccard_get_resource(device_t dev, device_t child, int type, int rid, 604 u_long *startp, u_long *countp) 605{ 606 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 607 struct resource_list *rl = &devi->resources; 608 struct resource_list_entry *rle; 609 610 rle = resource_list_find(rl, type, rid); 611 if (!rle) 612 return ENOENT; 613 614 if (startp) 615 *startp = rle->start; 616 if (countp) 617 *countp = rle->count; 618 619 return 0; 620} 621 622static void 623pccard_delete_resource(device_t dev, device_t child, int type, int rid) 624{ 625 struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child); 626 struct resource_list *rl = &devi->resources; 627 resource_list_delete(rl, type, rid); 628} 629 630static int 631pccard_set_res_flags(device_t dev, device_t child, int type, int rid, 632 u_int32_t flags) 633{ 634 return CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 635 rid, flags); 636} 637 638static int 639pccard_set_memory_offset(device_t dev, device_t child, int rid, 640 u_int32_t offset) 641{ 642 return CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 643 offset); 644} 645 646static device_method_t pccard_methods[] = { 647 /* Device interface */ 648 DEVMETHOD(device_probe, pccard_probe), 649 DEVMETHOD(device_attach, pccard_attach), 650 DEVMETHOD(device_shutdown, bus_generic_shutdown), 651 DEVMETHOD(device_suspend, bus_generic_suspend), 652 DEVMETHOD(device_resume, bus_generic_resume), 653 654 /* Bus interface */ 655 DEVMETHOD(bus_print_child, pccard_print_child), 656 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 657 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 658 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 659 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 660 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 661 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 662 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 663 DEVMETHOD(bus_set_resource, pccard_set_resource), 664 DEVMETHOD(bus_get_resource, pccard_get_resource), 665 DEVMETHOD(bus_delete_resource, pccard_delete_resource), 666 667 /* Card Interface */ 668 DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 669 DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 670 DEVMETHOD(card_get_type, pccard_card_gettype), 671 DEVMETHOD(card_attach_card, pccard_attach_card), 672 DEVMETHOD(card_detach_card, pccard_detach_card), 673 674 { 0, 0 } 675}; 676 677static driver_t pccard_driver = { 678 "pccard", 679 pccard_methods, 680 1, /* no softc */ 681}; 682 683devclass_t pccard_devclass; 684 685DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 686DRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 687DRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0); 688DRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 689