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