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