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