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