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