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