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