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