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