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