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