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 = 1 /* mem->kind == PCCARD_A_MEM_ATTR */; 183 184 map = &mem_map_index[win]; 185 mem = &sc->mem[win]; 186 offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 187 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 188 exca_putb(sc, map->sysmem_start_lsb, 189 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 190 exca_putb(sc, map->sysmem_start_msb, 191 ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 192 EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | 193 (mem8 ? 0 : EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT)); 194 195 exca_putb(sc, map->sysmem_stop_lsb, 196 ((mem->addr + mem->realsize - 1) >> 197 EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 198 exca_putb(sc, map->sysmem_stop_msb, 199 (((mem->addr + mem->realsize - 1) >> 200 (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 201 EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | 202 EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); 203 204 exca_putb(sc, map->sysmem_win, 205 (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff); 206 207 exca_putb(sc, map->cardmem_lsb, offset & 0xff); 208 exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) & 209 EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | 210 ((mem->kind == PCCARD_A_MEM_ATTR) ? 211 EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0)); 212 213 #ifdef EXCA_DEBUG 214 if (mem->kind == PCCARD_A_MEM_ATTR) 215 printf("attribtue memory\n"); 216 else 217 printf("common memory\n"); 218 #endif 219 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | 220 EXCA_ADDRWIN_ENABLE_MEMCS16); 221 222 DELAY(100); 223 #ifdef EXCA_DEBUG 224 { 225 int r1, r2, r3, r4, r5, r6, r7; 226 r1 = exca_getb(sc, map->sysmem_start_msb); 227 r2 = exca_getb(sc, map->sysmem_start_lsb); 228 r3 = exca_getb(sc, map->sysmem_stop_msb); 229 r4 = exca_getb(sc, map->sysmem_stop_lsb); 230 r5 = exca_getb(sc, map->cardmem_msb); 231 r6 = exca_getb(sc, map->cardmem_lsb); 232 r7 = exca_getb(sc, map->sysmem_win); 233 printf("exca_do_mem_map win %d: %02x%02x %02x%02x " 234 "%02x%02x %02x (%08x+%06x.%06x*%06x)\n", 235 win, r1, r2, r3, r4, r5, r6, r7, 236 mem->addr, mem->size, mem->realsize, 237 mem->cardaddr); 238 } 239 #endif 240 } 241 242 /* 243 * public interface to map a resource. kind is the type of memory to 244 * map (either common or attribute). Memory created via this interface 245 * starts out at card address 0. Since the only way to set this is 246 * to set it on a struct resource after it has been mapped, we're safe 247 * in maping this assumption. Note that resources can be remapped using 248 * exca_do_mem_map so that's how the card address can be set later. 249 */ 250 int 251 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 252 { 253 int win; 254 255 for (win = 0; win < EXCA_MEM_WINS; win++) { 256 if ((sc->memalloc & (1 << win)) == 0) { 257 sc->memalloc |= (1 << win); 258 break; 259 } 260 } 261 if (win >= EXCA_MEM_WINS) 262 return (ENOSPC); 263 if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 && 264 (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) { 265 device_printf(sc->dev, "Does not support mapping above 24M."); 266 return (EINVAL); 267 } 268 269 sc->mem[win].cardaddr = 0; 270 sc->mem[win].memt = rman_get_bustag(res); 271 sc->mem[win].memh = rman_get_bushandle(res); 272 sc->mem[win].addr = rman_get_start(res); 273 sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 274 sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 275 sc->mem[win].realsize = sc->mem[win].realsize - 276 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 277 sc->mem[win].kind = kind; 278 DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", 279 win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); 280 exca_do_mem_map(sc, win); 281 282 return (0); 283 } 284 285 /* 286 * Private helper function. This turns off a given memory map that is in 287 * use. We do this by just clearing the enable bit in the pcic. If we needed 288 * to make memory unmapping/mapping pairs faster, we would have to store 289 * more state information about the pcic and then use that to intelligently 290 * to the map/unmap. However, since we don't do that sort of thing often 291 * (generally just at configure time), it isn't a case worth optimizing. 292 */ 293 static void 294 exca_mem_unmap(struct exca_softc *sc, int window) 295 { 296 if (window < 0 || window >= EXCA_MEM_WINS) 297 panic("exca_mem_unmap: window out of range"); 298 299 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 300 sc->memalloc &= ~(1 << window); 301 } 302 303 /* 304 * Find the map that we're using to hold the resource. This works well 305 * so long as the client drivers don't do silly things like map the same 306 * area mutliple times, or map both common and attribute memory at the 307 * same time. This latter restriction is a bug. We likely should just 308 * store a pointer to the res in the mem[x] data structure. 309 */ 310 static int 311 exca_mem_findmap(struct exca_softc *sc, struct resource *res) 312 { 313 int win; 314 315 for (win = 0; win < EXCA_MEM_WINS; win++) { 316 if (sc->mem[win].memt == rman_get_bustag(res) && 317 sc->mem[win].addr == rman_get_start(res) && 318 sc->mem[win].size == rman_get_size(res)) 319 return (win); 320 } 321 return (-1); 322 } 323 324 /* 325 * Set the memory flag. This means that we are setting if the memory 326 * is coming from attribute memory or from common memory on the card. 327 * CIS entries are generally in attribute memory (although they can 328 * reside in common memory). Generally, this is the only use for attribute 329 * memory. However, some cards require their drivers to dance in both 330 * common and/or attribute memory and this interface (and setting the 331 * offset interface) exist for such cards. 332 */ 333 int 334 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 335 { 336 int win; 337 338 win = exca_mem_findmap(sc, res); 339 if (win < 0) { 340 device_printf(sc->dev, 341 "set_res_flags: specified resource not active\n"); 342 return (ENOENT); 343 } 344 345 sc->mem[win].kind = flags; 346 exca_do_mem_map(sc, win); 347 return (0); 348 } 349 350 /* 351 * Given a resource, go ahead and unmap it if we can find it in the 352 * resrouce list that's used. 353 */ 354 int 355 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 356 { 357 int win; 358 359 win = exca_mem_findmap(sc, res); 360 if (win < 0) 361 return (ENOENT); 362 exca_mem_unmap(sc, win); 363 return (0); 364 } 365 366 /* 367 * Set the offset of the memory. We use this for reading the CIS and 368 * frobbing the pccard's pccard registers (CCR, etc). Some drivers 369 * need to access arbitrary attribute and common memory during their 370 * initialization and operation. 371 */ 372 int 373 exca_mem_set_offset(struct exca_softc *sc, struct resource *res, 374 uint32_t cardaddr, uint32_t *deltap) 375 { 376 int win; 377 uint32_t delta; 378 379 win = exca_mem_findmap(sc, res); 380 if (win < 0) { 381 device_printf(sc->dev, 382 "set_memory_offset: specified resource not active\n"); 383 return (ENOENT); 384 } 385 sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1); 386 delta = cardaddr % EXCA_MEM_PAGESIZE; 387 if (deltap) 388 *deltap = delta; 389 sc->mem[win].realsize = sc->mem[win].size + delta + 390 EXCA_MEM_PAGESIZE - 1; 391 sc->mem[win].realsize = sc->mem[win].realsize - 392 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 393 exca_do_mem_map(sc, win); 394 return (0); 395 } 396 397 398 /* I/O */ 399 400 #define EXCA_IOINFO(NUM) { \ 401 EXCA_IOADDR ## NUM ## _START_LSB, \ 402 EXCA_IOADDR ## NUM ## _START_MSB, \ 403 EXCA_IOADDR ## NUM ## _STOP_LSB, \ 404 EXCA_IOADDR ## NUM ## _STOP_MSB, \ 405 EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 406 EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 407 | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 408 | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 409 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 410 { \ 411 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 412 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 413 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 414 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 415 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 416 } \ 417 } 418 419 static struct io_map_index_st { 420 int start_lsb; 421 int start_msb; 422 int stop_lsb; 423 int stop_msb; 424 int ioenable; 425 int ioctlmask; 426 int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 427 } io_map_index[] = { 428 EXCA_IOINFO(0), 429 EXCA_IOINFO(1), 430 }; 431 #undef EXCA_IOINFO 432 433 static void 434 exca_do_io_map(struct exca_softc *sc, int win) 435 { 436 struct io_map_index_st *map; 437 438 struct pccard_io_handle *io; 439 440 map = &io_map_index[win]; 441 io = &sc->io[win]; 442 exca_putb(sc, map->start_lsb, io->addr & 0xff); 443 exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); 444 445 exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 446 exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 447 448 exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 449 exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 450 451 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 452 #ifdef EXCA_DEBUG 453 { 454 int r1, r2, r3, r4; 455 r1 = exca_getb(sc, map->start_msb); 456 r2 = exca_getb(sc, map->start_lsb); 457 r3 = exca_getb(sc, map->stop_msb); 458 r4 = exca_getb(sc, map->stop_lsb); 459 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 460 "(%08x+%08x)\n", win, r1, r2, r3, r4, 461 io->addr, io->size); 462 } 463 #endif 464 } 465 466 int 467 exca_io_map(struct exca_softc *sc, int width, struct resource *r) 468 { 469 int win; 470 #ifdef EXCA_DEBUG 471 static char *width_names[] = { "auto", "io8", "io16"}; 472 #endif 473 for (win=0; win < EXCA_IO_WINS; win++) { 474 if ((sc->ioalloc & (1 << win)) == 0) { 475 sc->ioalloc |= (1 << win); 476 break; 477 } 478 } 479 if (win >= EXCA_IO_WINS) 480 return (ENOSPC); 481 482 sc->io[win].iot = rman_get_bustag(r); 483 sc->io[win].ioh = rman_get_bushandle(r); 484 sc->io[win].addr = rman_get_start(r); 485 sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 486 sc->io[win].flags = 0; 487 sc->io[win].width = width; 488 DPRINTF("exca_io_map window %d %s port %x+%x\n", 489 win, width_names[width], sc->io[win].addr, 490 sc->io[win].size); 491 exca_do_io_map(sc, win); 492 493 return (0); 494 } 495 496 static void 497 exca_io_unmap(struct exca_softc *sc, int window) 498 { 499 if (window >= EXCA_IO_WINS) 500 panic("exca_io_unmap: window out of range"); 501 502 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 503 504 sc->ioalloc &= ~(1 << window); 505 506 sc->io[window].iot = 0; 507 sc->io[window].ioh = 0; 508 sc->io[window].addr = 0; 509 sc->io[window].size = 0; 510 sc->io[window].flags = 0; 511 sc->io[window].width = 0; 512 } 513 514 static int 515 exca_io_findmap(struct exca_softc *sc, struct resource *res) 516 { 517 int win; 518 519 for (win = 0; win < EXCA_IO_WINS; win++) { 520 if (sc->io[win].iot == rman_get_bustag(res) && 521 sc->io[win].addr == rman_get_start(res) && 522 sc->io[win].size == rman_get_size(res)) 523 return (win); 524 } 525 return (-1); 526 } 527 528 529 int 530 exca_io_unmap_res(struct exca_softc *sc, struct resource *res) 531 { 532 int win; 533 534 win = exca_io_findmap(sc, res); 535 if (win < 0) 536 return (ENOENT); 537 exca_io_unmap(sc, win); 538 return (0); 539 } 540 541 /* Misc */ 542 543 /* 544 * If interrupts are enabled, then we should be able to just wait for 545 * an interrupt routine to wake us up. Busy waiting shouldn't be 546 * necessary. Sadly, not all legacy ISA cards support an interrupt 547 * for the busy state transitions, at least according to their datasheets, 548 * so we busy wait a while here.. 549 */ 550 static void 551 exca_wait_ready(struct exca_softc *sc) 552 { 553 int i; 554 DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 555 exca_getb(sc, EXCA_IF_STATUS)); 556 for (i = 0; i < 10000; i++) { 557 if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 558 return; 559 DELAY(500); 560 } 561 device_printf(sc->dev, "ready never happened, status = %02x\n", 562 exca_getb(sc, EXCA_IF_STATUS)); 563 } 564 565 /* 566 * Reset the card. Ideally, we'd do a lot of this via interrupts. 567 * However, many PC Cards will deassert the ready signal. This means 568 * that they are asserting an interrupt. This makes it hard to 569 * do anything but a busy wait here. One could argue that these 570 * such cards are broken, or that the bridge that allows this sort 571 * of interrupt through isn't quite what you'd want (and may be a standards 572 * violation). However, such arguing would leave a huge class of PC Cards 573 * and bridges out of reach for use in the system. 574 * 575 * Maybe I should reevaluate the above based on the power bug I fixed 576 * in OLDCARD. 577 */ 578 void 579 exca_reset(struct exca_softc *sc, device_t child) 580 { 581 int win; 582 583 /* enable socket i/o */ 584 exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 585 586 exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); 587 /* hold reset for 30ms */ 588 DELAY(30*1000); 589 /* clear the reset flag */ 590 exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 591 /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ 592 DELAY(20*1000); 593 594 exca_wait_ready(sc); 595 596 /* disable all address windows */ 597 exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); 598 599 exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); 600 DEVPRINTF(sc->dev, "card type is io\n"); 601 602 /* reinstall all the memory and io mappings */ 603 for (win = 0; win < EXCA_MEM_WINS; ++win) 604 if (sc->memalloc & (1 << win)) 605 exca_do_mem_map(sc, win); 606 for (win = 0; win < EXCA_IO_WINS; ++win) 607 if (sc->ioalloc & (1 << win)) 608 exca_do_io_map(sc, win); 609 } 610 611 /* 612 * Initialize the exca_softc data structure for the first time. 613 */ 614 void 615 exca_init(struct exca_softc *sc, device_t dev, 616 bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) 617 { 618 sc->dev = dev; 619 sc->memalloc = 0; 620 sc->ioalloc = 0; 621 sc->bst = bst; 622 sc->bsh = bsh; 623 sc->offset = offset; 624 sc->flags = 0; 625 sc->getb = exca_mem_getb; 626 sc->putb = exca_mem_putb; 627 } 628 629 /* 630 * Is this socket valid? 631 */ 632 static int 633 exca_valid_slot(struct exca_softc *exca) 634 { 635 uint8_t c; 636 637 /* Assume the worst */ 638 exca->chipset = EXCA_BOGUS; 639 640 /* 641 * see if there's a PCMCIA controller here 642 * Intel PCMCIA controllers use 0x82 and 0x83 643 * IBM clone chips use 0x88 and 0x89, apparently 644 */ 645 c = exca_getb(exca, EXCA_IDENT); 646 DEVPRINTF(exca->dev, "Ident is %x\n", c); 647 if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 648 return (0); 649 if ((c & EXCA_IDENT_ZERO) != 0) 650 return (0); 651 switch (c & EXCA_IDENT_REV_MASK) { 652 /* 653 * 82365 or clones. 654 */ 655 case EXCA_IDENT_REV_I82365SLR0: 656 case EXCA_IDENT_REV_I82365SLR1: 657 exca->chipset = EXCA_I82365; 658 /* 659 * Check for Vadem chips by unlocking their extra 660 * registers and looking for valid ID. Bit 3 in 661 * the ID register is normally 0, except when 662 * EXCA_VADEMREV is set. Other bridges appear 663 * to ignore this frobbing. 664 */ 665 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 666 EXCA_VADEM_COOKIE1); 667 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 668 EXCA_VADEM_COOKIE2); 669 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 670 c = exca_getb(exca, EXCA_IDENT); 671 if (c & 0x08) { 672 switch (c & 7) { 673 case 1: 674 exca->chipset = EXCA_VG365; 675 break; 676 case 2: 677 exca->chipset = EXCA_VG465; 678 break; 679 case 3: 680 exca->chipset = EXCA_VG468; 681 break; 682 default: 683 exca->chipset = EXCA_VG469; 684 break; 685 } 686 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 687 break; 688 } 689 /* 690 * Check for RICOH RF5C[23]96 PCMCIA Controller 691 */ 692 c = exca_getb(exca, EXCA_RICOH_ID); 693 if (c == EXCA_RID_396) { 694 exca->chipset = EXCA_RF5C396; 695 break; 696 } else if (c == EXCA_RID_296) { 697 exca->chipset = EXCA_RF5C296; 698 break; 699 } 700 /* 701 * Check for Cirrus logic chips. 702 */ 703 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 704 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 705 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 706 EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 707 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 708 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 709 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 710 exca->chipset = EXCA_PD6722; 711 else 712 exca->chipset = EXCA_PD6710; 713 break; 714 } 715 } 716 break; 717 718 case EXCA_IDENT_REV_I82365SLDF: 719 /* 720 * Intel i82365sl-DF step or maybe a vlsi 82c146 721 * we detected the vlsi case earlier, so if the controller 722 * isn't set, we know it is a i82365sl step D. 723 */ 724 exca->chipset = EXCA_I82365SL_DF; 725 break; 726 case EXCA_IDENT_REV_IBM1: 727 case EXCA_IDENT_REV_IBM2: 728 exca->chipset = EXCA_IBM; 729 break; 730 case EXCA_IDENT_REV_IBM_KING: 731 exca->chipset = EXCA_IBM_KING; 732 break; 733 default: 734 return (0); 735 } 736 return (1); 737 } 738 739 /* 740 * Probe the expected slots. We maybe should set the ID for each of these 741 * slots too while we're at it. But maybe that belongs to a separate 742 * function. 743 * 744 * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 745 */ 746 int 747 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 748 bus_space_handle_t ioh) 749 { 750 int err; 751 int i; 752 753 err = ENXIO; 754 for (i = 0; i < EXCA_NSLOTS; i++) { 755 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 756 exca->getb = exca_io_getb; 757 exca->putb = exca_io_putb; 758 if (exca_valid_slot(&exca[i])) { 759 device_set_desc(dev, chip_names[exca[i].chipset]); 760 err = 0; 761 } 762 } 763 return (err); 764 } 765 766 void 767 exca_insert(struct exca_softc *exca) 768 { 769 if (device_is_attached(exca->pccarddev)) { 770 if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 771 device_printf(exca->dev, 772 "PC Card card activation failed\n"); 773 } else { 774 device_printf(exca->dev, 775 "PC Card inserted, but no pccard bus.\n"); 776 } 777 } 778 779 780 void 781 exca_removal(struct exca_softc *exca) 782 { 783 if (device_is_attached(exca->pccarddev)) 784 CARD_DETACH_CARD(exca->pccarddev); 785 } 786 787 int 788 exca_activate_resource(struct exca_softc *exca, device_t child, int type, 789 int rid, struct resource *res) 790 { 791 int err; 792 793 if (rman_get_flags(res) & RF_ACTIVE) 794 return (0); 795 err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 796 type, rid, res); 797 if (err) 798 return (err); 799 switch (type) { 800 case SYS_RES_IOPORT: 801 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 802 break; 803 case SYS_RES_MEMORY: 804 err = exca_mem_map(exca, PCCARD_A_MEM_COM, res); 805 break; 806 } 807 if (err) 808 BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 809 type, rid, res); 810 return (err); 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