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