1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (c) 2002 M Warner Losh. All rights reserved. 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/errno.h> 60 #include <sys/kernel.h> 61 #include <sys/malloc.h> 62 #include <sys/queue.h> 63 #include <sys/module.h> 64 #include <sys/conf.h> 65 66 #include <sys/bus.h> 67 #include <machine/bus.h> 68 #include <sys/rman.h> 69 #include <machine/resource.h> 70 71 #include <dev/pccard/pccardreg.h> 72 #include <dev/pccard/pccardvar.h> 73 74 #include <dev/exca/excareg.h> 75 #include <dev/exca/excavar.h> 76 77 #ifdef EXCA_DEBUG 78 #define DEVPRINTF(dev, fmt, args...) device_printf((dev), (fmt), ## args) 79 #define DPRINTF(fmt, args...) printf(fmt, ## args) 80 #else 81 #define DEVPRINTF(dev, fmt, args...) 82 #define DPRINTF(fmt, args...) 83 #endif 84 85 86 /* memory */ 87 88 #define EXCA_MEMINFO(NUM) { \ 89 EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \ 90 EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \ 91 EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ 92 EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ 93 EXCA_SYSMEM_ADDR ## NUM ## _WIN, \ 94 EXCA_CARDMEM_ADDR ## NUM ## _LSB, \ 95 EXCA_CARDMEM_ADDR ## NUM ## _MSB, \ 96 EXCA_ADDRWIN_ENABLE_MEM ## NUM, \ 97 } 98 99 static struct mem_map_index_st { 100 int sysmem_start_lsb; 101 int sysmem_start_msb; 102 int sysmem_stop_lsb; 103 int sysmem_stop_msb; 104 int sysmem_win; 105 int cardmem_lsb; 106 int cardmem_msb; 107 int memenable; 108 } mem_map_index[] = { 109 EXCA_MEMINFO(0), 110 EXCA_MEMINFO(1), 111 EXCA_MEMINFO(2), 112 EXCA_MEMINFO(3), 113 EXCA_MEMINFO(4) 114 }; 115 #undef EXCA_MEMINFO 116 117 /* 118 * Helper function. This will map the requested memory slot. We setup the 119 * map before we call this function. This is used to initially force the 120 * mapping, as well as later restore the mapping after it has been destroyed 121 * in some fashion (due to a power event typically). 122 */ 123 static void 124 exca_do_mem_map(struct exca_softc *sc, int win) 125 { 126 struct mem_map_index_st *map; 127 struct pccard_mem_handle *mem; 128 129 map = &mem_map_index[win]; 130 mem = &sc->mem[win]; 131 exca_write(sc, map->sysmem_start_lsb, 132 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 133 exca_write(sc, map->sysmem_start_msb, 134 ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 135 EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | 0x80); 136 137 exca_write(sc, map->sysmem_stop_lsb, 138 ((mem->addr + mem->realsize - 1) >> 139 EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 140 exca_write(sc, map->sysmem_stop_msb, 141 (((mem->addr + mem->realsize - 1) >> 142 (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 143 EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | 144 EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); 145 146 exca_write(sc, map->sysmem_win, 147 (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff); 148 149 exca_write(sc, map->cardmem_lsb, 150 (mem->offset >> EXCA_CARDMEM_ADDRX_SHIFT) & 0xff); 151 exca_write(sc, map->cardmem_msb, 152 ((mem->offset >> (EXCA_CARDMEM_ADDRX_SHIFT + 8)) & 153 EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | 154 ((mem->kind == PCCARD_MEM_ATTR) ? 155 EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0)); 156 157 exca_setb(sc, EXCA_ADDRWIN_ENABLE, EXCA_ADDRWIN_ENABLE_MEMCS16 | 158 map->memenable); 159 160 DELAY(100); 161 #ifdef EXCA_DEBUG 162 { 163 int r1, r2, r3, r4, r5, r6, r7; 164 r1 = exca_read(sc, map->sysmem_start_msb); 165 r2 = exca_read(sc, map->sysmem_start_lsb); 166 r3 = exca_read(sc, map->sysmem_stop_msb); 167 r4 = exca_read(sc, map->sysmem_stop_lsb); 168 r5 = exca_read(sc, map->cardmem_msb); 169 r6 = exca_read(sc, map->cardmem_lsb); 170 r7 = exca_read(sc, map->sysmem_win); 171 printf("exca_do_mem_map window %d: %02x%02x %02x%02x " 172 "%02x%02x %02x (%08x+%08x.%08x*%08lx)\n", 173 win, r1, r2, r3, r4, r5, r6, r7, 174 mem->addr, mem->size, mem->realsize, 175 mem->offset); 176 } 177 #endif 178 } 179 180 /* 181 * public interface to map a resource. kind is the type of memory to 182 * map (either common or attribute). Memory created via this interface 183 * starts out at card address 0. Since the only way to set this is 184 * to set it on a struct resource after it has been mapped, we're safe 185 * in maping this assumption. Note that resources can be remapped using 186 * exca_do_mem_map so that's how the card address can be set later. 187 */ 188 int 189 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 190 { 191 int win; 192 193 for (win = 0; win < EXCA_MEM_WINS; win++) { 194 if ((sc->memalloc & (1 << win)) == 0) { 195 sc->memalloc |= (1 << win); 196 break; 197 } 198 } 199 if (win >= EXCA_MEM_WINS) 200 return (1); 201 202 sc->mem[win].cardaddr = 0; 203 sc->mem[win].memt = rman_get_bustag(res); 204 sc->mem[win].memh = rman_get_bushandle(res); 205 sc->mem[win].addr = rman_get_start(res); 206 sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 207 sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 208 sc->mem[win].realsize = sc->mem[win].realsize - 209 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 210 sc->mem[win].offset = (long)(sc->mem[win].addr); 211 sc->mem[win].kind = kind; 212 DPRINTF("exca_mem_map window %d bus %x+%x+%lx card addr %x\n", 213 win, sc->mem[win].addr, sc->mem[win].size, 214 sc->mem[win].offset, sc->mem[win].cardaddr); 215 exca_do_mem_map(sc, win); 216 217 return (0); 218 } 219 220 /* 221 * Private helper function. This turns off a given memory map that is in 222 * use. We do this by just clearing the enable bit in the pcic. If we needed 223 * to make memory unmapping/mapping pairs faster, we would have to store 224 * more state information about the pcic and then use that to intelligently 225 * to the map/unmap. However, since we don't do that sort of thing often 226 * (generally just at configure time), it isn't a case worth optimizing. 227 */ 228 static void 229 exca_mem_unmap(struct exca_softc *sc, int window) 230 { 231 if (window < 0 || window >= EXCA_MEM_WINS) 232 panic("exca_mem_unmap: window out of range"); 233 234 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 235 sc->memalloc &= ~(1 << window); 236 } 237 238 /* 239 * Find the map that we're using to hold the resoruce. This works well 240 * so long as the client drivers don't do silly things like map the same 241 * area mutliple times, or map both common and attribute memory at the 242 * same time. This latter restriction is a bug. We likely should just 243 * store a pointer to the res in the mem[x] data structure. 244 */ 245 static int 246 exca_mem_findmap(struct exca_softc *sc, struct resource *res) 247 { 248 int win; 249 250 for (win = 0; win < EXCA_MEM_WINS; win++) { 251 if (sc->mem[win].memt == rman_get_bustag(res) && 252 sc->mem[win].addr == rman_get_start(res) && 253 sc->mem[win].size == rman_get_size(res)) 254 return (win); 255 } 256 return (-1); 257 } 258 259 /* 260 * Set the memory flag. This means that we are setting if the memory 261 * is coming from attribute memory or from common memory on the card. 262 * CIS entries are generally in attribute memory (although they can 263 * reside in common memory). Generally, this is the only use for attribute 264 * memory. However, some cards require their drivers to dance in both 265 * common and/or attribute memory and this interface (and setting the 266 * offset interface) exist for such cards. 267 */ 268 int 269 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 270 { 271 int win; 272 273 win = exca_mem_findmap(sc, res); 274 if (win < 0) { 275 device_printf(sc->dev, 276 "set_res_flags: specified resource not active\n"); 277 return (ENOENT); 278 } 279 280 sc->mem[win].kind = flags; 281 exca_do_mem_map(sc, win); 282 return (0); 283 } 284 285 /* 286 * Given a resource, go ahead and unmap it if we can find it in the 287 * resrouce list that's used. 288 */ 289 int 290 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 291 { 292 int win; 293 294 win = exca_mem_findmap(sc, res); 295 if (win < 0) 296 return (ENOENT); 297 exca_mem_unmap(sc, win); 298 return (0); 299 } 300 301 /* 302 * Set the offset of the memory. We use this for reading the CIS and 303 * frobbing the pccard's pccard registers (POR, etc). Some drivers 304 * need to access this functionality as well, since they have receive 305 * buffers defined in the attribute memory. Thankfully, these cards 306 * are few and fare between. Some cards also have common memory that 307 * is large and only map a small portion of it at a time (but these cards 308 * are rare, the more common case being to have just a small amount 309 * of common memory that the driver needs to bcopy data from in order to 310 * get at it. 311 */ 312 int 313 exca_mem_set_offset(struct exca_softc *sc, struct resource *res, 314 uint32_t cardaddr, uint32_t *deltap) 315 { 316 int win; 317 uint32_t delta; 318 319 win = exca_mem_findmap(sc, res); 320 if (win < 0) { 321 device_printf(sc->dev, 322 "set_memory_offset: specified resource not active\n"); 323 return (ENOENT); 324 } 325 sc->mem[win].cardaddr = cardaddr; 326 delta = cardaddr % EXCA_MEM_PAGESIZE; 327 if (deltap) 328 *deltap = delta; 329 cardaddr -= delta; 330 sc->mem[win].realsize = sc->mem[win].size + delta + 331 EXCA_MEM_PAGESIZE - 1; 332 sc->mem[win].realsize = sc->mem[win].realsize - 333 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 334 sc->mem[win].offset = cardaddr - sc->mem[win].addr; 335 exca_do_mem_map(sc, win); 336 return (0); 337 } 338 339 340 /* I/O */ 341 342 #define EXCA_IOINFO(NUM) { \ 343 EXCA_IOADDR ## NUM ## _START_LSB, \ 344 EXCA_IOADDR ## NUM ## _START_MSB, \ 345 EXCA_IOADDR ## NUM ## _STOP_LSB, \ 346 EXCA_IOADDR ## NUM ## _STOP_MSB, \ 347 EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 348 EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 349 | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 350 | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 351 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 352 { \ 353 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 354 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 355 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 356 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 357 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 358 } \ 359 } 360 361 static struct io_map_index_st { 362 int start_lsb; 363 int start_msb; 364 int stop_lsb; 365 int stop_msb; 366 int ioenable; 367 int ioctlmask; 368 int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 369 } io_map_index[] = { 370 EXCA_IOINFO(0), 371 EXCA_IOINFO(1), 372 }; 373 #undef EXCA_IOINFO 374 375 static void 376 exca_do_io_map(struct exca_softc *sc, int win) 377 { 378 struct io_map_index_st *map; 379 380 struct pccard_io_handle *io; 381 382 map = &io_map_index[win]; 383 io = &sc->io[win]; 384 exca_write(sc, map->start_lsb, io->addr & 0xff); 385 exca_write(sc, map->start_msb, (io->addr >> 8) & 0xff); 386 387 exca_write(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 388 exca_write(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 389 390 exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 391 exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 392 393 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 394 #ifdef EXCA_DEBUG 395 { 396 int r1, r2, r3, r4; 397 r1 = exca_read(sc, map->start_msb); 398 r2 = exca_read(sc, map->start_lsb); 399 r3 = exca_read(sc, map->stop_msb); 400 r4 = exca_read(sc, map->stop_lsb); 401 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 402 "(%08x+%08x)\n", win, r1, r2, r3, r4, 403 io->addr, io->size); 404 } 405 #endif 406 } 407 408 int 409 exca_io_map(struct exca_softc *sc, int width, struct resource *r) 410 { 411 int win; 412 #ifdef EXCA_DEBUG 413 static char *width_names[] = { "auto", "io8", "io16"}; 414 #endif 415 for (win=0; win < EXCA_IO_WINS; win++) { 416 if ((sc->ioalloc & (1 << win)) == 0) { 417 sc->ioalloc |= (1 << win); 418 break; 419 } 420 } 421 if (win >= EXCA_IO_WINS) 422 return (1); 423 424 sc->io[win].iot = rman_get_bustag(r); 425 sc->io[win].ioh = rman_get_bushandle(r); 426 sc->io[win].addr = rman_get_start(r); 427 sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 428 sc->io[win].flags = 0; 429 sc->io[win].width = width; 430 DPRINTF("exca_io_map window %d %s port %x+%x\n", 431 win, width_names[width], sc->io[win].addr, 432 sc->io[win].size); 433 exca_do_io_map(sc, win); 434 435 return (0); 436 } 437 438 static void 439 exca_io_unmap(struct exca_softc *sc, int window) 440 { 441 if (window >= EXCA_IO_WINS) 442 panic("exca_io_unmap: window out of range"); 443 444 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 445 446 sc->ioalloc &= ~(1 << window); 447 448 sc->io[window].iot = 0; 449 sc->io[window].ioh = 0; 450 sc->io[window].addr = 0; 451 sc->io[window].size = 0; 452 sc->io[window].flags = 0; 453 sc->io[window].width = 0; 454 } 455 456 static int 457 exca_io_findmap(struct exca_softc *sc, struct resource *res) 458 { 459 int win; 460 461 for (win = 0; win < EXCA_IO_WINS; win++) { 462 if (sc->io[win].iot == rman_get_bustag(res) && 463 sc->io[win].addr == rman_get_start(res) && 464 sc->io[win].size == rman_get_size(res)) 465 return (win); 466 } 467 return (-1); 468 } 469 470 471 int 472 exca_io_unmap_res(struct exca_softc *sc, struct resource *res) 473 { 474 int win; 475 476 win = exca_io_findmap(sc, res); 477 if (win < 0) 478 return (ENOENT); 479 exca_io_unmap(sc, win); 480 return (0); 481 } 482 483 /* Misc */ 484 485 /* 486 * If interrupts are enabled, then we should be able to just wait for 487 * an interrupt routine to wake us up. Busy waiting shouldn't be 488 * necessary. Sadly, not all legacy ISA cards support an interrupt 489 * for the busy state transitions, at least according to their datasheets, 490 * so we busy wait a while here.. 491 */ 492 static void 493 exca_wait_ready(struct exca_softc *sc) 494 { 495 int i; 496 DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 497 exca_read(sc, EXCA_IF_STATUS)); 498 for (i = 0; i < 10000; i++) { 499 if (exca_read(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 500 return; 501 DELAY(500); 502 } 503 device_printf(sc->dev, "ready never happened, status = %02x\n", 504 exca_read(sc, EXCA_IF_STATUS)); 505 } 506 507 /* 508 * Reset the card. Ideally, we'd do a lot of this via interrupts. 509 * However, many PC Cards will deassert the ready signal. This means 510 * that they are asserting an interrupt. This makes it hard to 511 * do anything but a busy wait here. One could argue that these 512 * such cards are broken, or that the bridge that allows this sort 513 * of interrupt through isn't quite what you'd want (and may be a standards 514 * violation). However, such arguing would leave a huge class of pc cards 515 * and bridges out of reach for 516 */ 517 void 518 exca_reset(struct exca_softc *sc, device_t child) 519 { 520 int cardtype; 521 int win; 522 523 /* enable socket i/o */ 524 exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 525 526 exca_write(sc, EXCA_INTR, EXCA_INTR_ENABLE); 527 /* hold reset for 30ms */ 528 DELAY(30*1000); 529 /* clear the reset flag */ 530 exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 531 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 532 DELAY(20*1000); 533 534 exca_wait_ready(sc); 535 536 /* disable all address windows */ 537 exca_write(sc, EXCA_ADDRWIN_ENABLE, 0); 538 539 CARD_GET_TYPE(child, &cardtype); 540 exca_setb(sc, EXCA_INTR, (cardtype == PCCARD_IFTYPE_IO) ? 541 EXCA_INTR_CARDTYPE_IO : EXCA_INTR_CARDTYPE_MEM); 542 DEVPRINTF(sc->dev, "card type is %s\n", 543 (cardtype == PCCARD_IFTYPE_IO) ? "io" : "mem"); 544 545 /* reinstall all the memory and io mappings */ 546 for (win = 0; win < EXCA_MEM_WINS; ++win) 547 if (sc->memalloc & (1 << win)) 548 exca_do_mem_map(sc, win); 549 for (win = 0; win < EXCA_IO_WINS; ++win) 550 if (sc->ioalloc & (1 << win)) 551 exca_do_io_map(sc, win); 552 } 553 554 /* 555 * Initialize the exca_softc data structure for the first time. 556 */ 557 void 558 exca_init(struct exca_softc *sc, device_t dev, exca_write_t *wrfn, 559 exca_read_t *rdfn, bus_space_tag_t bst, bus_space_handle_t bsh, 560 uint32_t offset) 561 { 562 sc->dev = dev; 563 sc->write_exca = wrfn; 564 sc->read_exca = rdfn; 565 sc->memalloc = 0; 566 sc->ioalloc = 0; 567 sc->bst = bst; 568 sc->bsh = bsh; 569 sc->offset = offset; 570 sc->flags = 0; 571 } 572 573 /* 574 * Probe the expected slots. We maybe should set the ID for each of these 575 * slots too while we're at it. But maybe that belongs to a separate 576 * function. 577 * 578 * Callers must charantee that there are at least EXCA_NSLOTS (4) in 579 * the array that they pass the address of the first element in the 580 * "exca" parameter. 581 */ 582 int 583 exca_probe_slots(device_t dev, struct exca_softc *exca, exca_write_t writefnp, 584 exca_read_t readfnp) 585 { 586 int rid; 587 struct resource *res; 588 int err; 589 bus_space_tag_t iot; 590 bus_space_handle_t ioh; 591 int i; 592 593 err = ENXIO; 594 rid = 0; 595 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, EXCA_IOSIZE, 596 RF_ACTIVE); 597 if (res == NULL) 598 return (ENXIO); 599 iot = rman_get_bustag(res); 600 ioh = rman_get_bushandle(res); 601 for (i = 0; i < EXCA_NSLOTS; i++) { 602 exca_init(&exca[i], dev, writefnp, readfnp, iot, ioh, 603 i * EXCA_SOCKET_SIZE); 604 if (exca_is_pcic(&exca[i])) { 605 err = 0; 606 exca[i].flags |= EXCA_SOCKET_PRESENT; 607 } 608 } 609 bus_release_resource(dev, SYS_RES_IOPORT, rid, res); 610 return (err); 611 } 612 613 int 614 exca_is_pcic(struct exca_softc *sc) 615 { 616 /* XXX */ 617 return (0); 618 } 619 620 static int exca_modevent(module_t mod, int cmd, void *arg) 621 { 622 return 0; 623 } 624 DEV_MODULE(exca, exca_modevent, NULL); 625 MODULE_VERSION(exca, 1); 626