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