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