xref: /freebsd/sys/dev/exca/exca.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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/errno.h>
60 #include <sys/kernel.h>
61 #include <sys/malloc.h>
62 #include <sys/queue.h>
63 #include <sys/module.h>
64 #include <sys/conf.h>
65 
66 #include <sys/bus.h>
67 #include <machine/bus.h>
68 #include <sys/rman.h>
69 #include <machine/resource.h>
70 
71 #include <dev/pccard/pccardreg.h>
72 #include <dev/pccard/pccardvar.h>
73 
74 #include <dev/exca/excareg.h>
75 #include <dev/exca/excavar.h>
76 
77 #ifdef EXCA_DEBUG
78 #define DEVPRINTF(dev, fmt, args...)	device_printf((dev), (fmt), ## args)
79 #define DPRINTF(fmt, args...)		printf(fmt, ## args)
80 #else
81 #define DEVPRINTF(dev, fmt, args...)
82 #define DPRINTF(fmt, args...)
83 #endif
84 
85 #if 0
86 static const char *chip_names[] =
87 {
88 	"CardBus socket",
89 	"Intel i82365SL-A/B or clone",
90 	"Intel i82365sl-DF step",
91 	"VLSI chip",
92 	"Cirrus Logic PD6710",
93 	"Cirrus logic PD6722",
94 	"Cirrus Logic PD6729",
95 	"Vadem 365",
96 	"Vadem 465",
97 	"Vadem 468",
98 	"Vadem 469",
99 	"Ricoh RF5C296",
100 	"Ricoh RF5C396",
101 	"IBM clone",
102 	"IBM KING PCMCIA Controller"
103 };
104 #endif
105 
106 static exca_getb_fn exca_mem_getb;
107 static exca_putb_fn exca_mem_putb;
108 static exca_getb_fn exca_io_getb;
109 static exca_putb_fn exca_io_putb;
110 
111 /* memory */
112 
113 #define	EXCA_MEMINFO(NUM) {						\
114 	EXCA_SYSMEM_ADDR ## NUM ## _START_LSB,				\
115 	EXCA_SYSMEM_ADDR ## NUM ## _START_MSB,				\
116 	EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB,				\
117 	EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB,				\
118 	EXCA_SYSMEM_ADDR ## NUM ## _WIN,				\
119 	EXCA_CARDMEM_ADDR ## NUM ## _LSB,				\
120 	EXCA_CARDMEM_ADDR ## NUM ## _MSB,				\
121 	EXCA_ADDRWIN_ENABLE_MEM ## NUM,					\
122 }
123 
124 static struct mem_map_index_st {
125 	int	sysmem_start_lsb;
126 	int	sysmem_start_msb;
127 	int	sysmem_stop_lsb;
128 	int	sysmem_stop_msb;
129 	int	sysmem_win;
130 	int	cardmem_lsb;
131 	int	cardmem_msb;
132 	int	memenable;
133 } mem_map_index[] = {
134 	EXCA_MEMINFO(0),
135 	EXCA_MEMINFO(1),
136 	EXCA_MEMINFO(2),
137 	EXCA_MEMINFO(3),
138 	EXCA_MEMINFO(4)
139 };
140 #undef	EXCA_MEMINFO
141 
142 static uint8_t
143 exca_mem_getb(struct exca_softc *sc, int reg)
144 {
145 	return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
146 }
147 
148 static void
149 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val)
150 {
151 	return (bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val));
152 }
153 
154 static uint8_t
155 exca_io_getb(struct exca_softc *sc, int reg)
156 {
157 	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
158 	return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA));
159 }
160 
161 static void
162 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val)
163 {
164 	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
165 	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val);
166 }
167 
168 /*
169  * Helper function.  This will map the requested memory slot.  We setup the
170  * map before we call this function.  This is used to initially force the
171  * mapping, as well as later restore the mapping after it has been destroyed
172  * in some fashion (due to a power event typically).
173  */
174 static void
175 exca_do_mem_map(struct exca_softc *sc, int win)
176 {
177 	struct mem_map_index_st *map;
178 	struct pccard_mem_handle *mem;
179 
180 	map = &mem_map_index[win];
181 	mem = &sc->mem[win];
182 	exca_putb(sc, map->sysmem_start_lsb,
183 	    (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
184 	exca_putb(sc, map->sysmem_start_msb,
185 	    ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
186 	    EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | 0x80);
187 
188 	exca_putb(sc, map->sysmem_stop_lsb,
189 	    ((mem->addr + mem->realsize - 1) >>
190 	    EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
191 	exca_putb(sc, map->sysmem_stop_msb,
192 	    (((mem->addr + mem->realsize - 1) >>
193 	    (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
194 	    EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
195 	    EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2);
196 
197 	exca_putb(sc, map->sysmem_win,
198 	    (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff);
199 
200 	exca_putb(sc, map->cardmem_lsb,
201 	    (mem->offset >> EXCA_CARDMEM_ADDRX_SHIFT) & 0xff);
202 	exca_putb(sc, map->cardmem_msb,
203 	    ((mem->offset >> (EXCA_CARDMEM_ADDRX_SHIFT + 8)) &
204 	    EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) |
205 	    ((mem->kind == PCCARD_MEM_ATTR) ?
206 	    EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0));
207 
208 	exca_setb(sc, EXCA_ADDRWIN_ENABLE, EXCA_ADDRWIN_ENABLE_MEMCS16 |
209 	    map->memenable);
210 
211 	DELAY(100);
212 #ifdef EXCA_DEBUG
213 	{
214 		int r1, r2, r3, r4, r5, r6, r7;
215 		r1 = exca_getb(sc, map->sysmem_start_msb);
216 		r2 = exca_getb(sc, map->sysmem_start_lsb);
217 		r3 = exca_getb(sc, map->sysmem_stop_msb);
218 		r4 = exca_getb(sc, map->sysmem_stop_lsb);
219 		r5 = exca_getb(sc, map->cardmem_msb);
220 		r6 = exca_getb(sc, map->cardmem_lsb);
221 		r7 = exca_getb(sc, map->sysmem_win);
222 		printf("exca_do_mem_map window %d: %02x%02x %02x%02x "
223 		    "%02x%02x %02x (%08x+%08x.%08x*%08lx)\n",
224 		    win, r1, r2, r3, r4, r5, r6, r7,
225 		    mem->addr, mem->size, mem->realsize,
226 		    mem->offset);
227 	}
228 #endif
229 }
230 
231 /*
232  * public interface to map a resource.  kind is the type of memory to
233  * map (either common or attribute).  Memory created via this interface
234  * starts out at card address 0.  Since the only way to set this is
235  * to set it on a struct resource after it has been mapped, we're safe
236  * in maping this assumption.  Note that resources can be remapped using
237  * exca_do_mem_map so that's how the card address can be set later.
238  */
239 int
240 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res)
241 {
242 	int win;
243 
244 	for (win = 0; win < EXCA_MEM_WINS; win++) {
245 		if ((sc->memalloc & (1 << win)) == 0) {
246 			sc->memalloc |= (1 << win);
247 			break;
248 		}
249 	}
250 	if (win >= EXCA_MEM_WINS)
251 		return (1);
252 	if (((rman_get_start(res) >> EXCA_CARDMEM_ADDRX_SHIFT) & 0xff) != 0 &&
253 	    (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) {
254 		device_printf(sc->dev, "Does not support mapping above 24M.");
255 		return (1);
256 	}
257 
258 	sc->mem[win].cardaddr = 0;
259 	sc->mem[win].memt = rman_get_bustag(res);
260 	sc->mem[win].memh = rman_get_bushandle(res);
261 	sc->mem[win].addr = rman_get_start(res);
262 	sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1;
263 	sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1;
264 	sc->mem[win].realsize = sc->mem[win].realsize -
265 	    (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
266 	sc->mem[win].offset = (long)(sc->mem[win].addr);
267 	sc->mem[win].kind = kind;
268 	DPRINTF("exca_mem_map window %d bus %x+%x+%lx card addr %x\n",
269 	    win, sc->mem[win].addr, sc->mem[win].size,
270 	    sc->mem[win].offset, sc->mem[win].cardaddr);
271 	exca_do_mem_map(sc, win);
272 
273 	return (0);
274 }
275 
276 /*
277  * Private helper function.  This turns off a given memory map that is in
278  * use.  We do this by just clearing the enable bit in the pcic.  If we needed
279  * to make memory unmapping/mapping pairs faster, we would have to store
280  * more state information about the pcic and then use that to intelligently
281  * to the map/unmap.  However, since we don't do that sort of thing often
282  * (generally just at configure time), it isn't a case worth optimizing.
283  */
284 static void
285 exca_mem_unmap(struct exca_softc *sc, int window)
286 {
287 	if (window < 0 || window >= EXCA_MEM_WINS)
288 		panic("exca_mem_unmap: window out of range");
289 
290 	exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable);
291 	sc->memalloc &= ~(1 << window);
292 }
293 
294 /*
295  * Find the map that we're using to hold the resoruce.  This works well
296  * so long as the client drivers don't do silly things like map the same
297  * area mutliple times, or map both common and attribute memory at the
298  * same time.  This latter restriction is a bug.  We likely should just
299  * store a pointer to the res in the mem[x] data structure.
300  */
301 static int
302 exca_mem_findmap(struct exca_softc *sc, struct resource *res)
303 {
304 	int win;
305 
306 	for (win = 0; win < EXCA_MEM_WINS; win++) {
307 		if (sc->mem[win].memt == rman_get_bustag(res) &&
308 		    sc->mem[win].addr == rman_get_start(res) &&
309 		    sc->mem[win].size == rman_get_size(res))
310 			return (win);
311 	}
312 	return (-1);
313 }
314 
315 /*
316  * Set the memory flag.  This means that we are setting if the memory
317  * is coming from attribute memory or from common memory on the card.
318  * CIS entries are generally in attribute memory (although they can
319  * reside in common memory).  Generally, this is the only use for attribute
320  * memory.  However, some cards require their drivers to dance in both
321  * common and/or attribute memory and this interface (and setting the
322  * offset interface) exist for such cards.
323  */
324 int
325 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags)
326 {
327 	int win;
328 
329 	win = exca_mem_findmap(sc, res);
330 	if (win < 0) {
331 		device_printf(sc->dev,
332 		    "set_res_flags: specified resource not active\n");
333 		return (ENOENT);
334 	}
335 
336 	sc->mem[win].kind = flags;
337 	exca_do_mem_map(sc, win);
338 	return (0);
339 }
340 
341 /*
342  * Given a resource, go ahead and unmap it if we can find it in the
343  * resrouce list that's used.
344  */
345 int
346 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
347 {
348 	int win;
349 
350 	win = exca_mem_findmap(sc, res);
351 	if (win < 0)
352 		return (ENOENT);
353 	exca_mem_unmap(sc, win);
354 	return (0);
355 }
356 
357 /*
358  * Set the offset of the memory.  We use this for reading the CIS and
359  * frobbing the pccard's pccard registers (POR, etc).  Some drivers
360  * need to access this functionality as well, since they have receive
361  * buffers defined in the attribute memory.  Thankfully, these cards
362  * are few and fare between.  Some cards also have common memory that
363  * is large and only map a small portion of it at a time (but these cards
364  * are rare, the more common case being to have just a small amount
365  * of common memory that the driver needs to bcopy data from in order to
366  * get at it.
367  */
368 int
369 exca_mem_set_offset(struct exca_softc *sc, struct resource *res,
370     uint32_t cardaddr, uint32_t *deltap)
371 {
372 	int win;
373 	uint32_t delta;
374 
375 	win = exca_mem_findmap(sc, res);
376 	if (win < 0) {
377 		device_printf(sc->dev,
378 		    "set_memory_offset: specified resource not active\n");
379 		return (ENOENT);
380 	}
381 	sc->mem[win].cardaddr = cardaddr;
382 	delta = cardaddr % EXCA_MEM_PAGESIZE;
383 	if (deltap)
384 		*deltap = delta;
385 	cardaddr -= delta;
386 	sc->mem[win].realsize = sc->mem[win].size + delta +
387 	    EXCA_MEM_PAGESIZE - 1;
388 	sc->mem[win].realsize = sc->mem[win].realsize -
389 	    (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
390 	sc->mem[win].offset = cardaddr - sc->mem[win].addr;
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 cardtype;
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 	CARD_GET_TYPE(child, &cardtype);
599 	exca_setb(sc, EXCA_INTR, (cardtype == PCCARD_IFTYPE_IO) ?
600 	    EXCA_INTR_CARDTYPE_IO : EXCA_INTR_CARDTYPE_MEM);
601 	DEVPRINTF(sc->dev, "card type is %s\n",
602 	    (cardtype == PCCARD_IFTYPE_IO) ? "io" : "mem");
603 
604 	/* reinstall all the memory and io mappings */
605 	for (win = 0; win < EXCA_MEM_WINS; ++win)
606 		if (sc->memalloc & (1 << win))
607 			exca_do_mem_map(sc, win);
608 	for (win = 0; win < EXCA_IO_WINS; ++win)
609 		if (sc->ioalloc & (1 << win))
610 			exca_do_io_map(sc, win);
611 }
612 
613 /*
614  * Initialize the exca_softc data structure for the first time.
615  */
616 void
617 exca_init(struct exca_softc *sc, device_t dev,
618     bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset)
619 {
620 	sc->dev = dev;
621 	sc->memalloc = 0;
622 	sc->ioalloc = 0;
623 	sc->bst = bst;
624 	sc->bsh = bsh;
625 	sc->offset = offset;
626 	sc->flags = 0;
627 	sc->getb = exca_mem_getb;
628 	sc->putb = exca_mem_putb;
629 }
630 
631 /*
632  * Is this socket valid?
633  */
634 static int
635 exca_valid_slot(struct exca_softc *exca)
636 {
637 	uint8_t c;
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 static int
763 exca_modevent(module_t mod, int cmd, void *arg)
764 {
765 	return 0;
766 }
767 
768 DEV_MODULE(exca, exca_modevent, NULL);
769 MODULE_VERSION(exca, 1);
770