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