xref: /freebsd/sys/dev/exca/exca.c (revision 9162f64b58d01ec01481d60b6cdc06ffd8e8c7fc)
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 
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 static const char *chip_names[] =
90 {
91 	"CardBus socket",
92 	"Intel i82365SL-A/B or clone",
93 	"Intel i82365sl-DF step",
94 	"VLSI chip",
95 	"Cirrus Logic PD6710",
96 	"Cirrus logic PD6722",
97 	"Cirrus Logic PD6729",
98 	"Vadem 365",
99 	"Vadem 465",
100 	"Vadem 468",
101 	"Vadem 469",
102 	"Ricoh RF5C296",
103 	"Ricoh RF5C396",
104 	"IBM clone",
105 	"IBM KING PCMCIA Controller"
106 };
107 
108 static exca_getb_fn exca_mem_getb;
109 static exca_putb_fn exca_mem_putb;
110 static exca_getb_fn exca_io_getb;
111 static exca_putb_fn exca_io_putb;
112 
113 /* memory */
114 
115 #define	EXCA_MEMINFO(NUM) {						\
116 	EXCA_SYSMEM_ADDR ## NUM ## _START_LSB,				\
117 	EXCA_SYSMEM_ADDR ## NUM ## _START_MSB,				\
118 	EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB,				\
119 	EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB,				\
120 	EXCA_SYSMEM_ADDR ## NUM ## _WIN,				\
121 	EXCA_CARDMEM_ADDR ## NUM ## _LSB,				\
122 	EXCA_CARDMEM_ADDR ## NUM ## _MSB,				\
123 	EXCA_ADDRWIN_ENABLE_MEM ## NUM,					\
124 }
125 
126 static struct mem_map_index_st {
127 	int	sysmem_start_lsb;
128 	int	sysmem_start_msb;
129 	int	sysmem_stop_lsb;
130 	int	sysmem_stop_msb;
131 	int	sysmem_win;
132 	int	cardmem_lsb;
133 	int	cardmem_msb;
134 	int	memenable;
135 } mem_map_index[] = {
136 	EXCA_MEMINFO(0),
137 	EXCA_MEMINFO(1),
138 	EXCA_MEMINFO(2),
139 	EXCA_MEMINFO(3),
140 	EXCA_MEMINFO(4)
141 };
142 #undef	EXCA_MEMINFO
143 
144 static uint8_t
145 exca_mem_getb(struct exca_softc *sc, int reg)
146 {
147 	return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
148 }
149 
150 static void
151 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val)
152 {
153 	bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val);
154 }
155 
156 static uint8_t
157 exca_io_getb(struct exca_softc *sc, int reg)
158 {
159 	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
160 	return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA));
161 }
162 
163 static void
164 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val)
165 {
166 	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
167 	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val);
168 }
169 
170 /*
171  * Helper function.  This will map the requested memory slot.  We setup the
172  * map before we call this function.  This is used to initially force the
173  * mapping, as well as later restore the mapping after it has been destroyed
174  * in some fashion (due to a power event typically).
175  */
176 static void
177 exca_do_mem_map(struct exca_softc *sc, int win)
178 {
179 	struct mem_map_index_st *map;
180 	struct pccard_mem_handle *mem;
181 	uint32_t offset;
182 	uint32_t mem16;
183 	uint32_t attrmem;
184 
185 	map = &mem_map_index[win];
186 	mem = &sc->mem[win];
187 	mem16 = (mem->kind & PCCARD_MEM_16BIT) ?
188 	    EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT : 0;
189 	attrmem = (mem->kind & PCCARD_MEM_ATTR) ?
190 	    EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0;
191 	offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) -
192 	  (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff;
193 	exca_putb(sc, map->sysmem_start_lsb,
194 	    mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT);
195 	exca_putb(sc, map->sysmem_start_msb,
196 	    ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
197 	    EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | mem16);
198 
199 	exca_putb(sc, map->sysmem_stop_lsb,
200 	    (mem->addr + mem->realsize - 1) >> EXCA_SYSMEM_ADDRX_SHIFT);
201 	exca_putb(sc, map->sysmem_stop_msb,
202 	    (((mem->addr + mem->realsize - 1) >>
203 	    (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
204 	    EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
205 	    EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2);
206 	exca_putb(sc, map->sysmem_win, mem->addr >> EXCA_MEMREG_WIN_SHIFT);
207 
208 	exca_putb(sc, map->cardmem_lsb, offset & 0xff);
209 	exca_putb(sc, map->cardmem_msb, ((offset >> 8) &
210 	    EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | attrmem);
211 
212 #ifdef EXCA_DEBUG
213 	if (mem->kind & PCCARD_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 (ENOSPC);
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 (EINVAL);
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 resource.  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 	switch (flags)
345 	{
346 	case PCCARD_A_MEM_ATTR:
347 		sc->mem[win].kind |= PCCARD_MEM_ATTR;
348 		break;
349 	case PCCARD_A_MEM_COM:
350 		sc->mem[win].kind &= ~PCCARD_MEM_ATTR;
351 		break;
352 	case PCCARD_A_MEM_16BIT:
353 		sc->mem[win].kind |= PCCARD_MEM_16BIT;
354 		break;
355 	case PCCARD_A_MEM_8BIT:
356 		sc->mem[win].kind &= ~PCCARD_MEM_16BIT;
357 		break;
358 	}
359 	exca_do_mem_map(sc, win);
360 	return (0);
361 }
362 
363 /*
364  * Given a resource, go ahead and unmap it if we can find it in the
365  * resrouce list that's used.
366  */
367 int
368 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
369 {
370 	int win;
371 
372 	win = exca_mem_findmap(sc, res);
373 	if (win < 0)
374 		return (ENOENT);
375 	exca_mem_unmap(sc, win);
376 	return (0);
377 }
378 
379 /*
380  * Set the offset of the memory.  We use this for reading the CIS and
381  * frobbing the pccard's pccard registers (CCR, etc).  Some drivers
382  * need to access arbitrary attribute and common memory during their
383  * initialization and operation.
384  */
385 int
386 exca_mem_set_offset(struct exca_softc *sc, struct resource *res,
387     uint32_t cardaddr, uint32_t *deltap)
388 {
389 	int win;
390 	uint32_t delta;
391 
392 	win = exca_mem_findmap(sc, res);
393 	if (win < 0) {
394 		device_printf(sc->dev,
395 		    "set_memory_offset: specified resource not active\n");
396 		return (ENOENT);
397 	}
398 	sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1);
399 	delta = cardaddr % EXCA_MEM_PAGESIZE;
400 	if (deltap)
401 		*deltap = delta;
402 	sc->mem[win].realsize = sc->mem[win].size + delta +
403 	    EXCA_MEM_PAGESIZE - 1;
404 	sc->mem[win].realsize = sc->mem[win].realsize -
405 	    (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
406 	exca_do_mem_map(sc, win);
407 	return (0);
408 }
409 
410 
411 /* I/O */
412 
413 #define	EXCA_IOINFO(NUM) {						\
414 	EXCA_IOADDR ## NUM ## _START_LSB,				\
415 	EXCA_IOADDR ## NUM ## _START_MSB,				\
416 	EXCA_IOADDR ## NUM ## _STOP_LSB,				\
417 	EXCA_IOADDR ## NUM ## _STOP_MSB,				\
418 	EXCA_ADDRWIN_ENABLE_IO ## NUM,					\
419 	EXCA_IOCTL_IO ## NUM ## _WAITSTATE				\
420 	| EXCA_IOCTL_IO ## NUM ## _ZEROWAIT				\
421 	| EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK			\
422 	| EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK,			\
423 	{								\
424 		EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD,		\
425 		EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE		\
426 		| EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT,		\
427 		EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE		\
428 		| EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT,		\
429 	}								\
430 }
431 
432 static struct io_map_index_st {
433 	int	start_lsb;
434 	int	start_msb;
435 	int	stop_lsb;
436 	int	stop_msb;
437 	int	ioenable;
438 	int	ioctlmask;
439 	int	ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */
440 } io_map_index[] = {
441 	EXCA_IOINFO(0),
442 	EXCA_IOINFO(1),
443 };
444 #undef	EXCA_IOINFO
445 
446 static void
447 exca_do_io_map(struct exca_softc *sc, int win)
448 {
449 	struct io_map_index_st *map;
450 
451 	struct pccard_io_handle *io;
452 
453 	map = &io_map_index[win];
454 	io = &sc->io[win];
455 	exca_putb(sc, map->start_lsb, io->addr & 0xff);
456 	exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff);
457 
458 	exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff);
459 	exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff);
460 
461 	exca_clrb(sc, EXCA_IOCTL, map->ioctlmask);
462 	exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]);
463 
464 	exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable);
465 #ifdef EXCA_DEBUG
466 	{
467 		int r1, r2, r3, r4;
468 		r1 = exca_getb(sc, map->start_msb);
469 		r2 = exca_getb(sc, map->start_lsb);
470 		r3 = exca_getb(sc, map->stop_msb);
471 		r4 = exca_getb(sc, map->stop_lsb);
472 		DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x "
473 		    "(%08x+%08x)\n", win, r1, r2, r3, r4,
474 		    io->addr, io->size);
475 	}
476 #endif
477 }
478 
479 int
480 exca_io_map(struct exca_softc *sc, int width, struct resource *r)
481 {
482 	int win;
483 #ifdef EXCA_DEBUG
484 	static char *width_names[] = { "auto", "io8", "io16"};
485 #endif
486 	for (win=0; win < EXCA_IO_WINS; win++) {
487 		if ((sc->ioalloc & (1 << win)) == 0) {
488 			sc->ioalloc |= (1 << win);
489 			break;
490 		}
491 	}
492 	if (win >= EXCA_IO_WINS)
493 		return (ENOSPC);
494 
495 	sc->io[win].iot = rman_get_bustag(r);
496 	sc->io[win].ioh = rman_get_bushandle(r);
497 	sc->io[win].addr = rman_get_start(r);
498 	sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1;
499 	sc->io[win].flags = 0;
500 	sc->io[win].width = width;
501 	DPRINTF("exca_io_map window %d %s port %x+%x\n",
502 	    win, width_names[width], sc->io[win].addr,
503 	    sc->io[win].size);
504 	exca_do_io_map(sc, win);
505 
506 	return (0);
507 }
508 
509 static void
510 exca_io_unmap(struct exca_softc *sc, int window)
511 {
512 	if (window >= EXCA_IO_WINS)
513 		panic("exca_io_unmap: window out of range");
514 
515 	exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable);
516 
517 	sc->ioalloc &= ~(1 << window);
518 
519 	sc->io[window].iot = 0;
520 	sc->io[window].ioh = 0;
521 	sc->io[window].addr = 0;
522 	sc->io[window].size = 0;
523 	sc->io[window].flags = 0;
524 	sc->io[window].width = 0;
525 }
526 
527 static int
528 exca_io_findmap(struct exca_softc *sc, struct resource *res)
529 {
530 	int win;
531 
532 	for (win = 0; win < EXCA_IO_WINS; win++) {
533 		if (sc->io[win].iot == rman_get_bustag(res) &&
534 		    sc->io[win].addr == rman_get_start(res) &&
535 		    sc->io[win].size == rman_get_size(res))
536 			return (win);
537 	}
538 	return (-1);
539 }
540 
541 
542 int
543 exca_io_unmap_res(struct exca_softc *sc, struct resource *res)
544 {
545 	int win;
546 
547 	win = exca_io_findmap(sc, res);
548 	if (win < 0)
549 		return (ENOENT);
550 	exca_io_unmap(sc, win);
551 	return (0);
552 }
553 
554 /* Misc */
555 
556 /*
557  * If interrupts are enabled, then we should be able to just wait for
558  * an interrupt routine to wake us up.  Busy waiting shouldn't be
559  * necessary.  Sadly, not all legacy ISA cards support an interrupt
560  * for the busy state transitions, at least according to their datasheets,
561  * so we busy wait a while here..
562  */
563 static void
564 exca_wait_ready(struct exca_softc *sc)
565 {
566 	int i;
567 	DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n",
568 	    exca_getb(sc, EXCA_IF_STATUS));
569 	for (i = 0; i < 10000; i++) {
570 		if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY)
571 			return;
572 		DELAY(500);
573 	}
574 	device_printf(sc->dev, "ready never happened, status = %02x\n",
575 	    exca_getb(sc, EXCA_IF_STATUS));
576 }
577 
578 /*
579  * Reset the card.  Ideally, we'd do a lot of this via interrupts.
580  * However, many PC Cards will deassert the ready signal.  This means
581  * that they are asserting an interrupt.  This makes it hard to
582  * do anything but a busy wait here.  One could argue that these
583  * such cards are broken, or that the bridge that allows this sort
584  * of interrupt through isn't quite what you'd want (and may be a standards
585  * violation).  However, such arguing would leave a huge class of PC Cards
586  * and bridges out of reach for use in the system.
587  *
588  * Maybe I should reevaluate the above based on the power bug I fixed
589  * in OLDCARD.
590  */
591 void
592 exca_reset(struct exca_softc *sc, device_t child)
593 {
594 	int win;
595 
596 	/* enable socket i/o */
597 	exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE);
598 
599 	exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE);
600 	/* hold reset for 30ms */
601 	DELAY(30*1000);
602 	/* clear the reset flag */
603 	exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET);
604 	/* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */
605 	DELAY(20*1000);
606 
607 	exca_wait_ready(sc);
608 
609 	/* disable all address windows */
610 	exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0);
611 
612 	exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO);
613 	DEVPRINTF(sc->dev, "card type is io\n");
614 
615 	/* reinstall all the memory and io mappings */
616 	for (win = 0; win < EXCA_MEM_WINS; ++win)
617 		if (sc->memalloc & (1 << win))
618 			exca_do_mem_map(sc, win);
619 	for (win = 0; win < EXCA_IO_WINS; ++win)
620 		if (sc->ioalloc & (1 << win))
621 			exca_do_io_map(sc, win);
622 }
623 
624 /*
625  * Initialize the exca_softc data structure for the first time.
626  */
627 void
628 exca_init(struct exca_softc *sc, device_t dev,
629     bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset)
630 {
631 	sc->dev = dev;
632 	sc->memalloc = 0;
633 	sc->ioalloc = 0;
634 	sc->bst = bst;
635 	sc->bsh = bsh;
636 	sc->offset = offset;
637 	sc->flags = 0;
638 	sc->getb = exca_mem_getb;
639 	sc->putb = exca_mem_putb;
640 }
641 
642 /*
643  * Is this socket valid?
644  */
645 static int
646 exca_valid_slot(struct exca_softc *exca)
647 {
648 	uint8_t c;
649 
650 	/* Assume the worst */
651 	exca->chipset = EXCA_BOGUS;
652 
653 	/*
654 	 * see if there's a PCMCIA controller here
655 	 * Intel PCMCIA controllers use 0x82 and 0x83
656 	 * IBM clone chips use 0x88 and 0x89, apparently
657 	 */
658 	c = exca_getb(exca, EXCA_IDENT);
659 	DEVPRINTF(exca->dev, "Ident is %x\n", c);
660 	if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO)
661 		return (0);
662 	if ((c & EXCA_IDENT_ZERO) != 0)
663 		return (0);
664 	switch (c & EXCA_IDENT_REV_MASK) {
665 	/*
666 	 *	82365 or clones.
667 	 */
668 	case EXCA_IDENT_REV_I82365SLR0:
669 	case EXCA_IDENT_REV_I82365SLR1:
670 		exca->chipset = EXCA_I82365;
671 		/*
672 		 * Check for Vadem chips by unlocking their extra
673 		 * registers and looking for valid ID.  Bit 3 in
674 		 * the ID register is normally 0, except when
675 		 * EXCA_VADEMREV is set.  Other bridges appear
676 		 * to ignore this frobbing.
677 		 */
678 		bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
679 		    EXCA_VADEM_COOKIE1);
680 		bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
681 		    EXCA_VADEM_COOKIE2);
682 		exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
683 		c = exca_getb(exca, EXCA_IDENT);
684 		if (c & 0x08) {
685 			switch (c & 7) {
686 			case 1:
687 				exca->chipset = EXCA_VG365;
688 				break;
689 			case 2:
690 				exca->chipset = EXCA_VG465;
691 				break;
692 			case 3:
693 				exca->chipset = EXCA_VG468;
694 				break;
695 			default:
696 				exca->chipset = EXCA_VG469;
697 				break;
698 			}
699 			exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
700 			break;
701 		}
702 		/*
703 		 * Check for RICOH RF5C[23]96 PCMCIA Controller
704 		 */
705 		c = exca_getb(exca, EXCA_RICOH_ID);
706 		if (c == EXCA_RID_396) {
707 			exca->chipset = EXCA_RF5C396;
708 			break;
709 		} else if (c == EXCA_RID_296) {
710 			exca->chipset = EXCA_RF5C296;
711 			break;
712 		}
713 		/*
714 		 *	Check for Cirrus logic chips.
715 		 */
716 		exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0);
717 		c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
718 		if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) ==
719 		    EXCA_CIRRUS_CHIP_INFO_CHIP_ID) {
720 			c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
721 			if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
722 				if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS)
723 					exca->chipset = EXCA_PD6722;
724 				else
725 					exca->chipset = EXCA_PD6710;
726 				break;
727 			}
728 		}
729 		break;
730 
731 	case EXCA_IDENT_REV_I82365SLDF:
732 		/*
733 		 *	Intel i82365sl-DF step or maybe a vlsi 82c146
734 		 * we detected the vlsi case earlier, so if the controller
735 		 * isn't set, we know it is a i82365sl step D.
736 		 */
737 		exca->chipset = EXCA_I82365SL_DF;
738 		break;
739 	case EXCA_IDENT_REV_IBM1:
740 	case EXCA_IDENT_REV_IBM2:
741 		exca->chipset = EXCA_IBM;
742 		break;
743 	case EXCA_IDENT_REV_IBM_KING:
744 		exca->chipset = EXCA_IBM_KING;
745 		break;
746 	default:
747 		return (0);
748 	}
749 	return (1);
750 }
751 
752 /*
753  * Probe the expected slots.  We maybe should set the ID for each of these
754  * slots too while we're at it.  But maybe that belongs to a separate
755  * function.
756  *
757  * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
758  */
759 int
760 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
761     bus_space_handle_t ioh)
762 {
763 	int err;
764 	int i;
765 
766 	err = ENXIO;
767 	for (i = 0; i < EXCA_NSLOTS; i++)  {
768 		exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE);
769 		exca->getb = exca_io_getb;
770 		exca->putb = exca_io_putb;
771 		if (exca_valid_slot(&exca[i])) {
772 			device_set_desc(dev, chip_names[exca[i].chipset]);
773 			err = 0;
774 		}
775 	}
776 	return (err);
777 }
778 
779 void
780 exca_insert(struct exca_softc *exca)
781 {
782 	if (device_is_attached(exca->pccarddev)) {
783 		if (CARD_ATTACH_CARD(exca->pccarddev) != 0)
784 			device_printf(exca->dev,
785 			    "PC Card card activation failed\n");
786 	} else {
787 		device_printf(exca->dev,
788 		    "PC Card inserted, but no pccard bus.\n");
789 	}
790 }
791 
792 
793 void
794 exca_removal(struct exca_softc *exca)
795 {
796 	if (device_is_attached(exca->pccarddev))
797 		CARD_DETACH_CARD(exca->pccarddev);
798 }
799 
800 int
801 exca_activate_resource(struct exca_softc *exca, device_t child, int type,
802     int rid, struct resource *res)
803 {
804 	int err;
805 
806 	if (rman_get_flags(res) & RF_ACTIVE)
807 		return (0);
808 	err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
809 	    type, rid, res);
810 	if (err)
811 		return (err);
812 	switch (type) {
813 	case SYS_RES_IOPORT:
814 		err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res);
815 		break;
816 	case SYS_RES_MEMORY:
817 		err = exca_mem_map(exca, 0, res);
818 		break;
819 	}
820 	if (err)
821 		BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
822 		    type, rid, res);
823 	return (err);
824 }
825 
826 int
827 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type,
828     int rid, struct resource *res)
829 {
830 	if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */
831 		switch (type) {
832 		case SYS_RES_IOPORT:
833 			if (exca_io_unmap_res(exca, res))
834 				return (ENOENT);
835 			break;
836 		case SYS_RES_MEMORY:
837 			if (exca_mem_unmap_res(exca, res))
838 				return (ENOENT);
839 			break;
840 		}
841 	}
842 	return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
843 	    type, rid, res));
844 }
845 
846 #if 0
847 static struct resource *
848 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid,
849     u_long start, u_long end, u_long count, uint flags)
850 {
851 	struct resource *res = NULL;
852 	int tmp;
853 
854 	switch (type) {
855 	case SYS_RES_MEMORY:
856 		if (start < cbb_start_mem)
857 			start = cbb_start_mem;
858 		if (end < start)
859 			end = start;
860 		flags = (flags & ~RF_ALIGNMENT_MASK) |
861 		    rman_make_alignment_flags(CBB_MEMALIGN);
862 		break;
863 	case SYS_RES_IOPORT:
864 		if (start < cbb_start_16_io)
865 			start = cbb_start_16_io;
866 		if (end < start)
867 			end = start;
868 		break;
869 	case SYS_RES_IRQ:
870 		tmp = rman_get_start(sc->irq_res);
871 		if (start > tmp || end < tmp || count != 1) {
872 			device_printf(child, "requested interrupt %ld-%ld,"
873 			    "count = %ld not supported by cbb\n",
874 			    start, end, count);
875 			return (NULL);
876 		}
877 		flags |= RF_SHAREABLE;
878 		start = end = rman_get_start(sc->irq_res);
879 		break;
880 	}
881 	res = BUS_ALLOC_RESOURCE(up, child, type, rid,
882 	    start, end, count, flags & ~RF_ACTIVE);
883 	if (res == NULL)
884 		return (NULL);
885 	cbb_insert_res(sc, res, type, *rid);
886 	if (flags & RF_ACTIVE) {
887 		if (bus_activate_resource(child, type, *rid, res) != 0) {
888 			bus_release_resource(child, type, *rid, res);
889 			return (NULL);
890 		}
891 	}
892 
893 	return (res);
894 }
895 
896 static int
897 exca_release_resource(struct exca_softc *sc, device_t child, int type,
898     int rid, struct resource *res)
899 {
900 	int error;
901 
902 	if (rman_get_flags(res) & RF_ACTIVE) {
903 		error = bus_deactivate_resource(child, type, rid, res);
904 		if (error != 0)
905 			return (error);
906 	}
907 	cbb_remove_res(sc, res);
908 	return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
909 	    type, rid, res));
910 }
911 #endif
912 
913 static int
914 exca_modevent(module_t mod, int cmd, void *arg)
915 {
916 	return 0;
917 }
918 
919 DEV_MODULE(exca, exca_modevent, NULL);
920 MODULE_VERSION(exca, 1);
921