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