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