1 /*- 2 * Copyright (c) 2002-2005 M Warner Losh. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * This software may be derived from NetBSD i82365.c and other files with 25 * the following copyright: 26 * 27 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 1. Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * 2. Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in the 36 * documentation and/or other materials provided with the distribution. 37 * 3. All advertising materials mentioning features or use of this software 38 * must display the following acknowledgement: 39 * This product includes software developed by Marc Horowitz. 40 * 4. The name of the author may not be used to endorse or promote products 41 * derived from this software without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 #include <sys/cdefs.h> 56 __FBSDID("$FreeBSD$"); 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/condvar.h> 61 #include <sys/errno.h> 62 #include <sys/kernel.h> 63 #include <sys/malloc.h> 64 #include <sys/queue.h> 65 #include <sys/module.h> 66 #include <sys/lock.h> 67 #include <sys/mutex.h> 68 #include <sys/conf.h> 69 70 #include <sys/bus.h> 71 #include <machine/bus.h> 72 #include <sys/rman.h> 73 #include <machine/resource.h> 74 75 #include <dev/pccard/pccardreg.h> 76 #include <dev/pccard/pccardvar.h> 77 78 #include <dev/exca/excareg.h> 79 #include <dev/exca/excavar.h> 80 81 #ifdef EXCA_DEBUG 82 #define DEVPRINTF(dev, fmt, args...) device_printf((dev), (fmt), ## args) 83 #define DPRINTF(fmt, args...) printf(fmt, ## args) 84 #else 85 #define DEVPRINTF(dev, fmt, args...) 86 #define DPRINTF(fmt, args...) 87 #endif 88 89 static const char *chip_names[] = 90 { 91 "CardBus socket", 92 "Intel i82365SL-A/B or clone", 93 "Intel i82365sl-DF step", 94 "VLSI chip", 95 "Cirrus Logic PD6710", 96 "Cirrus logic PD6722", 97 "Cirrus Logic PD6729", 98 "Vadem 365", 99 "Vadem 465", 100 "Vadem 468", 101 "Vadem 469", 102 "Ricoh RF5C296", 103 "Ricoh RF5C396", 104 "IBM clone", 105 "IBM KING PCMCIA Controller" 106 }; 107 108 static exca_getb_fn exca_mem_getb; 109 static exca_putb_fn exca_mem_putb; 110 static exca_getb_fn exca_io_getb; 111 static exca_putb_fn exca_io_putb; 112 113 /* memory */ 114 115 #define EXCA_MEMINFO(NUM) { \ 116 EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \ 117 EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \ 118 EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ 119 EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ 120 EXCA_SYSMEM_ADDR ## NUM ## _WIN, \ 121 EXCA_CARDMEM_ADDR ## NUM ## _LSB, \ 122 EXCA_CARDMEM_ADDR ## NUM ## _MSB, \ 123 EXCA_ADDRWIN_ENABLE_MEM ## NUM, \ 124 } 125 126 static struct mem_map_index_st { 127 int sysmem_start_lsb; 128 int sysmem_start_msb; 129 int sysmem_stop_lsb; 130 int sysmem_stop_msb; 131 int sysmem_win; 132 int cardmem_lsb; 133 int cardmem_msb; 134 int memenable; 135 } mem_map_index[] = { 136 EXCA_MEMINFO(0), 137 EXCA_MEMINFO(1), 138 EXCA_MEMINFO(2), 139 EXCA_MEMINFO(3), 140 EXCA_MEMINFO(4) 141 }; 142 #undef EXCA_MEMINFO 143 144 static uint8_t 145 exca_mem_getb(struct exca_softc *sc, int reg) 146 { 147 return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg)); 148 } 149 150 static void 151 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val) 152 { 153 bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val); 154 } 155 156 static uint8_t 157 exca_io_getb(struct exca_softc *sc, int reg) 158 { 159 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 160 return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA)); 161 } 162 163 static void 164 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val) 165 { 166 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 167 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val); 168 } 169 170 /* 171 * Helper function. This will map the requested memory slot. We setup the 172 * map before we call this function. This is used to initially force the 173 * mapping, as well as later restore the mapping after it has been destroyed 174 * in some fashion (due to a power event typically). 175 */ 176 static void 177 exca_do_mem_map(struct exca_softc *sc, int win) 178 { 179 struct mem_map_index_st *map; 180 struct pccard_mem_handle *mem; 181 uint32_t offset; 182 int mem8 = (mem->kind == PCCARD_A_MEM_ATTR); 183 mem8 = 1; 184 185 map = &mem_map_index[win]; 186 mem = &sc->mem[win]; 187 offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 188 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 189 exca_putb(sc, map->sysmem_start_lsb, 190 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 191 exca_putb(sc, map->sysmem_start_msb, 192 ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 193 EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | 194 (mem8 ? 0 : EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT)); 195 196 exca_putb(sc, map->sysmem_stop_lsb, 197 ((mem->addr + mem->realsize - 1) >> 198 EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 199 exca_putb(sc, map->sysmem_stop_msb, 200 (((mem->addr + mem->realsize - 1) >> 201 (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 202 EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | 203 EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); 204 205 exca_putb(sc, map->sysmem_win, 206 (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff); 207 208 exca_putb(sc, map->cardmem_lsb, offset & 0xff); 209 exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) & 210 EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | 211 ((mem->kind == PCCARD_A_MEM_ATTR) ? 212 EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0)); 213 214 #ifdef EXCA_DEBUG 215 if (mem->kind == PCCARD_A_MEM_ATTR) 216 printf("attribtue memory\n"); 217 else 218 printf("common memory\n"); 219 #endif 220 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | 221 EXCA_ADDRWIN_ENABLE_MEMCS16); 222 223 DELAY(100); 224 #ifdef EXCA_DEBUG 225 { 226 int r1, r2, r3, r4, r5, r6, r7; 227 r1 = exca_getb(sc, map->sysmem_start_msb); 228 r2 = exca_getb(sc, map->sysmem_start_lsb); 229 r3 = exca_getb(sc, map->sysmem_stop_msb); 230 r4 = exca_getb(sc, map->sysmem_stop_lsb); 231 r5 = exca_getb(sc, map->cardmem_msb); 232 r6 = exca_getb(sc, map->cardmem_lsb); 233 r7 = exca_getb(sc, map->sysmem_win); 234 printf("exca_do_mem_map win %d: %02x%02x %02x%02x " 235 "%02x%02x %02x (%08x+%06x.%06x*%06x)\n", 236 win, r1, r2, r3, r4, r5, r6, r7, 237 mem->addr, mem->size, mem->realsize, 238 mem->cardaddr); 239 } 240 #endif 241 } 242 243 /* 244 * public interface to map a resource. kind is the type of memory to 245 * map (either common or attribute). Memory created via this interface 246 * starts out at card address 0. Since the only way to set this is 247 * to set it on a struct resource after it has been mapped, we're safe 248 * in maping this assumption. Note that resources can be remapped using 249 * exca_do_mem_map so that's how the card address can be set later. 250 */ 251 int 252 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 253 { 254 int win; 255 256 for (win = 0; win < EXCA_MEM_WINS; win++) { 257 if ((sc->memalloc & (1 << win)) == 0) { 258 sc->memalloc |= (1 << win); 259 break; 260 } 261 } 262 if (win >= EXCA_MEM_WINS) 263 return (1); 264 if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 && 265 (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) { 266 device_printf(sc->dev, "Does not support mapping above 24M."); 267 return (1); 268 } 269 270 sc->mem[win].cardaddr = 0; 271 sc->mem[win].memt = rman_get_bustag(res); 272 sc->mem[win].memh = rman_get_bushandle(res); 273 sc->mem[win].addr = rman_get_start(res); 274 sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 275 sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 276 sc->mem[win].realsize = sc->mem[win].realsize - 277 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 278 sc->mem[win].kind = kind; 279 DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", 280 win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); 281 exca_do_mem_map(sc, win); 282 283 return (0); 284 } 285 286 /* 287 * Private helper function. This turns off a given memory map that is in 288 * use. We do this by just clearing the enable bit in the pcic. If we needed 289 * to make memory unmapping/mapping pairs faster, we would have to store 290 * more state information about the pcic and then use that to intelligently 291 * to the map/unmap. However, since we don't do that sort of thing often 292 * (generally just at configure time), it isn't a case worth optimizing. 293 */ 294 static void 295 exca_mem_unmap(struct exca_softc *sc, int window) 296 { 297 if (window < 0 || window >= EXCA_MEM_WINS) 298 panic("exca_mem_unmap: window out of range"); 299 300 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 301 sc->memalloc &= ~(1 << window); 302 } 303 304 /* 305 * Find the map that we're using to hold the resoruce. This works well 306 * so long as the client drivers don't do silly things like map the same 307 * area mutliple times, or map both common and attribute memory at the 308 * same time. This latter restriction is a bug. We likely should just 309 * store a pointer to the res in the mem[x] data structure. 310 */ 311 static int 312 exca_mem_findmap(struct exca_softc *sc, struct resource *res) 313 { 314 int win; 315 316 for (win = 0; win < EXCA_MEM_WINS; win++) { 317 if (sc->mem[win].memt == rman_get_bustag(res) && 318 sc->mem[win].addr == rman_get_start(res) && 319 sc->mem[win].size == rman_get_size(res)) 320 return (win); 321 } 322 return (-1); 323 } 324 325 /* 326 * Set the memory flag. This means that we are setting if the memory 327 * is coming from attribute memory or from common memory on the card. 328 * CIS entries are generally in attribute memory (although they can 329 * reside in common memory). Generally, this is the only use for attribute 330 * memory. However, some cards require their drivers to dance in both 331 * common and/or attribute memory and this interface (and setting the 332 * offset interface) exist for such cards. 333 */ 334 int 335 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 336 { 337 int win; 338 339 win = exca_mem_findmap(sc, res); 340 if (win < 0) { 341 device_printf(sc->dev, 342 "set_res_flags: specified resource not active\n"); 343 return (ENOENT); 344 } 345 346 sc->mem[win].kind = flags; 347 exca_do_mem_map(sc, win); 348 return (0); 349 } 350 351 /* 352 * Given a resource, go ahead and unmap it if we can find it in the 353 * resrouce list that's used. 354 */ 355 int 356 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 357 { 358 int win; 359 360 win = exca_mem_findmap(sc, res); 361 if (win < 0) 362 return (ENOENT); 363 exca_mem_unmap(sc, win); 364 return (0); 365 } 366 367 /* 368 * Set the offset of the memory. We use this for reading the CIS and 369 * frobbing the pccard's pccard registers (CCR, etc). Some drivers 370 * need to access arbitrary attribute and common memory during their 371 * initialization and operation. 372 */ 373 int 374 exca_mem_set_offset(struct exca_softc *sc, struct resource *res, 375 uint32_t cardaddr, uint32_t *deltap) 376 { 377 int win; 378 uint32_t delta; 379 380 win = exca_mem_findmap(sc, res); 381 if (win < 0) { 382 device_printf(sc->dev, 383 "set_memory_offset: specified resource not active\n"); 384 return (ENOENT); 385 } 386 sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1); 387 delta = cardaddr % EXCA_MEM_PAGESIZE; 388 if (deltap) 389 *deltap = delta; 390 sc->mem[win].realsize = sc->mem[win].size + delta + 391 EXCA_MEM_PAGESIZE - 1; 392 sc->mem[win].realsize = sc->mem[win].realsize - 393 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 394 exca_do_mem_map(sc, win); 395 return (0); 396 } 397 398 399 /* I/O */ 400 401 #define EXCA_IOINFO(NUM) { \ 402 EXCA_IOADDR ## NUM ## _START_LSB, \ 403 EXCA_IOADDR ## NUM ## _START_MSB, \ 404 EXCA_IOADDR ## NUM ## _STOP_LSB, \ 405 EXCA_IOADDR ## NUM ## _STOP_MSB, \ 406 EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 407 EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 408 | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 409 | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 410 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 411 { \ 412 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 413 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 414 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 415 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 416 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 417 } \ 418 } 419 420 static struct io_map_index_st { 421 int start_lsb; 422 int start_msb; 423 int stop_lsb; 424 int stop_msb; 425 int ioenable; 426 int ioctlmask; 427 int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 428 } io_map_index[] = { 429 EXCA_IOINFO(0), 430 EXCA_IOINFO(1), 431 }; 432 #undef EXCA_IOINFO 433 434 static void 435 exca_do_io_map(struct exca_softc *sc, int win) 436 { 437 struct io_map_index_st *map; 438 439 struct pccard_io_handle *io; 440 441 map = &io_map_index[win]; 442 io = &sc->io[win]; 443 exca_putb(sc, map->start_lsb, io->addr & 0xff); 444 exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); 445 446 exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 447 exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 448 449 exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 450 exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 451 452 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 453 #ifdef EXCA_DEBUG 454 { 455 int r1, r2, r3, r4; 456 r1 = exca_getb(sc, map->start_msb); 457 r2 = exca_getb(sc, map->start_lsb); 458 r3 = exca_getb(sc, map->stop_msb); 459 r4 = exca_getb(sc, map->stop_lsb); 460 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 461 "(%08x+%08x)\n", win, r1, r2, r3, r4, 462 io->addr, io->size); 463 } 464 #endif 465 } 466 467 int 468 exca_io_map(struct exca_softc *sc, int width, struct resource *r) 469 { 470 int win; 471 #ifdef EXCA_DEBUG 472 static char *width_names[] = { "auto", "io8", "io16"}; 473 #endif 474 for (win=0; win < EXCA_IO_WINS; win++) { 475 if ((sc->ioalloc & (1 << win)) == 0) { 476 sc->ioalloc |= (1 << win); 477 break; 478 } 479 } 480 if (win >= EXCA_IO_WINS) 481 return (1); 482 483 sc->io[win].iot = rman_get_bustag(r); 484 sc->io[win].ioh = rman_get_bushandle(r); 485 sc->io[win].addr = rman_get_start(r); 486 sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 487 sc->io[win].flags = 0; 488 sc->io[win].width = width; 489 DPRINTF("exca_io_map window %d %s port %x+%x\n", 490 win, width_names[width], sc->io[win].addr, 491 sc->io[win].size); 492 exca_do_io_map(sc, win); 493 494 return (0); 495 } 496 497 static void 498 exca_io_unmap(struct exca_softc *sc, int window) 499 { 500 if (window >= EXCA_IO_WINS) 501 panic("exca_io_unmap: window out of range"); 502 503 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 504 505 sc->ioalloc &= ~(1 << window); 506 507 sc->io[window].iot = 0; 508 sc->io[window].ioh = 0; 509 sc->io[window].addr = 0; 510 sc->io[window].size = 0; 511 sc->io[window].flags = 0; 512 sc->io[window].width = 0; 513 } 514 515 static int 516 exca_io_findmap(struct exca_softc *sc, struct resource *res) 517 { 518 int win; 519 520 for (win = 0; win < EXCA_IO_WINS; win++) { 521 if (sc->io[win].iot == rman_get_bustag(res) && 522 sc->io[win].addr == rman_get_start(res) && 523 sc->io[win].size == rman_get_size(res)) 524 return (win); 525 } 526 return (-1); 527 } 528 529 530 int 531 exca_io_unmap_res(struct exca_softc *sc, struct resource *res) 532 { 533 int win; 534 535 win = exca_io_findmap(sc, res); 536 if (win < 0) 537 return (ENOENT); 538 exca_io_unmap(sc, win); 539 return (0); 540 } 541 542 /* Misc */ 543 544 /* 545 * If interrupts are enabled, then we should be able to just wait for 546 * an interrupt routine to wake us up. Busy waiting shouldn't be 547 * necessary. Sadly, not all legacy ISA cards support an interrupt 548 * for the busy state transitions, at least according to their datasheets, 549 * so we busy wait a while here.. 550 */ 551 static void 552 exca_wait_ready(struct exca_softc *sc) 553 { 554 int i; 555 DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 556 exca_getb(sc, EXCA_IF_STATUS)); 557 for (i = 0; i < 10000; i++) { 558 if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 559 return; 560 DELAY(500); 561 } 562 device_printf(sc->dev, "ready never happened, status = %02x\n", 563 exca_getb(sc, EXCA_IF_STATUS)); 564 } 565 566 /* 567 * Reset the card. Ideally, we'd do a lot of this via interrupts. 568 * However, many PC Cards will deassert the ready signal. This means 569 * that they are asserting an interrupt. This makes it hard to 570 * do anything but a busy wait here. One could argue that these 571 * such cards are broken, or that the bridge that allows this sort 572 * of interrupt through isn't quite what you'd want (and may be a standards 573 * violation). However, such arguing would leave a huge class of PC Cards 574 * and bridges out of reach for use in the system. 575 * 576 * Maybe I should reevaluate the above based on the power bug I fixed 577 * in OLDCARD. 578 */ 579 void 580 exca_reset(struct exca_softc *sc, device_t child) 581 { 582 int win; 583 584 /* enable socket i/o */ 585 exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 586 587 exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); 588 /* hold reset for 30ms */ 589 DELAY(30*1000); 590 /* clear the reset flag */ 591 exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 592 /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ 593 DELAY(20*1000); 594 595 exca_wait_ready(sc); 596 597 /* disable all address windows */ 598 exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); 599 600 exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); 601 DEVPRINTF(sc->dev, "card type is io\n"); 602 603 /* reinstall all the memory and io mappings */ 604 for (win = 0; win < EXCA_MEM_WINS; ++win) 605 if (sc->memalloc & (1 << win)) 606 exca_do_mem_map(sc, win); 607 for (win = 0; win < EXCA_IO_WINS; ++win) 608 if (sc->ioalloc & (1 << win)) 609 exca_do_io_map(sc, win); 610 } 611 612 /* 613 * Initialize the exca_softc data structure for the first time. 614 */ 615 void 616 exca_init(struct exca_softc *sc, device_t dev, 617 bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) 618 { 619 sc->dev = dev; 620 sc->memalloc = 0; 621 sc->ioalloc = 0; 622 sc->bst = bst; 623 sc->bsh = bsh; 624 sc->offset = offset; 625 sc->flags = 0; 626 sc->getb = exca_mem_getb; 627 sc->putb = exca_mem_putb; 628 } 629 630 /* 631 * Is this socket valid? 632 */ 633 static int 634 exca_valid_slot(struct exca_softc *exca) 635 { 636 uint8_t c; 637 638 /* Assume the worst */ 639 exca->chipset = EXCA_BOGUS; 640 641 /* 642 * see if there's a PCMCIA controller here 643 * Intel PCMCIA controllers use 0x82 and 0x83 644 * IBM clone chips use 0x88 and 0x89, apparently 645 */ 646 c = exca_getb(exca, EXCA_IDENT); 647 DEVPRINTF(exca->dev, "Ident is %x\n", c); 648 if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 649 return (0); 650 if ((c & EXCA_IDENT_ZERO) != 0) 651 return (0); 652 switch (c & EXCA_IDENT_REV_MASK) { 653 /* 654 * 82365 or clones. 655 */ 656 case EXCA_IDENT_REV_I82365SLR0: 657 case EXCA_IDENT_REV_I82365SLR1: 658 exca->chipset = EXCA_I82365; 659 /* 660 * Check for Vadem chips by unlocking their extra 661 * registers and looking for valid ID. Bit 3 in 662 * the ID register is normally 0, except when 663 * EXCA_VADEMREV is set. Other bridges appear 664 * to ignore this frobbing. 665 */ 666 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 667 EXCA_VADEM_COOKIE1); 668 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 669 EXCA_VADEM_COOKIE2); 670 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 671 c = exca_getb(exca, EXCA_IDENT); 672 if (c & 0x08) { 673 switch (c & 7) { 674 case 1: 675 exca->chipset = EXCA_VG365; 676 break; 677 case 2: 678 exca->chipset = EXCA_VG465; 679 break; 680 case 3: 681 exca->chipset = EXCA_VG468; 682 break; 683 default: 684 exca->chipset = EXCA_VG469; 685 break; 686 } 687 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 688 break; 689 } 690 /* 691 * Check for RICOH RF5C[23]96 PCMCIA Controller 692 */ 693 c = exca_getb(exca, EXCA_RICOH_ID); 694 if (c == EXCA_RID_396) { 695 exca->chipset = EXCA_RF5C396; 696 break; 697 } else if (c == EXCA_RID_296) { 698 exca->chipset = EXCA_RF5C296; 699 break; 700 } 701 /* 702 * Check for Cirrus logic chips. 703 */ 704 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 705 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 706 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 707 EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 708 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 709 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 710 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 711 exca->chipset = EXCA_PD6722; 712 else 713 exca->chipset = EXCA_PD6710; 714 break; 715 } 716 } 717 break; 718 719 case EXCA_IDENT_REV_I82365SLDF: 720 /* 721 * Intel i82365sl-DF step or maybe a vlsi 82c146 722 * we detected the vlsi case earlier, so if the controller 723 * isn't set, we know it is a i82365sl step D. 724 */ 725 exca->chipset = EXCA_I82365SL_DF; 726 break; 727 case EXCA_IDENT_REV_IBM1: 728 case EXCA_IDENT_REV_IBM2: 729 exca->chipset = EXCA_IBM; 730 break; 731 case EXCA_IDENT_REV_IBM_KING: 732 exca->chipset = EXCA_IBM_KING; 733 break; 734 default: 735 return (0); 736 } 737 return (1); 738 } 739 740 /* 741 * Probe the expected slots. We maybe should set the ID for each of these 742 * slots too while we're at it. But maybe that belongs to a separate 743 * function. 744 * 745 * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 746 */ 747 int 748 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 749 bus_space_handle_t ioh) 750 { 751 int err; 752 int i; 753 754 err = ENXIO; 755 for (i = 0; i < EXCA_NSLOTS; i++) { 756 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 757 exca->getb = exca_io_getb; 758 exca->putb = exca_io_putb; 759 if (exca_valid_slot(&exca[i])) { 760 device_set_desc(dev, chip_names[exca[i].chipset]); 761 err = 0; 762 } 763 } 764 return (err); 765 } 766 767 void 768 exca_insert(struct exca_softc *exca) 769 { 770 if (exca->pccarddev != NULL) { 771 if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 772 device_printf(exca->dev, 773 "PC Card card activation failed\n"); 774 } else { 775 device_printf(exca->dev, 776 "PC Card inserted, but no pccard bus.\n"); 777 } 778 } 779 780 781 void 782 exca_removal(struct exca_softc *exca) 783 { 784 if (exca->pccarddev != NULL) 785 CARD_DETACH_CARD(exca->pccarddev); 786 } 787 788 int 789 exca_activate_resource(struct exca_softc *exca, device_t child, int type, 790 int rid, struct resource *res) 791 { 792 int err; 793 if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */ 794 switch (type) { 795 case SYS_RES_IOPORT: 796 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 797 break; 798 case SYS_RES_MEMORY: 799 err = exca_mem_map(exca, PCCARD_A_MEM_COM, res); 800 break; 801 default: 802 err = 0; 803 break; 804 } 805 if (err) 806 return (err); 807 808 } 809 return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 810 type, rid, res)); 811 } 812 813 int 814 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 815 int rid, struct resource *res) 816 { 817 if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 818 switch (type) { 819 case SYS_RES_IOPORT: 820 if (exca_io_unmap_res(exca, res)) 821 return (ENOENT); 822 break; 823 case SYS_RES_MEMORY: 824 if (exca_mem_unmap_res(exca, res)) 825 return (ENOENT); 826 break; 827 } 828 } 829 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 830 type, rid, res)); 831 } 832 833 #if 0 834 static struct resource * 835 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 836 u_long start, u_long end, u_long count, uint flags) 837 { 838 struct resource *res = NULL; 839 int tmp; 840 841 switch (type) { 842 case SYS_RES_MEMORY: 843 if (start < cbb_start_mem) 844 start = cbb_start_mem; 845 if (end < start) 846 end = start; 847 flags = (flags & ~RF_ALIGNMENT_MASK) | 848 rman_make_alignment_flags(CBB_MEMALIGN); 849 break; 850 case SYS_RES_IOPORT: 851 if (start < cbb_start_16_io) 852 start = cbb_start_16_io; 853 if (end < start) 854 end = start; 855 break; 856 case SYS_RES_IRQ: 857 tmp = rman_get_start(sc->irq_res); 858 if (start > tmp || end < tmp || count != 1) { 859 device_printf(child, "requested interrupt %ld-%ld," 860 "count = %ld not supported by cbb\n", 861 start, end, count); 862 return (NULL); 863 } 864 flags |= RF_SHAREABLE; 865 start = end = rman_get_start(sc->irq_res); 866 break; 867 } 868 res = BUS_ALLOC_RESOURCE(up, child, type, rid, 869 start, end, count, flags & ~RF_ACTIVE); 870 if (res == NULL) 871 return (NULL); 872 cbb_insert_res(sc, res, type, *rid); 873 if (flags & RF_ACTIVE) { 874 if (bus_activate_resource(child, type, *rid, res) != 0) { 875 bus_release_resource(child, type, *rid, res); 876 return (NULL); 877 } 878 } 879 880 return (res); 881 } 882 883 static int 884 exca_release_resource(struct exca_softc *sc, device_t child, int type, 885 int rid, struct resource *res) 886 { 887 int error; 888 889 if (rman_get_flags(res) & RF_ACTIVE) { 890 error = bus_deactivate_resource(child, type, rid, res); 891 if (error != 0) 892 return (error); 893 } 894 cbb_remove_res(sc, res); 895 return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 896 type, rid, res)); 897 } 898 #endif 899 900 static int 901 exca_modevent(module_t mod, int cmd, void *arg) 902 { 903 return 0; 904 } 905 906 DEV_MODULE(exca, exca_modevent, NULL); 907 MODULE_VERSION(exca, 1); 908