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