exca.c revision 150460
1139749Simp/*-
2140022Simp * Copyright (c) 2002-2005 M Warner Losh.  All rights reserved.
389948Simp *
489948Simp * Redistribution and use in source and binary forms, with or without
589948Simp * modification, are permitted provided that the following conditions
689948Simp * are met:
789948Simp * 1. Redistributions of source code must retain the above copyright
889948Simp *    notice, this list of conditions and the following disclaimer.
989948Simp * 2. Redistributions in binary form must reproduce the above copyright
1089948Simp *    notice, this list of conditions and the following disclaimer in the
1189948Simp *    documentation and/or other materials provided with the distribution.
1289948Simp *
1389948Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1489948Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1589948Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1689948Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1789948Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1889948Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1989948Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2089948Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2189948Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2289948Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2389948Simp *
2489948Simp * This software may be derived from NetBSD i82365.c and other files with
2589948Simp * the following copyright:
2689948Simp *
2789948Simp * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
2889948Simp *
2989948Simp * Redistribution and use in source and binary forms, with or without
3089948Simp * modification, are permitted provided that the following conditions
3189948Simp * are met:
3289948Simp * 1. Redistributions of source code must retain the above copyright
3389948Simp *    notice, this list of conditions and the following disclaimer.
3489948Simp * 2. Redistributions in binary form must reproduce the above copyright
3589948Simp *    notice, this list of conditions and the following disclaimer in the
3689948Simp *    documentation and/or other materials provided with the distribution.
3789948Simp * 3. All advertising materials mentioning features or use of this software
3889948Simp *    must display the following acknowledgement:
3989948Simp *	This product includes software developed by Marc Horowitz.
4089948Simp * 4. The name of the author may not be used to endorse or promote products
4189948Simp *    derived from this software without specific prior written permission.
4289948Simp *
4389948Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4489948Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4589948Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4689948Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
4789948Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4889948Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4989948Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5089948Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5189948Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5289948Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5389948Simp */
5489948Simp
55119511Simp#include <sys/cdefs.h>
56119511Simp__FBSDID("$FreeBSD: head/sys/dev/exca/exca.c 150460 2005-09-22 06:01:44Z imp $");
57119511Simp
5889948Simp#include <sys/param.h>
5989948Simp#include <sys/systm.h>
60115988Simp#include <sys/condvar.h>
6189948Simp#include <sys/errno.h>
6289948Simp#include <sys/kernel.h>
6389948Simp#include <sys/malloc.h>
6489948Simp#include <sys/queue.h>
6597613Stakawata#include <sys/module.h>
66115988Simp#include <sys/lock.h>
67115988Simp#include <sys/mutex.h>
6897613Stakawata#include <sys/conf.h>
6989948Simp
7089948Simp#include <sys/bus.h>
7189948Simp#include <machine/bus.h>
7289948Simp#include <sys/rman.h>
7389948Simp#include <machine/resource.h>
7489948Simp
7589948Simp#include <dev/pccard/pccardreg.h>
7689948Simp#include <dev/pccard/pccardvar.h>
7789948Simp
7889948Simp#include <dev/exca/excareg.h>
7989948Simp#include <dev/exca/excavar.h>
8089948Simp
8189948Simp#ifdef EXCA_DEBUG
8289948Simp#define DEVPRINTF(dev, fmt, args...)	device_printf((dev), (fmt), ## args)
8389948Simp#define DPRINTF(fmt, args...)		printf(fmt, ## args)
8489948Simp#else
8589948Simp#define DEVPRINTF(dev, fmt, args...)
8689948Simp#define DPRINTF(fmt, args...)
8789948Simp#endif
8889948Simp
89110841Simp#if 0
90110841Simpstatic const char *chip_names[] =
91110841Simp{
92110841Simp	"CardBus socket",
93110841Simp	"Intel i82365SL-A/B or clone",
94110841Simp	"Intel i82365sl-DF step",
95110841Simp	"VLSI chip",
96110841Simp	"Cirrus Logic PD6710",
97110841Simp	"Cirrus logic PD6722",
98110841Simp	"Cirrus Logic PD6729",
99110841Simp	"Vadem 365",
100110841Simp	"Vadem 465",
101110841Simp	"Vadem 468",
102110841Simp	"Vadem 469",
103110841Simp	"Ricoh RF5C296",
104110841Simp	"Ricoh RF5C396",
105110841Simp	"IBM clone",
106110841Simp	"IBM KING PCMCIA Controller"
107110841Simp};
108110841Simp#endif
109110841Simp
110110841Simpstatic exca_getb_fn exca_mem_getb;
111110841Simpstatic exca_putb_fn exca_mem_putb;
112110841Simpstatic exca_getb_fn exca_io_getb;
113110841Simpstatic exca_putb_fn exca_io_putb;
114110841Simp
11589948Simp/* memory */
11689948Simp
11789948Simp#define	EXCA_MEMINFO(NUM) {						\
11889948Simp	EXCA_SYSMEM_ADDR ## NUM ## _START_LSB,				\
11989948Simp	EXCA_SYSMEM_ADDR ## NUM ## _START_MSB,				\
12089948Simp	EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB,				\
12189948Simp	EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB,				\
12289948Simp	EXCA_SYSMEM_ADDR ## NUM ## _WIN,				\
12389948Simp	EXCA_CARDMEM_ADDR ## NUM ## _LSB,				\
12489948Simp	EXCA_CARDMEM_ADDR ## NUM ## _MSB,				\
12597708Salfred	EXCA_ADDRWIN_ENABLE_MEM ## NUM,					\
12689948Simp}
12789948Simp
12889948Simpstatic struct mem_map_index_st {
12989948Simp	int	sysmem_start_lsb;
13089948Simp	int	sysmem_start_msb;
13189948Simp	int	sysmem_stop_lsb;
13289948Simp	int	sysmem_stop_msb;
13389948Simp	int	sysmem_win;
13489948Simp	int	cardmem_lsb;
13589948Simp	int	cardmem_msb;
13689948Simp	int	memenable;
13789948Simp} mem_map_index[] = {
13889948Simp	EXCA_MEMINFO(0),
13989948Simp	EXCA_MEMINFO(1),
14089948Simp	EXCA_MEMINFO(2),
14189948Simp	EXCA_MEMINFO(3),
14289948Simp	EXCA_MEMINFO(4)
14389948Simp};
14489948Simp#undef	EXCA_MEMINFO
14589948Simp
146110841Simpstatic uint8_t
147110841Simpexca_mem_getb(struct exca_softc *sc, int reg)
148110841Simp{
149110841Simp	return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
150110841Simp}
151110841Simp
152110841Simpstatic void
153110841Simpexca_mem_putb(struct exca_softc *sc, int reg, uint8_t val)
154110841Simp{
155115461Sphk	bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val);
156110841Simp}
157110841Simp
158110841Simpstatic uint8_t
159110841Simpexca_io_getb(struct exca_softc *sc, int reg)
160110841Simp{
161110841Simp	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
162110841Simp	return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA));
163110841Simp}
164110841Simp
165110841Simpstatic void
166110841Simpexca_io_putb(struct exca_softc *sc, int reg, uint8_t val)
167110841Simp{
168110841Simp	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
169110841Simp	bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val);
170110841Simp}
171110841Simp
17289948Simp/*
17389948Simp * Helper function.  This will map the requested memory slot.  We setup the
17489948Simp * map before we call this function.  This is used to initially force the
17589948Simp * mapping, as well as later restore the mapping after it has been destroyed
17689948Simp * in some fashion (due to a power event typically).
17789948Simp */
17889948Simpstatic void
17989948Simpexca_do_mem_map(struct exca_softc *sc, int win)
18089948Simp{
18189948Simp	struct mem_map_index_st *map;
18289948Simp	struct pccard_mem_handle *mem;
183140022Simp	uint32_t offset;
18489948Simp
18589948Simp	map = &mem_map_index[win];
18689948Simp	mem = &sc->mem[win];
187140022Simp	offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) -
188140022Simp	  (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff;
189110841Simp	exca_putb(sc, map->sysmem_start_lsb,
19089948Simp	    (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
191110841Simp	exca_putb(sc, map->sysmem_start_msb,
19289948Simp	    ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
193119520Simp	    EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK));
19489948Simp
195110841Simp	exca_putb(sc, map->sysmem_stop_lsb,
19689948Simp	    ((mem->addr + mem->realsize - 1) >>
19789948Simp	    EXCA_SYSMEM_ADDRX_SHIFT) & 0xff);
198110841Simp	exca_putb(sc, map->sysmem_stop_msb,
19989948Simp	    (((mem->addr + mem->realsize - 1) >>
20089948Simp	    (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
201133782Simp	    EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
202133782Simp	    EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2);
20389948Simp
204110841Simp	exca_putb(sc, map->sysmem_win,
20589948Simp	    (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff);
20689948Simp
207140022Simp	exca_putb(sc, map->cardmem_lsb, offset & 0xff);
208140022Simp	exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) &
20989948Simp	    EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) |
210119551Simp	    ((mem->kind == PCCARD_A_MEM_ATTR) ?
21189948Simp	    EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0));
21289948Simp
213119520Simp#ifdef EXCA_DEBUG
214119551Simp	if (mem->kind == PCCARD_A_MEM_ATTR)
215119520Simp		printf("attribtue memory\n");
216119520Simp	else
217119520Simp		printf("common memory\n");
218119520Simp#endif
219133782Simp	exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable |
220133782Simp	    EXCA_ADDRWIN_ENABLE_MEMCS16);
22189948Simp
22289948Simp	DELAY(100);
22389948Simp#ifdef EXCA_DEBUG
22489948Simp	{
22589948Simp		int r1, r2, r3, r4, r5, r6, r7;
226110841Simp		r1 = exca_getb(sc, map->sysmem_start_msb);
227110841Simp		r2 = exca_getb(sc, map->sysmem_start_lsb);
228110841Simp		r3 = exca_getb(sc, map->sysmem_stop_msb);
229110841Simp		r4 = exca_getb(sc, map->sysmem_stop_lsb);
230110841Simp		r5 = exca_getb(sc, map->cardmem_msb);
231110841Simp		r6 = exca_getb(sc, map->cardmem_lsb);
232110841Simp		r7 = exca_getb(sc, map->sysmem_win);
233133782Simp		printf("exca_do_mem_map win %d: %02x%02x %02x%02x "
234133782Simp		    "%02x%02x %02x (%08x+%06x.%06x*%06x)\n",
23589948Simp		    win, r1, r2, r3, r4, r5, r6, r7,
23689948Simp		    mem->addr, mem->size, mem->realsize,
237119520Simp		    mem->cardaddr);
23889948Simp	}
23989948Simp#endif
24089948Simp}
24189948Simp
24289948Simp/*
24389948Simp * public interface to map a resource.  kind is the type of memory to
24489948Simp * map (either common or attribute).  Memory created via this interface
24589948Simp * starts out at card address 0.  Since the only way to set this is
24689948Simp * to set it on a struct resource after it has been mapped, we're safe
24789948Simp * in maping this assumption.  Note that resources can be remapped using
24889948Simp * exca_do_mem_map so that's how the card address can be set later.
24989948Simp */
25089948Simpint
25189948Simpexca_mem_map(struct exca_softc *sc, int kind, struct resource *res)
25289948Simp{
25389948Simp	int win;
25489948Simp
25589948Simp	for (win = 0; win < EXCA_MEM_WINS; win++) {
25689948Simp		if ((sc->memalloc & (1 << win)) == 0) {
25789948Simp			sc->memalloc |= (1 << win);
25889948Simp			break;
25989948Simp		}
26089948Simp	}
26189948Simp	if (win >= EXCA_MEM_WINS)
26289948Simp		return (1);
263120421Simp	if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 &&
264100703Simp	    (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) {
265100703Simp		device_printf(sc->dev, "Does not support mapping above 24M.");
266100703Simp		return (1);
267100703Simp	}
26889948Simp
26989948Simp	sc->mem[win].cardaddr = 0;
27089948Simp	sc->mem[win].memt = rman_get_bustag(res);
27189948Simp	sc->mem[win].memh = rman_get_bushandle(res);
27289948Simp	sc->mem[win].addr = rman_get_start(res);
27389948Simp	sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1;
27489948Simp	sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1;
27589948Simp	sc->mem[win].realsize = sc->mem[win].realsize -
27689948Simp	    (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
27789948Simp	sc->mem[win].kind = kind;
278119520Simp	DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n",
279119520Simp	    win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr);
28089948Simp	exca_do_mem_map(sc, win);
28189948Simp
28289948Simp	return (0);
28389948Simp}
28489948Simp
28589948Simp/*
28689948Simp * Private helper function.  This turns off a given memory map that is in
28789948Simp * use.  We do this by just clearing the enable bit in the pcic.  If we needed
28889948Simp * to make memory unmapping/mapping pairs faster, we would have to store
28989948Simp * more state information about the pcic and then use that to intelligently
29089948Simp * to the map/unmap.  However, since we don't do that sort of thing often
29189948Simp * (generally just at configure time), it isn't a case worth optimizing.
29289948Simp */
29389948Simpstatic void
29489948Simpexca_mem_unmap(struct exca_softc *sc, int window)
29589948Simp{
29689948Simp	if (window < 0 || window >= EXCA_MEM_WINS)
29789948Simp		panic("exca_mem_unmap: window out of range");
29889948Simp
29989948Simp	exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable);
30089948Simp	sc->memalloc &= ~(1 << window);
30189948Simp}
30289948Simp
30389948Simp/*
30489948Simp * Find the map that we're using to hold the resoruce.  This works well
30589948Simp * so long as the client drivers don't do silly things like map the same
30689948Simp * area mutliple times, or map both common and attribute memory at the
30789948Simp * same time.  This latter restriction is a bug.  We likely should just
30889948Simp * store a pointer to the res in the mem[x] data structure.
30989948Simp */
31089948Simpstatic int
31189948Simpexca_mem_findmap(struct exca_softc *sc, struct resource *res)
31289948Simp{
31389948Simp	int win;
31489948Simp
31589948Simp	for (win = 0; win < EXCA_MEM_WINS; win++) {
31689948Simp		if (sc->mem[win].memt == rman_get_bustag(res) &&
31789948Simp		    sc->mem[win].addr == rman_get_start(res) &&
31889948Simp		    sc->mem[win].size == rman_get_size(res))
31989948Simp			return (win);
32089948Simp	}
32189948Simp	return (-1);
32289948Simp}
32389948Simp
32489948Simp/*
32589948Simp * Set the memory flag.  This means that we are setting if the memory
32689948Simp * is coming from attribute memory or from common memory on the card.
32789948Simp * CIS entries are generally in attribute memory (although they can
32889948Simp * reside in common memory).  Generally, this is the only use for attribute
32989948Simp * memory.  However, some cards require their drivers to dance in both
33089948Simp * common and/or attribute memory and this interface (and setting the
33189948Simp * offset interface) exist for such cards.
33289948Simp */
33389948Simpint
33489948Simpexca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags)
33589948Simp{
33689948Simp	int win;
33789948Simp
33889948Simp	win = exca_mem_findmap(sc, res);
33989948Simp	if (win < 0) {
34089948Simp		device_printf(sc->dev,
34189948Simp		    "set_res_flags: specified resource not active\n");
34289948Simp		return (ENOENT);
34389948Simp	}
34489948Simp
34589948Simp	sc->mem[win].kind = flags;
34689948Simp	exca_do_mem_map(sc, win);
34789948Simp	return (0);
34889948Simp}
34989948Simp
35089948Simp/*
35189948Simp * Given a resource, go ahead and unmap it if we can find it in the
35289948Simp * resrouce list that's used.
35389948Simp */
35489948Simpint
35589948Simpexca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
35689948Simp{
35789948Simp	int win;
35889948Simp
35989948Simp	win = exca_mem_findmap(sc, res);
36089948Simp	if (win < 0)
36189948Simp		return (ENOENT);
36289948Simp	exca_mem_unmap(sc, win);
36389948Simp	return (0);
36489948Simp}
36589948Simp
36689948Simp/*
36789948Simp * Set the offset of the memory.  We use this for reading the CIS and
36889948Simp * frobbing the pccard's pccard registers (POR, etc).  Some drivers
36989948Simp * need to access this functionality as well, since they have receive
370119520Simp * buffers defined in the attribute memory.
37189948Simp */
37289948Simpint
37389948Simpexca_mem_set_offset(struct exca_softc *sc, struct resource *res,
37489948Simp    uint32_t cardaddr, uint32_t *deltap)
37589948Simp{
37689948Simp	int win;
37789948Simp	uint32_t delta;
37889948Simp
37989948Simp	win = exca_mem_findmap(sc, res);
38089948Simp	if (win < 0) {
38189948Simp		device_printf(sc->dev,
38289948Simp		    "set_memory_offset: specified resource not active\n");
38389948Simp		return (ENOENT);
38489948Simp	}
385119520Simp	sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1);
38689948Simp	delta = cardaddr % EXCA_MEM_PAGESIZE;
38789948Simp	if (deltap)
38889948Simp		*deltap = delta;
38989948Simp	sc->mem[win].realsize = sc->mem[win].size + delta +
39089948Simp	    EXCA_MEM_PAGESIZE - 1;
39189948Simp	sc->mem[win].realsize = sc->mem[win].realsize -
39289948Simp	    (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
39389948Simp	exca_do_mem_map(sc, win);
39489948Simp	return (0);
39589948Simp}
39689948Simp
39789948Simp
39889948Simp/* I/O */
39989948Simp
40089948Simp#define	EXCA_IOINFO(NUM) {						\
40189948Simp	EXCA_IOADDR ## NUM ## _START_LSB,				\
40289948Simp	EXCA_IOADDR ## NUM ## _START_MSB,				\
40389948Simp	EXCA_IOADDR ## NUM ## _STOP_LSB,				\
40489948Simp	EXCA_IOADDR ## NUM ## _STOP_MSB,				\
40597708Salfred	EXCA_ADDRWIN_ENABLE_IO ## NUM,					\
40689948Simp	EXCA_IOCTL_IO ## NUM ## _WAITSTATE				\
40789948Simp	| EXCA_IOCTL_IO ## NUM ## _ZEROWAIT				\
40889948Simp	| EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK			\
40989948Simp	| EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK,			\
41089948Simp	{								\
41189948Simp		EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD,		\
41289948Simp		EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE		\
41389948Simp		| EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT,		\
41489948Simp		EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE		\
41589948Simp		| EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT,		\
41689948Simp	}								\
41789948Simp}
41889948Simp
41989948Simpstatic struct io_map_index_st {
42089948Simp	int	start_lsb;
42189948Simp	int	start_msb;
42289948Simp	int	stop_lsb;
42389948Simp	int	stop_msb;
42489948Simp	int	ioenable;
42589948Simp	int	ioctlmask;
42689948Simp	int	ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */
42789948Simp} io_map_index[] = {
42889948Simp	EXCA_IOINFO(0),
42989948Simp	EXCA_IOINFO(1),
43089948Simp};
43189948Simp#undef	EXCA_IOINFO
43289948Simp
43389948Simpstatic void
43489948Simpexca_do_io_map(struct exca_softc *sc, int win)
43589948Simp{
43689948Simp	struct io_map_index_st *map;
43789948Simp
43889948Simp	struct pccard_io_handle *io;
43989948Simp
44089948Simp	map = &io_map_index[win];
44189948Simp	io = &sc->io[win];
442110841Simp	exca_putb(sc, map->start_lsb, io->addr & 0xff);
443110841Simp	exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff);
44489948Simp
445110841Simp	exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff);
446110841Simp	exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff);
44789948Simp
44889948Simp	exca_clrb(sc, EXCA_IOCTL, map->ioctlmask);
44989948Simp	exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]);
45089948Simp
45189948Simp	exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable);
45289948Simp#ifdef EXCA_DEBUG
45389948Simp	{
45489948Simp		int r1, r2, r3, r4;
455110841Simp		r1 = exca_getb(sc, map->start_msb);
456110841Simp		r2 = exca_getb(sc, map->start_lsb);
457110841Simp		r3 = exca_getb(sc, map->stop_msb);
458110841Simp		r4 = exca_getb(sc, map->stop_lsb);
45989948Simp		DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x "
46089948Simp		    "(%08x+%08x)\n", win, r1, r2, r3, r4,
46189948Simp		    io->addr, io->size);
46289948Simp	}
46389948Simp#endif
46489948Simp}
46589948Simp
46689948Simpint
46789948Simpexca_io_map(struct exca_softc *sc, int width, struct resource *r)
46889948Simp{
46989948Simp	int win;
47089948Simp#ifdef EXCA_DEBUG
47189948Simp	static char *width_names[] = { "auto", "io8", "io16"};
47289948Simp#endif
47389948Simp	for (win=0; win < EXCA_IO_WINS; win++) {
47489948Simp		if ((sc->ioalloc & (1 << win)) == 0) {
47589948Simp			sc->ioalloc |= (1 << win);
47689948Simp			break;
47789948Simp		}
47889948Simp	}
47989948Simp	if (win >= EXCA_IO_WINS)
48089948Simp		return (1);
48189948Simp
48289948Simp	sc->io[win].iot = rman_get_bustag(r);
48389948Simp	sc->io[win].ioh = rman_get_bushandle(r);
48489948Simp	sc->io[win].addr = rman_get_start(r);
48589948Simp	sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1;
48689948Simp	sc->io[win].flags = 0;
48789948Simp	sc->io[win].width = width;
48889948Simp	DPRINTF("exca_io_map window %d %s port %x+%x\n",
48989948Simp	    win, width_names[width], sc->io[win].addr,
49089948Simp	    sc->io[win].size);
49189948Simp	exca_do_io_map(sc, win);
49289948Simp
49389948Simp	return (0);
49489948Simp}
49589948Simp
49689948Simpstatic void
49789948Simpexca_io_unmap(struct exca_softc *sc, int window)
49889948Simp{
49989948Simp	if (window >= EXCA_IO_WINS)
50089948Simp		panic("exca_io_unmap: window out of range");
50189948Simp
50289948Simp	exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable);
50389948Simp
50489948Simp	sc->ioalloc &= ~(1 << window);
50589948Simp
50689948Simp	sc->io[window].iot = 0;
50789948Simp	sc->io[window].ioh = 0;
50889948Simp	sc->io[window].addr = 0;
50989948Simp	sc->io[window].size = 0;
51089948Simp	sc->io[window].flags = 0;
51189948Simp	sc->io[window].width = 0;
51289948Simp}
51389948Simp
51489948Simpstatic int
51589948Simpexca_io_findmap(struct exca_softc *sc, struct resource *res)
51689948Simp{
51789948Simp	int win;
51889948Simp
51989948Simp	for (win = 0; win < EXCA_IO_WINS; win++) {
52089948Simp		if (sc->io[win].iot == rman_get_bustag(res) &&
52189948Simp		    sc->io[win].addr == rman_get_start(res) &&
52289948Simp		    sc->io[win].size == rman_get_size(res))
52389948Simp			return (win);
52489948Simp	}
52589948Simp	return (-1);
52689948Simp}
52789948Simp
52889948Simp
52989948Simpint
53089948Simpexca_io_unmap_res(struct exca_softc *sc, struct resource *res)
53189948Simp{
53289948Simp	int win;
53389948Simp
53489948Simp	win = exca_io_findmap(sc, res);
53589948Simp	if (win < 0)
53689948Simp		return (ENOENT);
53789948Simp	exca_io_unmap(sc, win);
53889948Simp	return (0);
53989948Simp}
54089948Simp
54189948Simp/* Misc */
54289948Simp
54389948Simp/*
54489948Simp * If interrupts are enabled, then we should be able to just wait for
54589948Simp * an interrupt routine to wake us up.  Busy waiting shouldn't be
54689948Simp * necessary.  Sadly, not all legacy ISA cards support an interrupt
54789948Simp * for the busy state transitions, at least according to their datasheets,
54889948Simp * so we busy wait a while here..
54989948Simp */
55089948Simpstatic void
55189948Simpexca_wait_ready(struct exca_softc *sc)
55289948Simp{
55389948Simp	int i;
55489948Simp	DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n",
555110841Simp	    exca_getb(sc, EXCA_IF_STATUS));
55689948Simp	for (i = 0; i < 10000; i++) {
557110841Simp		if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY)
55889948Simp			return;
55989948Simp		DELAY(500);
56089948Simp	}
56189948Simp	device_printf(sc->dev, "ready never happened, status = %02x\n",
562110841Simp	    exca_getb(sc, EXCA_IF_STATUS));
56389948Simp}
56489948Simp
56589948Simp/*
56689948Simp * Reset the card.  Ideally, we'd do a lot of this via interrupts.
56789948Simp * However, many PC Cards will deassert the ready signal.  This means
56889948Simp * that they are asserting an interrupt.  This makes it hard to
56989948Simp * do anything but a busy wait here.  One could argue that these
57089948Simp * such cards are broken, or that the bridge that allows this sort
57189948Simp * of interrupt through isn't quite what you'd want (and may be a standards
572150460Simp * violation).  However, such arguing would leave a huge class of PC Cards
573104601Simp * and bridges out of reach for use in the system.
574104601Simp *
575104601Simp * Maybe I should reevaluate the above based on the power bug I fixed
576104601Simp * in OLDCARD.
57789948Simp */
57889948Simpvoid
57989948Simpexca_reset(struct exca_softc *sc, device_t child)
58089948Simp{
58189948Simp	int win;
58289948Simp
58389948Simp	/* enable socket i/o */
58489948Simp	exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE);
58589948Simp
586110841Simp	exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE);
58789948Simp	/* hold reset for 30ms */
58889948Simp	DELAY(30*1000);
58989948Simp	/* clear the reset flag */
59089948Simp	exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET);
591150460Simp	/* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */
59289948Simp	DELAY(20*1000);
59389948Simp
59489948Simp	exca_wait_ready(sc);
59589948Simp
59689948Simp	/* disable all address windows */
597110841Simp	exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0);
59889948Simp
599120872Simp	exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO);
600120872Simp	DEVPRINTF(sc->dev, "card type is io\n");
60189948Simp
60289948Simp	/* reinstall all the memory and io mappings */
60389948Simp	for (win = 0; win < EXCA_MEM_WINS; ++win)
60489948Simp		if (sc->memalloc & (1 << win))
60589948Simp			exca_do_mem_map(sc, win);
60689948Simp	for (win = 0; win < EXCA_IO_WINS; ++win)
60789948Simp		if (sc->ioalloc & (1 << win))
60889948Simp			exca_do_io_map(sc, win);
60989948Simp}
61089948Simp
61189948Simp/*
61289948Simp * Initialize the exca_softc data structure for the first time.
61389948Simp */
61489948Simpvoid
615100703Simpexca_init(struct exca_softc *sc, device_t dev,
616100703Simp    bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset)
61789948Simp{
61889948Simp	sc->dev = dev;
61989948Simp	sc->memalloc = 0;
62089948Simp	sc->ioalloc = 0;
62189948Simp	sc->bst = bst;
62289948Simp	sc->bsh = bsh;
62389948Simp	sc->offset = offset;
62489948Simp	sc->flags = 0;
625110841Simp	sc->getb = exca_mem_getb;
626110841Simp	sc->putb = exca_mem_putb;
62789948Simp}
62889948Simp
62989948Simp/*
630110841Simp * Is this socket valid?
631110841Simp */
632110841Simpstatic int
633110841Simpexca_valid_slot(struct exca_softc *exca)
634110841Simp{
635110841Simp	uint8_t c;
636110841Simp
637115988Simp	/* Assume the worst */
638115988Simp	exca->chipset = EXCA_BOGUS;
639115988Simp
640110841Simp	/*
641110841Simp	 * see if there's a PCMCIA controller here
642110841Simp	 * Intel PCMCIA controllers use 0x82 and 0x83
643110841Simp	 * IBM clone chips use 0x88 and 0x89, apparently
644110841Simp	 */
645110841Simp	c = exca_getb(exca, EXCA_IDENT);
646110841Simp	if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO)
647110841Simp		return (0);
648110841Simp	if ((c & EXCA_IDENT_ZERO) != 0)
649110841Simp		return (0);
650110841Simp	switch (c & EXCA_IDENT_REV_MASK) {
651110841Simp	/*
652110841Simp	 *	82365 or clones.
653110841Simp	 */
654110841Simp	case EXCA_IDENT_REV_I82365SLR0:
655110841Simp	case EXCA_IDENT_REV_I82365SLR1:
656110841Simp		exca->chipset = EXCA_I82365;
657110841Simp		/*
658110841Simp		 * Check for Vadem chips by unlocking their extra
659110841Simp		 * registers and looking for valid ID.  Bit 3 in
660110841Simp		 * the ID register is normally 0, except when
661110841Simp		 * EXCA_VADEMREV is set.  Other bridges appear
662110841Simp		 * to ignore this frobbing.
663110841Simp		 */
664110841Simp		bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
665110841Simp		    EXCA_VADEM_COOKIE1);
666110841Simp		bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
667110841Simp		    EXCA_VADEM_COOKIE2);
668110841Simp		exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
669110841Simp		c = exca_getb(exca, EXCA_IDENT);
670110841Simp		if (c & 0x08) {
671110841Simp			switch (c & 7) {
672110841Simp			case 1:
673110841Simp				exca->chipset = EXCA_VG365;
674110841Simp				break;
675110841Simp			case 2:
676110841Simp				exca->chipset = EXCA_VG465;
677110841Simp				break;
678110841Simp			case 3:
679110841Simp				exca->chipset = EXCA_VG468;
680110841Simp				break;
681110841Simp			default:
682110841Simp				exca->chipset = EXCA_VG469;
683110841Simp				break;
684110841Simp			}
685110841Simp			exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
686110841Simp			break;
687110841Simp		}
688110841Simp		/*
689110841Simp		 * Check for RICOH RF5C[23]96 PCMCIA Controller
690110841Simp		 */
691110841Simp		c = exca_getb(exca, EXCA_RICOH_ID);
692110841Simp		if (c == EXCA_RID_396) {
693110841Simp			exca->chipset = EXCA_RF5C396;
694110841Simp			break;
695110841Simp		} else if (c == EXCA_RID_296) {
696110841Simp			exca->chipset = EXCA_RF5C296;
697110841Simp			break;
698110841Simp		}
699110841Simp		/*
700110841Simp		 *	Check for Cirrus logic chips.
701110841Simp		 */
702110841Simp		exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0);
703110841Simp		c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
704110841Simp		if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) ==
705110841Simp		    EXCA_CIRRUS_CHIP_INFO_CHIP_ID) {
706110841Simp			c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
707110841Simp			if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
708110841Simp				if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS)
709110841Simp					exca->chipset = EXCA_PD6722;
710110841Simp				else
711110841Simp					exca->chipset = EXCA_PD6710;
712110841Simp				break;
713110841Simp			}
714110841Simp		}
715110841Simp		break;
716110841Simp
717110841Simp	case EXCA_IDENT_REV_I82365SLDF:
718110841Simp		/*
719110841Simp		 *	Intel i82365sl-DF step or maybe a vlsi 82c146
720110841Simp		 * we detected the vlsi case earlier, so if the controller
721110841Simp		 * isn't set, we know it is a i82365sl step D.
722110841Simp		 */
723110841Simp		exca->chipset = EXCA_I82365SL_DF;
724110841Simp		break;
725110841Simp	case EXCA_IDENT_REV_IBM1:
726110841Simp	case EXCA_IDENT_REV_IBM2:
727110841Simp		exca->chipset = EXCA_IBM;
728110841Simp		break;
729110841Simp	case EXCA_IDENT_REV_IBM_KING:
730110841Simp		exca->chipset = EXCA_IBM_KING;
731110841Simp		break;
732110841Simp	default:
733110841Simp		return (0);
734110841Simp	}
735110841Simp	return (1);
736110841Simp}
737110841Simp
738110841Simp/*
73989948Simp * Probe the expected slots.  We maybe should set the ID for each of these
74089948Simp * slots too while we're at it.  But maybe that belongs to a separate
74189948Simp * function.
74289948Simp *
743110841Simp * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
74489948Simp */
74589948Simpint
746110841Simpexca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
747110841Simp    bus_space_handle_t ioh)
74889948Simp{
74989948Simp	int err;
75089948Simp	int i;
75189948Simp
75289948Simp	err = ENXIO;
753110841Simp	for (i = 0; i < EXCA_NSLOTS; i++)  {
754100703Simp		exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE);
755110841Simp		exca->getb = exca_io_getb;
756110841Simp		exca->putb = exca_io_putb;
757110841Simp		if (exca_valid_slot(&exca[i]))
75889948Simp			err = 0;
75989948Simp	}
76089948Simp	return (err);
76189948Simp}
76289948Simp
763115988Simpvoid
764115988Simpexca_insert(struct exca_softc *exca)
765115988Simp{
766115988Simp	if (exca->pccarddev != NULL) {
767115988Simp		if (CARD_ATTACH_CARD(exca->pccarddev) != 0)
768115988Simp			device_printf(exca->dev,
769115988Simp			    "PC Card card activation failed\n");
770115988Simp	} else {
771115988Simp		device_printf(exca->dev,
772115988Simp		    "PC Card inserted, but no pccard bus.\n");
773115988Simp	}
774115988Simp}
775115988Simp
776115988Simp
777115988Simpvoid
778115988Simpexca_removal(struct exca_softc *exca)
779115988Simp{
780115988Simp	if (exca->pccarddev != NULL)
781115988Simp		CARD_DETACH_CARD(exca->pccarddev);
782115988Simp}
783115988Simp
784115988Simpint
785115988Simpexca_activate_resource(struct exca_softc *exca, device_t child, int type,
786115988Simp    int rid, struct resource *res)
787115988Simp{
788115988Simp	int err;
789115988Simp	if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */
790115988Simp		switch (type) {
791115988Simp		case SYS_RES_IOPORT:
792119551Simp			err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res);
793115988Simp			break;
794115988Simp		case SYS_RES_MEMORY:
795119551Simp			err = exca_mem_map(exca, PCCARD_A_MEM_COM, res);
796115988Simp			break;
797115988Simp		default:
798115988Simp			err = 0;
799115988Simp			break;
800115988Simp		}
801115988Simp		if (err)
802115988Simp			return (err);
803115988Simp
804115988Simp	}
805115988Simp	return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
806115988Simp		  type, rid, res));
807115988Simp}
808115988Simp
809115988Simpint
810115988Simpexca_deactivate_resource(struct exca_softc *exca, device_t child, int type,
811115988Simp    int rid, struct resource *res)
812115988Simp{
813115988Simp	if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */
814115988Simp		switch (type) {
815115988Simp		case SYS_RES_IOPORT:
816115988Simp			if (exca_io_unmap_res(exca, res))
817115988Simp				return (ENOENT);
818115988Simp			break;
819115988Simp		case SYS_RES_MEMORY:
820115988Simp			if (exca_mem_unmap_res(exca, res))
821115988Simp				return (ENOENT);
822115988Simp			break;
823115988Simp		}
824115988Simp	}
825115988Simp	return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
826115988Simp	    type, rid, res));
827115988Simp}
828115988Simp
829133782Simp#if 0
830133782Simpstatic struct resource *
831133782Simpexca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid,
832133782Simp    u_long start, u_long end, u_long count, uint flags)
833133782Simp{
834133782Simp	struct resource *res = NULL;
835133782Simp	int tmp;
836133782Simp
837133782Simp	switch (type) {
838133782Simp	case SYS_RES_MEMORY:
839133782Simp		if (start < cbb_start_mem)
840133782Simp			start = cbb_start_mem;
841133782Simp		if (end < start)
842133782Simp			end = start;
843133782Simp		flags = (flags & ~RF_ALIGNMENT_MASK) |
844133782Simp		    rman_make_alignment_flags(CBB_MEMALIGN);
845133782Simp		break;
846133782Simp	case SYS_RES_IOPORT:
847133782Simp		if (start < cbb_start_16_io)
848133782Simp			start = cbb_start_16_io;
849133782Simp		if (end < start)
850133782Simp			end = start;
851133782Simp		break;
852133782Simp	case SYS_RES_IRQ:
853133782Simp		tmp = rman_get_start(sc->irq_res);
854133782Simp		if (start > tmp || end < tmp || count != 1) {
855133782Simp			device_printf(child, "requested interrupt %ld-%ld,"
856133782Simp			    "count = %ld not supported by cbb\n",
857133782Simp			    start, end, count);
858133782Simp			return (NULL);
859133782Simp		}
860133782Simp		flags |= RF_SHAREABLE;
861133782Simp		start = end = rman_get_start(sc->irq_res);
862133782Simp		break;
863133782Simp	}
864133782Simp	res = BUS_ALLOC_RESOURCE(up, child, type, rid,
865133782Simp	    start, end, count, flags & ~RF_ACTIVE);
866133782Simp	if (res == NULL)
867133782Simp		return (NULL);
868133782Simp	cbb_insert_res(sc, res, type, *rid);
869133782Simp	if (flags & RF_ACTIVE) {
870133782Simp		if (bus_activate_resource(child, type, *rid, res) != 0) {
871133782Simp			bus_release_resource(child, type, *rid, res);
872133782Simp			return (NULL);
873133782Simp		}
874133782Simp	}
875133782Simp
876133782Simp	return (res);
877133782Simp}
878133782Simp
879110841Simpstatic int
880133782Simpexca_release_resource(struct exca_softc *sc, device_t child, int type,
881133782Simp    int rid, struct resource *res)
882133782Simp{
883133782Simp	int error;
884133782Simp
885133782Simp	if (rman_get_flags(res) & RF_ACTIVE) {
886133782Simp		error = bus_deactivate_resource(child, type, rid, res);
887133782Simp		if (error != 0)
888133782Simp			return (error);
889133782Simp	}
890133782Simp	cbb_remove_res(sc, res);
891133782Simp	return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
892133782Simp	    type, rid, res));
893133782Simp}
894133782Simp#endif
895133782Simp
896133782Simpstatic int
897110841Simpexca_modevent(module_t mod, int cmd, void *arg)
89889948Simp{
899110841Simp	return 0;
90089948Simp}
90197613Stakawata
90297613StakawataDEV_MODULE(exca, exca_modevent, NULL);
90397613StakawataMODULE_VERSION(exca, 1);
904