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