]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/exca/exca.c
Initialize the event tailq.
[FreeBSD/FreeBSD.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 = (mem->kind == PCCARD_A_MEM_ATTR);
183         mem8 = 1;
184         
185         map = &mem_map_index[win];
186         mem = &sc->mem[win];
187         offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) -
188           (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff;
189         exca_putb(sc, map->sysmem_start_lsb,
190             (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
191         exca_putb(sc, map->sysmem_start_msb,
192             ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
193             EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) |
194             (mem8 ? 0 : EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT));
195
196         exca_putb(sc, map->sysmem_stop_lsb,
197             ((mem->addr + mem->realsize - 1) >>
198             EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
199         exca_putb(sc, map->sysmem_stop_msb,
200             (((mem->addr + mem->realsize - 1) >>
201             (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
202             EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
203             EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2);
204
205         exca_putb(sc, map->sysmem_win,
206             (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff);
207
208         exca_putb(sc, map->cardmem_lsb, offset & 0xff);
209         exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) &
210             EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) |
211             ((mem->kind == PCCARD_A_MEM_ATTR) ?
212             EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0));
213
214 #ifdef EXCA_DEBUG
215         if (mem->kind == PCCARD_A_MEM_ATTR)
216                 printf("attribtue memory\n");
217         else
218                 printf("common memory\n");
219 #endif
220         exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable |
221             EXCA_ADDRWIN_ENABLE_MEMCS16);
222
223         DELAY(100);
224 #ifdef EXCA_DEBUG
225         {
226                 int r1, r2, r3, r4, r5, r6, r7;
227                 r1 = exca_getb(sc, map->sysmem_start_msb);
228                 r2 = exca_getb(sc, map->sysmem_start_lsb);
229                 r3 = exca_getb(sc, map->sysmem_stop_msb);
230                 r4 = exca_getb(sc, map->sysmem_stop_lsb);
231                 r5 = exca_getb(sc, map->cardmem_msb);
232                 r6 = exca_getb(sc, map->cardmem_lsb);
233                 r7 = exca_getb(sc, map->sysmem_win);
234                 printf("exca_do_mem_map win %d: %02x%02x %02x%02x "
235                     "%02x%02x %02x (%08x+%06x.%06x*%06x)\n",
236                     win, r1, r2, r3, r4, r5, r6, r7,
237                     mem->addr, mem->size, mem->realsize,
238                     mem->cardaddr);
239         }
240 #endif
241 }
242
243 /*
244  * public interface to map a resource.  kind is the type of memory to
245  * map (either common or attribute).  Memory created via this interface
246  * starts out at card address 0.  Since the only way to set this is
247  * to set it on a struct resource after it has been mapped, we're safe
248  * in maping this assumption.  Note that resources can be remapped using
249  * exca_do_mem_map so that's how the card address can be set later.
250  */
251 int
252 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res)
253 {
254         int win;
255
256         for (win = 0; win < EXCA_MEM_WINS; win++) {
257                 if ((sc->memalloc & (1 << win)) == 0) {
258                         sc->memalloc |= (1 << win);
259                         break;
260                 }
261         }
262         if (win >= EXCA_MEM_WINS)
263                 return (1);
264         if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 &&
265             (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) {
266                 device_printf(sc->dev, "Does not support mapping above 24M.");
267                 return (1);
268         }
269
270         sc->mem[win].cardaddr = 0;
271         sc->mem[win].memt = rman_get_bustag(res);
272         sc->mem[win].memh = rman_get_bushandle(res);
273         sc->mem[win].addr = rman_get_start(res);
274         sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1;
275         sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1;
276         sc->mem[win].realsize = sc->mem[win].realsize -
277             (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
278         sc->mem[win].kind = kind;
279         DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n",
280             win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr);
281         exca_do_mem_map(sc, win);
282
283         return (0);
284 }
285
286 /*
287  * Private helper function.  This turns off a given memory map that is in
288  * use.  We do this by just clearing the enable bit in the pcic.  If we needed
289  * to make memory unmapping/mapping pairs faster, we would have to store
290  * more state information about the pcic and then use that to intelligently
291  * to the map/unmap.  However, since we don't do that sort of thing often
292  * (generally just at configure time), it isn't a case worth optimizing.
293  */
294 static void
295 exca_mem_unmap(struct exca_softc *sc, int window)
296 {
297         if (window < 0 || window >= EXCA_MEM_WINS)
298                 panic("exca_mem_unmap: window out of range");
299
300         exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable);
301         sc->memalloc &= ~(1 << window);
302 }
303
304 /*
305  * Find the map that we're using to hold the resoruce.  This works well
306  * so long as the client drivers don't do silly things like map the same
307  * area mutliple times, or map both common and attribute memory at the
308  * same time.  This latter restriction is a bug.  We likely should just
309  * store a pointer to the res in the mem[x] data structure.
310  */
311 static int
312 exca_mem_findmap(struct exca_softc *sc, struct resource *res)
313 {
314         int win;
315
316         for (win = 0; win < EXCA_MEM_WINS; win++) {
317                 if (sc->mem[win].memt == rman_get_bustag(res) &&
318                     sc->mem[win].addr == rman_get_start(res) &&
319                     sc->mem[win].size == rman_get_size(res))
320                         return (win);
321         }
322         return (-1);
323 }
324
325 /*
326  * Set the memory flag.  This means that we are setting if the memory
327  * is coming from attribute memory or from common memory on the card.
328  * CIS entries are generally in attribute memory (although they can
329  * reside in common memory).  Generally, this is the only use for attribute
330  * memory.  However, some cards require their drivers to dance in both
331  * common and/or attribute memory and this interface (and setting the
332  * offset interface) exist for such cards.
333  */
334 int
335 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags)
336 {
337         int win;
338
339         win = exca_mem_findmap(sc, res);
340         if (win < 0) {
341                 device_printf(sc->dev,
342                     "set_res_flags: specified resource not active\n");
343                 return (ENOENT);
344         }
345
346         sc->mem[win].kind = flags;
347         exca_do_mem_map(sc, win);
348         return (0);
349 }
350
351 /*
352  * Given a resource, go ahead and unmap it if we can find it in the
353  * resrouce list that's used.
354  */
355 int
356 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
357 {
358         int win;
359
360         win = exca_mem_findmap(sc, res);
361         if (win < 0)
362                 return (ENOENT);
363         exca_mem_unmap(sc, win);
364         return (0);
365 }
366         
367 /*
368  * Set the offset of the memory.  We use this for reading the CIS and
369  * frobbing the pccard's pccard registers (CCR, etc).  Some drivers
370  * need to access arbitrary attribute and common memory during their
371  * initialization and operation.
372  */
373 int
374 exca_mem_set_offset(struct exca_softc *sc, struct resource *res,
375     uint32_t cardaddr, uint32_t *deltap)
376 {
377         int win;
378         uint32_t delta;
379
380         win = exca_mem_findmap(sc, res);
381         if (win < 0) {
382                 device_printf(sc->dev,
383                     "set_memory_offset: specified resource not active\n");
384                 return (ENOENT);
385         }
386         sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1);
387         delta = cardaddr % EXCA_MEM_PAGESIZE;
388         if (deltap)
389                 *deltap = delta;
390         sc->mem[win].realsize = sc->mem[win].size + delta +
391             EXCA_MEM_PAGESIZE - 1;
392         sc->mem[win].realsize = sc->mem[win].realsize -
393             (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
394         exca_do_mem_map(sc, win);
395         return (0);
396 }
397                         
398 \f
399 /* I/O */
400
401 #define EXCA_IOINFO(NUM) {                                              \
402         EXCA_IOADDR ## NUM ## _START_LSB,                               \
403         EXCA_IOADDR ## NUM ## _START_MSB,                               \
404         EXCA_IOADDR ## NUM ## _STOP_LSB,                                \
405         EXCA_IOADDR ## NUM ## _STOP_MSB,                                \
406         EXCA_ADDRWIN_ENABLE_IO ## NUM,                                  \
407         EXCA_IOCTL_IO ## NUM ## _WAITSTATE                              \
408         | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT                             \
409         | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK                       \
410         | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK,                       \
411         {                                                               \
412                 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD,                \
413                 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE             \
414                 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT,               \
415                 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE             \
416                 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT,              \
417         }                                                               \
418 }
419
420 static struct io_map_index_st {
421         int     start_lsb;
422         int     start_msb;
423         int     stop_lsb;
424         int     stop_msb;
425         int     ioenable;
426         int     ioctlmask;
427         int     ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */
428 } io_map_index[] = {
429         EXCA_IOINFO(0),
430         EXCA_IOINFO(1),
431 };
432 #undef  EXCA_IOINFO
433
434 static void
435 exca_do_io_map(struct exca_softc *sc, int win)
436 {
437         struct io_map_index_st *map;
438
439         struct pccard_io_handle *io;
440
441         map = &io_map_index[win];
442         io = &sc->io[win];
443         exca_putb(sc, map->start_lsb, io->addr & 0xff);
444         exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff);
445
446         exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff);
447         exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff);
448
449         exca_clrb(sc, EXCA_IOCTL, map->ioctlmask);
450         exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]);
451
452         exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable);
453 #ifdef EXCA_DEBUG
454         {
455                 int r1, r2, r3, r4;
456                 r1 = exca_getb(sc, map->start_msb);
457                 r2 = exca_getb(sc, map->start_lsb);
458                 r3 = exca_getb(sc, map->stop_msb);
459                 r4 = exca_getb(sc, map->stop_lsb);
460                 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x "
461                     "(%08x+%08x)\n", win, r1, r2, r3, r4,
462                     io->addr, io->size);
463         }
464 #endif
465 }
466
467 int
468 exca_io_map(struct exca_softc *sc, int width, struct resource *r)
469 {
470         int win;
471 #ifdef EXCA_DEBUG
472         static char *width_names[] = { "auto", "io8", "io16"};
473 #endif
474         for (win=0; win < EXCA_IO_WINS; win++) {
475                 if ((sc->ioalloc & (1 << win)) == 0) {
476                         sc->ioalloc |= (1 << win);
477                         break;
478                 }
479         }
480         if (win >= EXCA_IO_WINS)
481                 return (1);
482
483         sc->io[win].iot = rman_get_bustag(r);
484         sc->io[win].ioh = rman_get_bushandle(r);
485         sc->io[win].addr = rman_get_start(r);
486         sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1;
487         sc->io[win].flags = 0;
488         sc->io[win].width = width;
489         DPRINTF("exca_io_map window %d %s port %x+%x\n",
490             win, width_names[width], sc->io[win].addr,
491             sc->io[win].size);
492         exca_do_io_map(sc, win);
493
494         return (0);
495 }
496
497 static void
498 exca_io_unmap(struct exca_softc *sc, int window)
499 {
500         if (window >= EXCA_IO_WINS)
501                 panic("exca_io_unmap: window out of range");
502
503         exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable);
504
505         sc->ioalloc &= ~(1 << window);
506
507         sc->io[window].iot = 0;
508         sc->io[window].ioh = 0;
509         sc->io[window].addr = 0;
510         sc->io[window].size = 0;
511         sc->io[window].flags = 0;
512         sc->io[window].width = 0;
513 }
514
515 static int
516 exca_io_findmap(struct exca_softc *sc, struct resource *res)
517 {
518         int win;
519
520         for (win = 0; win < EXCA_IO_WINS; win++) {
521                 if (sc->io[win].iot == rman_get_bustag(res) &&
522                     sc->io[win].addr == rman_get_start(res) &&
523                     sc->io[win].size == rman_get_size(res))
524                         return (win);
525         }
526         return (-1);
527 }
528
529
530 int
531 exca_io_unmap_res(struct exca_softc *sc, struct resource *res)
532 {
533         int win;
534
535         win = exca_io_findmap(sc, res);
536         if (win < 0)
537                 return (ENOENT);
538         exca_io_unmap(sc, win);
539         return (0);
540 }
541 \f
542 /* Misc */
543
544 /*
545  * If interrupts are enabled, then we should be able to just wait for
546  * an interrupt routine to wake us up.  Busy waiting shouldn't be
547  * necessary.  Sadly, not all legacy ISA cards support an interrupt
548  * for the busy state transitions, at least according to their datasheets, 
549  * so we busy wait a while here..
550  */
551 static void
552 exca_wait_ready(struct exca_softc *sc)
553 {
554         int i;
555         DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n",
556             exca_getb(sc, EXCA_IF_STATUS));
557         for (i = 0; i < 10000; i++) {
558                 if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY)
559                         return;
560                 DELAY(500);
561         }
562         device_printf(sc->dev, "ready never happened, status = %02x\n",
563             exca_getb(sc, EXCA_IF_STATUS));
564 }
565
566 /*
567  * Reset the card.  Ideally, we'd do a lot of this via interrupts.
568  * However, many PC Cards will deassert the ready signal.  This means
569  * that they are asserting an interrupt.  This makes it hard to 
570  * do anything but a busy wait here.  One could argue that these
571  * such cards are broken, or that the bridge that allows this sort
572  * of interrupt through isn't quite what you'd want (and may be a standards
573  * violation).  However, such arguing would leave a huge class of PC Cards
574  * and bridges out of reach for use in the system.
575  *
576  * Maybe I should reevaluate the above based on the power bug I fixed
577  * in OLDCARD.
578  */
579 void
580 exca_reset(struct exca_softc *sc, device_t child)
581 {
582         int win;
583
584         /* enable socket i/o */
585         exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE);
586
587         exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE);
588         /* hold reset for 30ms */
589         DELAY(30*1000);
590         /* clear the reset flag */
591         exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET);
592         /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */
593         DELAY(20*1000);
594
595         exca_wait_ready(sc);
596
597         /* disable all address windows */
598         exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0);
599
600         exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO);
601         DEVPRINTF(sc->dev, "card type is io\n");
602
603         /* reinstall all the memory and io mappings */
604         for (win = 0; win < EXCA_MEM_WINS; ++win)
605                 if (sc->memalloc & (1 << win))
606                         exca_do_mem_map(sc, win);
607         for (win = 0; win < EXCA_IO_WINS; ++win)
608                 if (sc->ioalloc & (1 << win))
609                         exca_do_io_map(sc, win);
610 }
611
612 /*
613  * Initialize the exca_softc data structure for the first time.
614  */
615 void
616 exca_init(struct exca_softc *sc, device_t dev, 
617     bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset)
618 {
619         sc->dev = dev;
620         sc->memalloc = 0;
621         sc->ioalloc = 0;
622         sc->bst = bst;
623         sc->bsh = bsh;
624         sc->offset = offset;
625         sc->flags = 0;
626         sc->getb = exca_mem_getb;
627         sc->putb = exca_mem_putb;
628 }
629
630 /*
631  * Is this socket valid?
632  */
633 static int
634 exca_valid_slot(struct exca_softc *exca)
635 {
636         uint8_t c;
637
638         /* Assume the worst */
639         exca->chipset = EXCA_BOGUS;
640
641         /*
642          * see if there's a PCMCIA controller here
643          * Intel PCMCIA controllers use 0x82 and 0x83
644          * IBM clone chips use 0x88 and 0x89, apparently
645          */
646         c = exca_getb(exca, EXCA_IDENT);
647         DEVPRINTF(exca->dev, "Ident is %x\n", c);
648         if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO)
649                 return (0);
650         if ((c & EXCA_IDENT_ZERO) != 0)
651                 return (0);
652         switch (c & EXCA_IDENT_REV_MASK) {
653         /*
654          *      82365 or clones.
655          */
656         case EXCA_IDENT_REV_I82365SLR0:
657         case EXCA_IDENT_REV_I82365SLR1:
658                 exca->chipset = EXCA_I82365;
659                 /*
660                  * Check for Vadem chips by unlocking their extra
661                  * registers and looking for valid ID.  Bit 3 in
662                  * the ID register is normally 0, except when
663                  * EXCA_VADEMREV is set.  Other bridges appear
664                  * to ignore this frobbing.
665                  */
666                 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
667                     EXCA_VADEM_COOKIE1);
668                 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
669                     EXCA_VADEM_COOKIE2);
670                 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
671                 c = exca_getb(exca, EXCA_IDENT);
672                 if (c & 0x08) {
673                         switch (c & 7) {
674                         case 1:
675                                 exca->chipset = EXCA_VG365;
676                                 break;
677                         case 2:
678                                 exca->chipset = EXCA_VG465;
679                                 break;
680                         case 3:
681                                 exca->chipset = EXCA_VG468;
682                                 break;
683                         default:
684                                 exca->chipset = EXCA_VG469;
685                                 break;
686                         }
687                         exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
688                         break;
689                 }
690                 /*
691                  * Check for RICOH RF5C[23]96 PCMCIA Controller
692                  */
693                 c = exca_getb(exca, EXCA_RICOH_ID);
694                 if (c == EXCA_RID_396) {
695                         exca->chipset = EXCA_RF5C396;
696                         break;
697                 } else if (c == EXCA_RID_296) {
698                         exca->chipset = EXCA_RF5C296;
699                         break;
700                 }
701                 /*
702                  *      Check for Cirrus logic chips.
703                  */
704                 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0);
705                 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
706                 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) ==
707                     EXCA_CIRRUS_CHIP_INFO_CHIP_ID) {
708                         c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
709                         if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
710                                 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS)
711                                         exca->chipset = EXCA_PD6722;
712                                 else
713                                         exca->chipset = EXCA_PD6710;
714                                 break;
715                         }
716                 }
717                 break;
718
719         case EXCA_IDENT_REV_I82365SLDF:
720                 /*
721                  *      Intel i82365sl-DF step or maybe a vlsi 82c146
722                  * we detected the vlsi case earlier, so if the controller
723                  * isn't set, we know it is a i82365sl step D.
724                  */
725                 exca->chipset = EXCA_I82365SL_DF;
726                 break;
727         case EXCA_IDENT_REV_IBM1:
728         case EXCA_IDENT_REV_IBM2:
729                 exca->chipset = EXCA_IBM;
730                 break;
731         case EXCA_IDENT_REV_IBM_KING:
732                 exca->chipset = EXCA_IBM_KING;
733                 break;
734         default:
735                 return (0);
736         }
737         return (1);
738 }
739
740 /*
741  * Probe the expected slots.  We maybe should set the ID for each of these
742  * slots too while we're at it.  But maybe that belongs to a separate
743  * function.
744  *
745  * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
746  */
747 int
748 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
749     bus_space_handle_t ioh)
750 {
751         int err;
752         int i;
753
754         err = ENXIO;
755         for (i = 0; i < EXCA_NSLOTS; i++)  {
756                 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE);
757                 exca->getb = exca_io_getb;
758                 exca->putb = exca_io_putb;
759                 if (exca_valid_slot(&exca[i])) {
760                         device_set_desc(dev, chip_names[exca[i].chipset]);
761                         err = 0;
762                 }
763         }
764         return (err);
765 }
766
767 void
768 exca_insert(struct exca_softc *exca)
769 {
770         if (exca->pccarddev != NULL) {
771                 if (CARD_ATTACH_CARD(exca->pccarddev) != 0)
772                         device_printf(exca->dev,
773                             "PC Card card activation failed\n");
774         } else {
775                 device_printf(exca->dev,
776                     "PC Card inserted, but no pccard bus.\n");
777         }
778 }
779   
780
781 void
782 exca_removal(struct exca_softc *exca)
783 {
784         if (exca->pccarddev != NULL)
785                 CARD_DETACH_CARD(exca->pccarddev);
786 }
787
788 int
789 exca_activate_resource(struct exca_softc *exca, device_t child, int type,
790     int rid, struct resource *res)
791 {
792         int err;
793         if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */
794                 switch (type) {
795                 case SYS_RES_IOPORT:
796                         err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res);
797                         break;
798                 case SYS_RES_MEMORY:
799                         err = exca_mem_map(exca, PCCARD_A_MEM_COM, res);
800                         break;
801                 default:
802                         err = 0;
803                         break;
804                 }
805                 if (err)
806                         return (err);
807
808         }
809         return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
810                   type, rid, res));
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);