xref: /dragonfly/sys/dev/pccard/exca/exca.c (revision 3f7b72606e8fadb0b2e9e32302c89298c107534b)
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
exca_mem_getb(struct exca_softc * sc,int reg)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
exca_mem_putb(struct exca_softc * sc,int reg,uint8_t val)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
exca_io_getb(struct exca_softc * sc,int reg)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
exca_io_putb(struct exca_softc * sc,int reg,uint8_t val)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
exca_do_mem_map(struct exca_softc * sc,int win)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
exca_mem_map(struct exca_softc * sc,int kind,struct resource * res)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
exca_mem_unmap(struct exca_softc * sc,int window)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
exca_mem_findmap(struct exca_softc * sc,struct resource * res)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
exca_mem_set_flags(struct exca_softc * sc,struct resource * res,uint32_t flags)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
exca_mem_unmap_res(struct exca_softc * sc,struct resource * res)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
exca_mem_set_offset(struct exca_softc * sc,struct resource * res,uint32_t cardaddr,uint32_t * deltap)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 
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
exca_do_io_map(struct exca_softc * sc,int win)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
exca_io_map(struct exca_softc * sc,int width,struct resource * r)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
exca_io_unmap(struct exca_softc * sc,int window)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
exca_io_findmap(struct exca_softc * sc,struct resource * res)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
exca_io_unmap_res(struct exca_softc * sc,struct resource * res)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 
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
exca_wait_ready(struct exca_softc * sc)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
exca_reset(struct exca_softc * sc,device_t child)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
exca_init(struct exca_softc * sc,device_t dev,bus_space_tag_t bst,bus_space_handle_t bsh,uint32_t offset)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
exca_valid_slot(struct exca_softc * exca)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
exca_probe_slots(device_t dev,struct exca_softc * exca,bus_space_tag_t iot,bus_space_handle_t ioh)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
exca_insert(struct exca_softc * exca)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
exca_removal(struct exca_softc * exca)773 exca_removal(struct exca_softc *exca)
774 {
775           if (exca->pccarddev != NULL)
776                     CARD_DETACH_CARD(exca->pccarddev);
777 }
778 
779 int
exca_activate_resource(struct exca_softc * exca,device_t child,int type,int rid,struct resource * res)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
exca_deactivate_resource(struct exca_softc * exca,device_t child,int type,int rid,struct resource * res)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
exca_modevent(module_t mod,int cmd,void * arg)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);
899