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