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