Update cardbus/pccard support.
[dragonfly/port-amd64.git] / sys / dev / pccard / exca / exca.c
blob81c5e4227a90d2874d8467b88a766e123d164b9d
1 /*-
2 * Copyright (c) 2002-2005 M Warner Losh. All rights reserved.
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.
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.
24 * This software may be derived from NetBSD i82365.c and other files with
25 * the following copyright:
27 * Copyright (c) 1997 Marc Horowitz. All rights reserved.
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.
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.
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 $
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>
68 #include <sys/bus.h>
69 #include <sys/rman.h>
71 #include <bus/pccard/pccardreg.h>
72 #include <bus/pccard/pccardvar.h>
74 #include <dev/pccard/exca/excareg.h>
75 #include <dev/pccard/exca/excavar.h>
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
85 #if 0
86 static const char *chip_names[] =
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"
104 #endif
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;
111 /* memory */
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, \
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)
140 #undef EXCA_MEMINFO
142 static uint8_t
143 exca_mem_getb(struct exca_softc *sc, int reg)
145 return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
148 static void
149 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val)
151 bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val);
154 static uint8_t
155 exca_io_getb(struct exca_softc *sc, int reg)
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));
161 static void
162 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val)
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);
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).
174 static void
175 exca_do_mem_map(struct exca_softc *sc, int win)
177 struct mem_map_index_st *map;
178 struct pccard_mem_handle *mem;
179 uint32_t offset;
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));
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);
200 exca_putb(sc, map->sysmem_win,
201 (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff);
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));
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);
218 DELAY(100);
219 #ifdef EXCA_DEBUG
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);
235 #endif
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.
247 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res)
249 int win;
251 for (win = 0; win < EXCA_MEM_WINS; win++) {
252 if ((sc->memalloc & (1 << win)) == 0) {
253 sc->memalloc |= (1 << win);
254 break;
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);
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);
278 return (0);
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.
289 static void
290 exca_mem_unmap(struct exca_softc *sc, int window)
292 if (window < 0 || window >= EXCA_MEM_WINS)
293 panic("exca_mem_unmap: window out of range");
295 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable);
296 sc->memalloc &= ~(1 << window);
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.
306 static int
307 exca_mem_findmap(struct exca_softc *sc, struct resource *res)
309 int win;
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);
317 return (-1);
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.
330 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags)
332 int win;
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);
341 sc->mem[win].kind = flags;
342 exca_do_mem_map(sc, win);
343 return (0);
347 * Given a resource, go ahead and unmap it if we can find it in the
348 * resrouce list that's used.
351 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
353 int win;
355 win = exca_mem_findmap(sc, res);
356 if (win < 0)
357 return (ENOENT);
358 exca_mem_unmap(sc, win);
359 return (0);
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.
369 exca_mem_set_offset(struct exca_softc *sc, struct resource *res,
370 uint32_t cardaddr, uint32_t *deltap)
372 int win;
373 uint32_t delta;
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);
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);
394 /* I/O */
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, \
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, \
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),
427 #undef EXCA_IOINFO
429 static void
430 exca_do_io_map(struct exca_softc *sc, int win)
432 struct io_map_index_st *map;
434 struct pccard_io_handle *io;
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);
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);
444 exca_clrb(sc, EXCA_IOCTL, map->ioctlmask);
445 exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]);
447 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable);
448 #ifdef EXCA_DEBUG
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);
459 #endif
463 exca_io_map(struct exca_softc *sc, int width, struct resource *r)
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;
475 if (win >= EXCA_IO_WINS)
476 return (1);
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);
489 return (0);
492 static void
493 exca_io_unmap(struct exca_softc *sc, int window)
495 if (window >= EXCA_IO_WINS)
496 panic("exca_io_unmap: window out of range");
498 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable);
500 sc->ioalloc &= ~(1 << window);
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;
510 static int
511 exca_io_findmap(struct exca_softc *sc, struct resource *res)
513 int win;
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);
521 return (-1);
526 exca_io_unmap_res(struct exca_softc *sc, struct resource *res)
528 int win;
530 win = exca_io_findmap(sc, res);
531 if (win < 0)
532 return (ENOENT);
533 exca_io_unmap(sc, win);
534 return (0);
537 /* Misc */
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..
546 static void
547 exca_wait_ready(struct exca_softc *sc)
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);
557 device_printf(sc->dev, "ready never happened, status = %02x\n",
558 exca_getb(sc, EXCA_IF_STATUS));
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.
571 * Maybe I should reevaluate the above based on the power bug I fixed
572 * in OLDCARD.
574 void
575 exca_reset(struct exca_softc *sc, device_t child)
577 int win;
579 /* enable socket i/o */
580 exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE);
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);
590 exca_wait_ready(sc);
592 /* disable all address windows */
593 exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0);
595 exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO);
596 DEVPRINTF(sc->dev, "card type is io\n");
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);
608 * Initialize the exca_softc data structure for the first time.
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)
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;
626 * Is this socket valid?
628 static int
629 exca_valid_slot(struct exca_softc *exca)
631 uint8_t c;
633 /* Assume the worst */
634 exca->chipset = EXCA_BOGUS;
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
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) {
648 * 82365 or clones.
650 case EXCA_IDENT_REV_I82365SLR0:
651 case EXCA_IDENT_REV_I82365SLR1:
652 exca->chipset = EXCA_I82365;
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.
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;
681 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
682 break;
685 * Check for RICOH RF5C[23]96 PCMCIA Controller
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;
696 * Check for Cirrus logic chips.
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;
711 break;
713 case EXCA_IDENT_REV_I82365SLDF:
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.
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);
731 return (1);
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.
739 * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
742 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
743 bus_space_handle_t ioh)
745 int err;
746 int i;
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;
756 return (err);
759 void
760 exca_insert(struct exca_softc *exca)
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");
773 void
774 exca_removal(struct exca_softc *exca)
776 if (exca->pccarddev != NULL)
777 CARD_DETACH_CARD(exca->pccarddev);
781 exca_activate_resource(struct exca_softc *exca, device_t child, int type,
782 int rid, struct resource *res)
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;
797 if (err)
798 return (err);
801 return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
802 type, rid, res));
806 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type,
807 int rid, struct resource *res)
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;
821 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
822 type, rid, res));
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)
830 struct resource *res = NULL;
831 int tmp;
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);
856 flags |= RF_SHAREABLE;
857 start = end = rman_get_start(sc->irq_res);
858 break;
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);
872 return (res);
875 static int
876 exca_release_resource(struct exca_softc *sc, device_t child, int type,
877 int rid, struct resource *res)
879 int error;
881 if (rman_get_flags(res) & RF_ACTIVE) {
882 error = bus_deactivate_resource(child, type, rid, res);
883 if (error != 0)
884 return (error);
886 cbb_remove_res(sc, res);
887 return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
888 type, rid, res));
890 #endif
892 static int
893 exca_modevent(module_t mod, int cmd, void *arg)
895 return 0;
898 DEV_MODULE(exca, exca_modevent, NULL);
899 MODULE_VERSION(exca, 1);