pccard.c revision 70761
1/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 2/* $FreeBSD: head/sys/dev/pccard/pccard.c 70761 2001-01-07 20:36:27Z 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#define PRVERBOSE(arg) printf arg 59#define DEVPRVERBOSE(arg) device_printf arg 60#else 61#define DPRINTF(arg) 62#define DEVPRINTF(arg) 63#define PRVERBOSE(arg) if (bootverbose) printf arg 64#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 65#endif 66 67#ifdef PCCARDVERBOSE 68int pccard_verbose = 1; 69#else 70int pccard_verbose = 0; 71#endif 72 73int pccard_print(void *, const char *); 74 75int 76pccard_ccr_read(pf, ccr) 77 struct pccard_function *pf; 78 int ccr; 79{ 80 return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 81 pf->pf_ccr_offset + ccr)); 82} 83 84void 85pccard_ccr_write(pf, ccr, val) 86 struct pccard_function *pf; 87 int ccr; 88 int val; 89{ 90 91 if ((pf->ccr_mask) & (1 << (ccr / 2))) { 92 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 93 pf->pf_ccr_offset + ccr, val); 94 } 95} 96 97static int 98pccard_attach_card(device_t dev) 99{ 100 struct pccard_softc *sc = PCCARD_SOFTC(dev); 101 struct pccard_function *pf; 102 struct pccard_ivar *ivar; 103 device_t child; 104 int attached; 105 106 sc->intr_handler_count = 0; 107 /* 108 * this is here so that when socket_enable calls gettype, trt happens 109 */ 110 STAILQ_INIT(&sc->card.pf_head); 111 112 DEVPRINTF((dev, "chip_socket_enable\n")); 113 POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 114 115 DEVPRINTF((dev, "read_cis\n")); 116 pccard_read_cis(sc); 117 118 DEVPRINTF((dev, "check_cis_quirks\n")); 119 pccard_check_cis_quirks(dev); 120 121 /* 122 * bail now if the card has no functions, or if there was an error in 123 * the cis. 124 */ 125 126 if (sc->card.error) { 127 device_printf (dev, "CARD ERROR!\n"); 128 return (1); 129 } 130 if (STAILQ_EMPTY(&sc->card.pf_head)) { 131 device_printf (dev, "Card has no functions!\n"); 132 return (1); 133 } 134 135 if (1) 136 pccard_print_cis(dev); 137 138 attached = 0; 139 140 DEVPRINTF((dev, "functions scanning\n")); 141 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 142 if (STAILQ_EMPTY(&pf->cfe_head)) 143 continue; 144 145 pf->sc = sc; 146 pf->cfe = NULL; 147 pf->dev = NULL; 148 } 149#if 0 150 DEVPRINTF((dev, "chip_socket_disable\n")); 151 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 152#endif 153 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 154 if (STAILQ_EMPTY(&pf->cfe_head)) 155 continue; 156 /* 157 * In NetBSD, the drivers are responsible for activating 158 * each function of a card. I think that in FreeBSD we 159 * want to activate them enough for the usual bus_*_resource 160 * routines will do the right thing. This many mean a 161 * departure from the current NetBSD model. 162 * 163 * This could get really ugly for multifunction cards. But 164 * it might also just fall out of the FreeBSD resource model. 165 * 166 */ 167 ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 168 M_WAITOK | M_ZERO); 169 child = device_add_child(dev, NULL, -1); 170 device_set_ivars(child, ivar); 171 ivar->fcn = pf; 172 pf->dev = child; 173 /* 174 * XXX We might want to move the next two lines into 175 * XXX the pccard interface layer. For the moment, this 176 * XXX is OK, but some drivers want to pick the config 177 * XXX entry to use as well as some address tweaks (mostly 178 * XXX due to bugs in decode logic that makes some 179 * XXX addresses illegal or broken). 180 */ 181 pccard_function_init(pf); 182 if (pccard_function_enable(pf) == 0 && 183 device_probe_and_attach(child) == 0) { 184 attached++; 185 186 DEVPRINTF((sc->dev, "function %d CCR at %d " 187 "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 188 pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 189 pccard_ccr_read(pf, 0x00), 190 pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 191 pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 192 pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 193 pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 194 } else { 195 device_delete_child(dev, child); 196 } 197 } 198 return 0; 199} 200 201static int 202pccard_detach_card(device_t dev, int flags) 203{ 204 struct pccard_softc *sc = PCCARD_SOFTC(dev); 205 struct pccard_function *pf; 206 207 /* 208 * We are running on either the PCCARD socket's event thread 209 * or in user context detaching a device by user request. 210 */ 211 STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 212 if (STAILQ_FIRST(&pf->cfe_head) == NULL) 213 continue; 214 215 pccard_function_disable(pf); 216 if (pf->dev) 217 device_delete_child(dev, pf->dev); 218 } 219 return 0; 220} 221 222const struct pccard_product * 223pccard_product_lookup(device_t dev, const struct pccard_product *tab, 224 size_t ent_size, pccard_product_match_fn matchfn) 225{ 226 const struct pccard_product *ent; 227 int matches; 228 u_int32_t fcn; 229 u_int32_t vendor; 230 u_int32_t prod; 231 char *vendorstr; 232 char *prodstr; 233 234#ifdef DIAGNOSTIC 235 if (sizeof *ent > ent_size) 236 panic("pccard_product_lookup: bogus ent_size %ld", 237 (long) ent_size); 238#endif 239 if (pccard_get_vendor(dev, &vendor)) 240 return (NULL); 241 if (pccard_get_product(dev, &prod)) 242 return (NULL); 243 if (pccard_get_function_number(dev, &fcn)) 244 return (NULL); 245 if (pccard_get_vendor_str(dev, &vendorstr)) 246 return (NULL); 247 if (pccard_get_product_str(dev, &prodstr)) 248 return (NULL); 249 for (ent = tab; ent->pp_name != NULL; 250 ent = (const struct pccard_product *) 251 ((const char *) ent + ent_size)) { 252 matches = 1; 253 if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 254 vendor != ent->pp_vendor) 255 matches = 0; 256 if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 257 prod != ent->pp_product) 258 matches = 0; 259 if (matches && fcn != ent->pp_expfunc) 260 matches = 0; 261 if (matches && ent->pp_vendor_str && 262 strcmp(ent->pp_vendor_str, vendorstr) != 0) 263 matches = 0; 264 if (matches && ent->pp_product_str && 265 strcmp(ent->pp_product_str, prodstr) != 0) 266 matches = 0; 267 if (matchfn != NULL) 268 matches = (*matchfn)(dev, ent, matches); 269 if (matches) 270 return (ent); 271 } 272 return (NULL); 273} 274 275static int 276pccard_card_gettype(device_t dev, int *type) 277{ 278 struct pccard_softc *sc = PCCARD_SOFTC(dev); 279 struct pccard_function *pf; 280 281 /* 282 * set the iftype to memory if this card has no functions (not yet 283 * probed), or only one function, and that is not initialized yet or 284 * that is memory. 285 */ 286 pf = STAILQ_FIRST(&sc->card.pf_head); 287 if (pf == NULL || 288 (STAILQ_NEXT(pf, pf_list) == NULL && 289 (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 290 *type = PCCARD_IFTYPE_MEMORY; 291 else 292 *type = PCCARD_IFTYPE_IO; 293 return 0; 294} 295 296/* 297 * Initialize a PCCARD function. May be called as long as the function is 298 * disabled. 299 */ 300void 301pccard_function_init(struct pccard_function *pf) 302{ 303 struct pccard_config_entry *cfe; 304 int i; 305 struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 306 struct resource_list *rl = &devi->resources; 307 struct resource *r = 0; 308 device_t bus; 309 int start; 310 int end; 311 312 if (pf->pf_flags & PFF_ENABLED) { 313 printf("pccard_function_init: function is enabled"); 314 return; 315 } 316 bus = device_get_parent(pf->dev); 317 /* Remember which configuration entry we are using. */ 318 for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL; 319 cfe = STAILQ_NEXT(cfe, cfe_list)) { 320 for (i = 0; i < cfe->num_iospace; i++) 321 cfe->iores[i] = NULL; 322 cfe->irqres = NULL; 323 for (i = 0; i < cfe->num_iospace; i++) { 324 start = cfe->iospace[i].start; 325 if (start) 326 end = start + cfe->iospace[i].length - 1; 327 else 328 end = ~0; 329 cfe->iorid[i] = i; 330 r = cfe->iores[i] = bus_alloc_resource(bus, 331 SYS_RES_IOPORT, &cfe->iorid[i], start, end, 332 cfe->iospace[i].length, 333 rman_make_alignment_flags(cfe->iospace[i].length)); 334 if (cfe->iores[i] == 0) 335 goto not_this_one; 336 resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i], 337 rman_get_start(r), rman_get_end(r), 338 cfe->iospace[i].length); 339 { 340 struct resource_list_entry *rle = resource_list_find(rl, SYS_RES_IOPORT, cfe->iorid[i]); 341 rle->res = r; 342 } 343 } 344 if (cfe->num_memspace > 0) { 345 goto not_this_one; 346 } 347 if (cfe->irqmask) { 348 cfe->irqrid = 0; 349 r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ, 350 &cfe->irqrid, 0, ~0, 1, 0); 351 if (cfe->irqres == 0) 352 goto not_this_one; 353 resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid, 354 rman_get_start(r), rman_get_end(r), 1); 355 { 356 struct resource_list_entry *rle = resource_list_find(rl, SYS_RES_IRQ, cfe->irqrid); 357 rle->res = r; 358 } 359 } 360 /* XXX Don't know how to deal with maxtwins */ 361 /* If we get to here, we've allocated all we need */ 362 pf->cfe = cfe; 363 break; 364 not_this_one:; 365 DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 366 cfe->number)); 367 /* 368 * Release resources that we partially allocated 369 * from this config entry. 370 */ 371 for (i = 0; i < cfe->num_iospace; i++) { 372 resource_list_delete(rl, SYS_RES_IOPORT, i); 373 if (cfe->iores[i]) 374 bus_release_resource(bus, SYS_RES_IOPORT, 375 cfe->iorid[i], cfe->iores[i]); 376 cfe->iores[i] = NULL; 377 } 378 if (cfe->irqmask && cfe->irqres) { 379 resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid); 380 bus_release_resource(bus, SYS_RES_IRQ, 381 cfe->irqrid, cfe->irqres); 382 cfe->irqres = NULL; 383 } 384 } 385} 386 387/* Enable a PCCARD function */ 388int 389pccard_function_enable(struct pccard_function *pf) 390{ 391 struct pccard_function *tmp; 392 int reg; 393 device_t dev = pf->sc->dev; 394 395 if (pf->cfe == NULL) { 396 DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 397 return ENOMEM; 398 } 399 400 /* 401 * Increase the reference count on the socket, enabling power, if 402 * necessary. 403 */ 404 if (pf->sc->sc_enabled_count++ == 0) 405 POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 406 DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); 407 408 if (pf->pf_flags & PFF_ENABLED) { 409 /* 410 * Don't do anything if we're already enabled. 411 */ 412 return (0); 413 } 414 415 /* 416 * it's possible for different functions' CCRs to be in the same 417 * underlying page. Check for that. 418 */ 419 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 420 if ((tmp->pf_flags & PFF_ENABLED) && 421 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 422 ((pf->ccr_base + PCCARD_CCR_SIZE) <= 423 (tmp->ccr_base - tmp->pf_ccr_offset + 424 tmp->pf_ccr_realsize))) { 425 pf->pf_ccrt = tmp->pf_ccrt; 426 pf->pf_ccrh = tmp->pf_ccrh; 427 pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 428 429 /* 430 * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 431 * tmp->ccr_base) + pf->ccr_base; 432 */ 433 /* pf->pf_ccr_offset = 434 (tmp->pf_ccr_offset + pf->ccr_base) - 435 tmp->ccr_base; */ 436 pf->pf_ccr_window = tmp->pf_ccr_window; 437 break; 438 } 439 } 440 if (tmp == NULL) { 441 pf->ccr_rid = 0; 442 pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 443 &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 444 if (!pf->ccr_res) 445 goto bad; 446 DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n", 447 rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 448 pf->ccr_base)); 449 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 450 pf->ccr_rid, PCCARD_A_MEM_ATTR); 451 CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 452 pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 453 pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 454 pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 455 pf->pf_ccr_realsize = 1; 456 } 457 458 reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 459 reg |= PCCARD_CCR_OPTION_LEVIREQ; 460 if (pccard_mfc(pf->sc)) { 461 reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 462 PCCARD_CCR_OPTION_ADDR_DECODE); 463 /* 464 * XXX Need to enable PCCARD_CCR_OPTION_IRQ_ENABLE if 465 * XXX we have an interrupt handler, but we don't know that 466 * XXX at this point. 467 */ 468/* reg |= PCCARD_CCR_OPTION_IREQ_ENABLE;*/ 469 } 470 pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 471 472 reg = 0; 473 if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 474 reg |= PCCARD_CCR_STATUS_IOIS8; 475 if (pf->cfe->flags & PCCARD_CFE_AUDIO) 476 reg |= PCCARD_CCR_STATUS_AUDIO; 477 pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 478 479 pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 480 481 if (pccard_mfc(pf->sc)) { 482 long tmp, iosize; 483 484 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 485 /* round up to nearest (2^n)-1 */ 486 for (iosize = 1; iosize < tmp; iosize <<= 1) 487 ; 488 iosize--; 489 490 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 491 pf->pf_mfc_iobase & 0xff); 492 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 493 (pf->pf_mfc_iobase >> 8) & 0xff); 494 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 495 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 496 497 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 498 } 499 500#ifdef PCCARDDEBUG 501 if (pccard_debug) { 502 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 503 device_printf(tmp->sc->dev, 504 "function %d CCR at %d offset %x: " 505 "%x %x %x %x, %x %x %x %x, %x\n", 506 tmp->number, tmp->pf_ccr_window, 507 tmp->pf_ccr_offset, 508 pccard_ccr_read(tmp, 0x00), 509 pccard_ccr_read(tmp, 0x02), 510 pccard_ccr_read(tmp, 0x04), 511 pccard_ccr_read(tmp, 0x06), 512 pccard_ccr_read(tmp, 0x0A), 513 pccard_ccr_read(tmp, 0x0C), 514 pccard_ccr_read(tmp, 0x0E), 515 pccard_ccr_read(tmp, 0x10), 516 pccard_ccr_read(tmp, 0x12)); 517 } 518 } 519#endif 520 pf->pf_flags |= PFF_ENABLED; 521 return (0); 522 523 bad: 524 /* 525 * Decrement the reference count, and power down the socket, if 526 * necessary. 527 */ 528 if (--pf->sc->sc_enabled_count == 0) 529 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 530 DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 531 532 return (1); 533} 534 535/* Disable PCCARD function. */ 536void 537pccard_function_disable(struct pccard_function *pf) 538{ 539 struct pccard_function *tmp; 540 device_t dev = pf->sc->dev; 541 542 if (pf->cfe == NULL) 543 panic("pccard_function_disable: function not initialized"); 544 545 if ((pf->pf_flags & PFF_ENABLED) == 0) { 546 /* 547 * Don't do anything if we're already disabled. 548 */ 549 return; 550 } 551 552 if (pf->intr_handler != NULL) { 553 pf->intr_handler = NULL; 554 pf->intr_handler_arg = NULL; 555 pf->intr_handler_cookie = NULL; 556 pccard_ccr_write(pf, PCCARD_CCR_OPTION, 557 pccard_ccr_read(pf, PCCARD_CCR_OPTION) & 558 ~PCCARD_CCR_OPTION_IREQ_ENABLE); 559 560 if (pf->sc->intr_handler_count == 1) { 561 struct pccard_ivar *ivar = PCCARD_IVAR(pf->dev); 562 struct resource_list_entry *rle = NULL; 563 564 pf->sc->intr_handler_count--; 565 rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 566 if (rle == NULL) 567 panic("No IRQ for pccard?"); 568 569 bus_teardown_intr(dev, rle->res, &pf->sc->intr_handler_count); 570 } 571 } 572 573 /* 574 * it's possible for different functions' CCRs to be in the same 575 * underlying page. Check for that. Note we mark us as disabled 576 * first to avoid matching ourself. 577 */ 578 579 pf->pf_flags &= ~PFF_ENABLED; 580 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 581 if ((tmp->pf_flags & PFF_ENABLED) && 582 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 583 ((pf->ccr_base + PCCARD_CCR_SIZE) <= 584 (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) 585 break; 586 } 587 588 /* Not used by anyone else; unmap the CCR. */ 589 if (tmp == NULL) { 590 bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 591 pf->ccr_res); 592 pf->ccr_res = NULL; 593 } 594 595 /* 596 * Decrement the reference count, and power down the socket, if 597 * necessary. 598 */ 599 if (--pf->sc->sc_enabled_count == 0) 600 POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 601 DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 602} 603 604#if 0 605/* XXX These functions are needed, but not like this XXX */ 606int 607pccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset, 608 bus_size_t size, struct pccard_io_handle *pcihp, int *windowp) 609{ 610 int reg; 611 612 if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size, 613 pcihp, windowp)) 614 return (1); 615 616 /* 617 * XXX in the multifunction multi-iospace-per-function case, this 618 * needs to cooperate with io_alloc to make sure that the spaces 619 * don't overlap, and that the ccr's are set correctly 620 */ 621 622 if (pccard_mfc(pf->sc)) { 623 long tmp, iosize; 624 625 if (pf->pf_mfc_iomax == 0) { 626 pf->pf_mfc_iobase = pcihp->addr + offset; 627 pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 628 } else { 629 /* this makes the assumption that nothing overlaps */ 630 if (pf->pf_mfc_iobase > pcihp->addr + offset) 631 pf->pf_mfc_iobase = pcihp->addr + offset; 632 if (pf->pf_mfc_iomax < pcihp->addr + offset + size) 633 pf->pf_mfc_iomax = pcihp->addr + offset + size; 634 } 635 636 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 637 /* round up to nearest (2^n)-1 */ 638 for (iosize = 1; iosize >= tmp; iosize <<= 1) 639 ; 640 iosize--; 641 642 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 643 pf->pf_mfc_iobase & 0xff); 644 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 645 (pf->pf_mfc_iobase >> 8) & 0xff); 646 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 647 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 648 649 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 650 651 reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION); 652 reg |= PCCARD_CCR_OPTION_ADDR_DECODE; 653 pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 654 } 655 return (0); 656} 657 658void 659pccard_io_unmap(struct pccard_function *pf, int window) 660{ 661 662 pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window); 663 664 /* XXX Anything for multi-function cards? */ 665} 666#endif 667 668/* 669 * simulate the old "probe" routine. In the new world order, the driver 670 * needs to grab devices while in the old they were assigned to the device by 671 * the pccardd process. These symbols are exported to the upper layers. 672 */ 673int 674pccard_compat_probe(device_t dev) 675{ 676 return (CARD_COMPAT_MATCH(dev)); 677} 678 679int 680pccard_compat_attach(device_t dev) 681{ 682 int err; 683 684 err = CARD_COMPAT_PROBE(dev); 685 if (err == 0) 686 err = CARD_COMPAT_ATTACH(dev); 687 return (err); 688} 689 690#define PCCARD_NPORT 2 691#define PCCARD_NMEM 5 692#define PCCARD_NIRQ 1 693#define PCCARD_NDRQ 0 694 695static int 696pccard_add_children(device_t dev, int busno) 697{ 698 /* Call parent to scan for any current children */ 699 return 0; 700} 701 702static int 703pccard_probe(device_t dev) 704{ 705 device_set_desc(dev, "16-bit PCCard bus"); 706 return pccard_add_children(dev, device_get_unit(dev)); 707} 708 709static int 710pccard_attach(device_t dev) 711{ 712 struct pccard_softc *sc = PCCARD_SOFTC(dev); 713 714 sc->dev = dev; 715 sc->sc_enabled_count = 0; 716 return bus_generic_attach(dev); 717} 718 719static void 720pccard_print_resources(struct resource_list *rl, const char *name, int type, 721 int count, const char *format) 722{ 723 struct resource_list_entry *rle; 724 int printed; 725 int i; 726 727 printed = 0; 728 for (i = 0; i < count; i++) { 729 rle = resource_list_find(rl, type, i); 730 if (rle) { 731 if (printed == 0) 732 printf(" %s ", name); 733 else if (printed > 0) 734 printf(","); 735 printed++; 736 printf(format, rle->start); 737 if (rle->count > 1) { 738 printf("-"); 739 printf(format, rle->start + rle->count - 1); 740 } 741 } else if (i > 3) { 742 /* check the first few regardless */ 743 break; 744 } 745 } 746} 747 748static int 749pccard_print_child(device_t dev, device_t child) 750{ 751 struct pccard_ivar *devi = PCCARD_IVAR(child); 752 struct resource_list *rl = &devi->resources; 753 int retval = 0; 754 755 retval += bus_print_child_header(dev, child); 756 retval += printf(" at"); 757 758 if (devi) { 759 pccard_print_resources(rl, "port", SYS_RES_IOPORT, 760 PCCARD_NPORT, "%#lx"); 761 pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 762 PCCARD_NMEM, "%#lx"); 763 pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 764 "%ld"); 765 pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 766 "%ld"); 767 retval += printf(" function %d config %d", devi->fcn->number, 768 devi->fcn->cfe->number); 769 } 770 771 retval += bus_print_child_footer(dev, child); 772 773 return (retval); 774} 775 776static int 777pccard_set_resource(device_t dev, device_t child, int type, int rid, 778 u_long start, u_long count) 779{ 780 struct pccard_ivar *devi = PCCARD_IVAR(child); 781 struct resource_list *rl = &devi->resources; 782 783 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 784 && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 785 return EINVAL; 786 if (rid < 0) 787 return EINVAL; 788 if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 789 return EINVAL; 790 if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 791 return EINVAL; 792 if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 793 return EINVAL; 794 if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 795 return EINVAL; 796 797 resource_list_add(rl, type, rid, start, start + count - 1, count); 798 799 return 0; 800} 801 802static int 803pccard_get_resource(device_t dev, device_t child, int type, int rid, 804 u_long *startp, u_long *countp) 805{ 806 struct pccard_ivar *devi = PCCARD_IVAR(child); 807 struct resource_list *rl = &devi->resources; 808 struct resource_list_entry *rle; 809 810 rle = resource_list_find(rl, type, rid); 811 if (!rle) 812 return ENOENT; 813 814 if (startp) 815 *startp = rle->start; 816 if (countp) 817 *countp = rle->count; 818 819 return 0; 820} 821 822static void 823pccard_delete_resource(device_t dev, device_t child, int type, int rid) 824{ 825 struct pccard_ivar *devi = PCCARD_IVAR(child); 826 struct resource_list *rl = &devi->resources; 827 resource_list_delete(rl, type, rid); 828} 829 830static int 831pccard_set_res_flags(device_t dev, device_t child, int type, int rid, 832 u_int32_t flags) 833{ 834 return CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 835 rid, flags); 836} 837 838static int 839pccard_set_memory_offset(device_t dev, device_t child, int rid, 840 u_int32_t offset, u_int32_t *deltap) 841 842{ 843 return CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 844 offset, deltap); 845} 846 847static int 848pccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 849{ 850 struct pccard_ivar *devi = PCCARD_IVAR(child); 851 struct pccard_function *func = devi->fcn; 852 struct pccard_softc *sc = PCCARD_SOFTC(bus); 853 854 /* PCCARD_IVAR_ETHADDR unhandled from oldcard */ 855 switch (which) { 856 default: 857 case PCCARD_IVAR_ETHADDR: 858 return (ENOENT); 859 break; 860 case PCCARD_IVAR_VENDOR: 861 *(u_int32_t *) result = sc->card.manufacturer; 862 break; 863 case PCCARD_IVAR_PRODUCT: 864 *(u_int32_t *) result = sc->card.product; 865 break; 866 case PCCARD_IVAR_FUNCTION_NUMBER: 867 if (!func) { 868 device_printf(bus, "No function number, bug!\n"); 869 return (ENOENT); 870 } 871 *(u_int32_t *) result = func->number; 872 break; 873 case PCCARD_IVAR_VENDOR_STR: 874 *(char **) result = sc->card.cis1_info[0]; 875 break; 876 case PCCARD_IVAR_PRODUCT_STR: 877 *(char **) result = sc->card.cis1_info[1]; 878 break; 879 case PCCARD_IVAR_CIS3_STR: 880 *(char **) result = sc->card.cis1_info[2]; 881 break; 882 case PCCARD_IVAR_CIS4_STR: 883 *(char **) result = sc->card.cis1_info[2]; 884 break; 885 } 886 return (0); 887} 888 889static void 890pccard_driver_added(device_t dev, driver_t *driver) 891{ 892 /* 893 * XXX eventually we need to attach stuff when we know we 894 * XXX have kids. For now we do nothing because we normally 895 * XXX add children ourselves. We don't want to necessarily 896 * XXX force a reprobe. 897 */ 898} 899 900static struct resource * 901pccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 902 u_long start, u_long end, u_long count, u_int flags) 903{ 904 struct resource_list_entry *rle = NULL; 905 906 /* XXX: This is an ugly way to fudge the resources. */ 907 908 if (device_get_parent(child) == dev) { 909 struct pccard_ivar *devi = PCCARD_IVAR(child); 910 struct resource_list *rl = &devi->resources; 911 912 rle = resource_list_find(rl, type, *rid); 913 } 914 915 if (rle != NULL) { 916 if (flags & RF_ACTIVE) 917 bus_activate_resource(dev, type, rle->rid, rle->res); 918 return (rle->res); 919 } 920 return (bus_generic_alloc_resource(dev, child, type, rid, start, 921 end, count, flags)); 922} 923 924static int 925pccard_release_resource(device_t dev, device_t child, int type, int rid, 926 struct resource *r) 927{ 928 struct resource_list_entry *rle = NULL; 929 930 if (device_get_parent(child) == dev) { 931 struct pccard_ivar *devi = PCCARD_IVAR(child); 932 struct resource_list *rl = &devi->resources; 933 934 rle = resource_list_find(rl, type, rid); 935 } 936 937 if (rle != NULL) { 938 return bus_release_resource(dev, type, rle->rid, rle->res); 939 } 940 941 return bus_generic_release_resource(dev, child, type, rid, r); 942} 943 944static int 945pccard_activate_resource(device_t dev, device_t child, int type, int rid, 946 struct resource *r) 947{ 948 /* XXX need to write to the COR to activate this for mf cards */ 949 struct resource_list_entry *rle = NULL; 950 951 if (device_get_parent(child) == dev) { 952 struct pccard_ivar *devi = PCCARD_IVAR(child); 953 struct resource_list *rl = &devi->resources; 954 955 rle = resource_list_find(rl, type, rid); 956 } 957 958 if (rle != NULL) { 959 return (bus_activate_resource(dev, type, rle->rid, rle->res)); 960 } 961 962 return (bus_generic_activate_resource(dev, child, type, rid, r)); 963} 964 965static int 966pccard_deactivate_resource(device_t dev, device_t child, int type, int rid, 967 struct resource *r) 968{ 969 /* XXX need to write to the COR to deactivate this for mf cards */ 970 struct resource_list_entry *rle = NULL; 971 972 if (device_get_parent(child) == dev) { 973 struct pccard_ivar *devi = PCCARD_IVAR(child); 974 struct resource_list *rl = &devi->resources; 975 976 rle = resource_list_find(rl, type, rid); 977 } 978 979 if (rle != NULL) { 980 return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); 981 } 982 983 return (bus_generic_deactivate_resource(dev, child, type, rid, r)); 984} 985 986static void 987pccard_child_detached(device_t parent, device_t dev) 988{ 989 struct pccard_ivar *ivar = PCCARD_IVAR(dev); 990 991 if (parent == device_get_parent(dev)) 992 free(ivar, M_DEVBUF); 993} 994 995static void 996pccard_intr(void *arg) { 997 struct pccard_function *pf; 998 STAILQ_FOREACH(pf, &((struct pccard_softc*)arg)->card.pf_head, pf_list) { 999 if (pf->intr_handler != NULL) { 1000 int reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1001 if (reg & PCCARD_CCR_STATUS_INTR) { 1002 pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1003 reg & ~PCCARD_CCR_STATUS_INTR); 1004 pf->intr_handler(pf->intr_handler_arg); 1005 } 1006 } 1007 } 1008} 1009 1010static int 1011pccard_setup_intr(device_t dev, device_t child, 1012 struct resource *irq, int flags, 1013 driver_intr_t *intr, void *arg, void **cookiep) 1014{ 1015 struct pccard_ivar *ivar = PCCARD_IVAR(child); 1016 struct pccard_function *func = ivar->fcn; 1017 struct resource_list_entry *rle = NULL; 1018 struct pccard_softc *sc = device_get_softc(dev); 1019 1020 if (func->intr_handler != NULL) 1021 panic("Only one interrupt handler per function allowed for pccard\n"); 1022 1023 rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 1024 if (rle == NULL || rle->res != irq) 1025 panic("irq in setup_intr does not match allocated irq\n"); 1026 1027 func->intr_handler = intr; 1028 func->intr_handler_arg = arg; 1029 func->intr_handler_cookie = *cookiep = func; 1030 pccard_ccr_write(func, PCCARD_CCR_OPTION, 1031 pccard_ccr_read(func, PCCARD_CCR_OPTION) | 1032 PCCARD_CCR_OPTION_IREQ_ENABLE); 1033 1034 if (sc->intr_handler_count++ == 0) { 1035 rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 1036 if (rle == NULL) 1037 panic("No IRQ for pccard?"); 1038 1039 bus_setup_intr(dev, rle->res, INTR_TYPE_TTY/* | INTR_FAST*/, 1040 pccard_intr, sc, (void*)&sc->intr_handler_count); 1041 } 1042 return 0; 1043} 1044 1045static int 1046pccard_teardown_intr(device_t dev, device_t child, struct resource *r, void *cookie) 1047{ 1048 struct pccard_ivar *ivar = PCCARD_IVAR(child); 1049 struct pccard_function *func = ivar->fcn; 1050 struct pccard_softc *sc = device_get_softc(dev); 1051 1052 if (func->intr_handler_cookie != cookie) 1053 panic("pccard teardown of unknown interrupt handler\n"); 1054 1055 func->intr_handler = NULL; 1056 func->intr_handler_arg = NULL; 1057 func->intr_handler_cookie = NULL; 1058 pccard_ccr_write(func, PCCARD_CCR_OPTION, 1059 pccard_ccr_read(func, PCCARD_CCR_OPTION) & 1060 ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1061 1062 if (--sc->intr_handler_count == 0) { 1063 struct resource_list_entry *rle = NULL; 1064 1065 rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 1066 if (rle == NULL) 1067 panic("No IRQ for pccard?"); 1068 1069 bus_teardown_intr(dev, rle->res, &sc->intr_handler_count); 1070 } 1071 return 0; 1072} 1073 1074static device_method_t pccard_methods[] = { 1075 /* Device interface */ 1076 DEVMETHOD(device_probe, pccard_probe), 1077 DEVMETHOD(device_attach, pccard_attach), 1078 DEVMETHOD(device_detach, bus_generic_detach), 1079 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1080 DEVMETHOD(device_suspend, bus_generic_suspend), 1081 DEVMETHOD(device_resume, bus_generic_resume), 1082 1083 /* Bus interface */ 1084 DEVMETHOD(bus_print_child, pccard_print_child), 1085 DEVMETHOD(bus_driver_added, pccard_driver_added), 1086 DEVMETHOD(bus_child_detached, pccard_child_detached), 1087 DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 1088 DEVMETHOD(bus_release_resource, pccard_release_resource), 1089 DEVMETHOD(bus_activate_resource, pccard_activate_resource), 1090 DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 1091 DEVMETHOD(bus_setup_intr, pccard_setup_intr), 1092 DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 1093 DEVMETHOD(bus_set_resource, pccard_set_resource), 1094 DEVMETHOD(bus_get_resource, pccard_get_resource), 1095 DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1096 DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1097 1098 /* Card Interface */ 1099 DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 1100 DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 1101 DEVMETHOD(card_get_type, pccard_card_gettype), 1102 DEVMETHOD(card_attach_card, pccard_attach_card), 1103 DEVMETHOD(card_detach_card, pccard_detach_card), 1104 1105 { 0, 0 } 1106}; 1107 1108static driver_t pccard_driver = { 1109 "pccard", 1110 pccard_methods, 1111 sizeof(struct pccard_softc) 1112}; 1113 1114devclass_t pccard_devclass; 1115 1116DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 1117DRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 1118DRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0); 1119DRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 1120MODULE_VERSION(pccard, 1); 1121/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/ 1122