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