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