xref: /freebsd/sys/dev/exca/exca.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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$");
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 
89 static 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 
108 static exca_getb_fn exca_mem_getb;
109 static exca_putb_fn exca_mem_putb;
110 static exca_getb_fn exca_io_getb;
111 static 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 
126 static 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 
144 static uint8_t
145 exca_mem_getb(struct exca_softc *sc, int reg)
146 {
147 	return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
148 }
149 
150 static void
151 exca_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 
156 static uint8_t
157 exca_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 
163 static void
164 exca_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  */
176 static void
177 exca_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  */
250 int
251 exca_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  */
293 static void
294 exca_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  */
310 static int
311 exca_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  */
333 int
334 exca_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  */
354 int
355 exca_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  */
372 int
373 exca_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 
419 static 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 
433 static void
434 exca_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 
466 int
467 exca_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 
496 static void
497 exca_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 
514 static int
515 exca_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 
529 int
530 exca_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  */
550 static void
551 exca_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  */
578 void
579 exca_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  */
614 void
615 exca_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  */
632 static int
633 exca_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  */
746 int
747 exca_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 
766 void
767 exca_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 
780 void
781 exca_removal(struct exca_softc *exca)
782 {
783 	if (device_is_attached(exca->pccarddev))
784 		CARD_DETACH_CARD(exca->pccarddev);
785 }
786 
787 int
788 exca_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 
813 int
814 exca_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
834 static struct resource *
835 exca_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 
883 static int
884 exca_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 
900 static int
901 exca_modevent(module_t mod, int cmd, void *arg)
902 {
903 	return 0;
904 }
905 
906 DEV_MODULE(exca, exca_modevent, NULL);
907 MODULE_VERSION(exca, 1);
908