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