FreeBSD/Linux Kernel Cross Reference
sys/dev/exca/exca.c
1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2002-2005 M. Warner Losh <imp@FreeBSD.org>
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
91 static 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
110 static exca_getb_fn exca_mem_getb;
111 static exca_putb_fn exca_mem_putb;
112 static exca_getb_fn exca_io_getb;
113 static 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
128 static 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
146 static uint8_t
147 exca_mem_getb(struct exca_softc *sc, int reg)
148 {
149 return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
150 }
151
152 static void
153 exca_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
158 static uint8_t
159 exca_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
165 static void
166 exca_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 */
178 static void
179 exca_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 */
248 int
249 exca_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 */
301 static void
302 exca_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 */
318 static int
319 exca_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 */
341 int
342 exca_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 */
376 int
377 exca_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 */
394 int
395 exca_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
441 static 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
455 static void
456 exca_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
488 int
489 exca_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
518 static void
519 exca_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
536 static int
537 exca_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
551 int
552 exca_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 */
572 static void
573 exca_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 */
600 void
601 exca_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 */
636 void
637 exca_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 sc->pccarddev = device_add_child(dev, "pccard", -1);
650 if (sc->pccarddev == NULL)
651 DEVPRINTF(brdev, "WARNING: cannot add pccard bus.\n");
652 else if (device_probe_and_attach(sc->pccarddev) != 0)
653 DEVPRINTF(brdev, "WARNING: cannot attach pccard bus.\n");
654 }
655
656 /*
657 * Is this socket valid?
658 */
659 static int
660 exca_valid_slot(struct exca_softc *exca)
661 {
662 uint8_t c;
663
664 /* Assume the worst */
665 exca->chipset = EXCA_BOGUS;
666
667 /*
668 * see if there's a PCMCIA controller here
669 * Intel PCMCIA controllers use 0x82 and 0x83
670 * IBM clone chips use 0x88 and 0x89, apparently
671 */
672 c = exca_getb(exca, EXCA_IDENT);
673 DEVPRINTF(exca->dev, "Ident is %x\n", c);
674 if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO)
675 return (0);
676 if ((c & EXCA_IDENT_ZERO) != 0)
677 return (0);
678 switch (c & EXCA_IDENT_REV_MASK) {
679 /*
680 * 82365 or clones.
681 */
682 case EXCA_IDENT_REV_I82365SLR0:
683 case EXCA_IDENT_REV_I82365SLR1:
684 exca->chipset = EXCA_I82365;
685 /*
686 * Check for Vadem chips by unlocking their extra
687 * registers and looking for valid ID. Bit 3 in
688 * the ID register is normally 0, except when
689 * EXCA_VADEMREV is set. Other bridges appear
690 * to ignore this frobbing.
691 */
692 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
693 EXCA_VADEM_COOKIE1);
694 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
695 EXCA_VADEM_COOKIE2);
696 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
697 c = exca_getb(exca, EXCA_IDENT);
698 if (c & 0x08) {
699 switch (c & 7) {
700 case 1:
701 exca->chipset = EXCA_VG365;
702 break;
703 case 2:
704 exca->chipset = EXCA_VG465;
705 break;
706 case 3:
707 exca->chipset = EXCA_VG468;
708 break;
709 default:
710 exca->chipset = EXCA_VG469;
711 break;
712 }
713 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
714 break;
715 }
716 /*
717 * Check for RICOH RF5C[23]96 PCMCIA Controller
718 */
719 c = exca_getb(exca, EXCA_RICOH_ID);
720 if (c == EXCA_RID_396) {
721 exca->chipset = EXCA_RF5C396;
722 break;
723 } else if (c == EXCA_RID_296) {
724 exca->chipset = EXCA_RF5C296;
725 break;
726 }
727 /*
728 * Check for Cirrus logic chips.
729 */
730 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0);
731 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
732 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) ==
733 EXCA_CIRRUS_CHIP_INFO_CHIP_ID) {
734 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
735 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
736 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS)
737 exca->chipset = EXCA_PD6722;
738 else
739 exca->chipset = EXCA_PD6710;
740 break;
741 }
742 }
743 break;
744
745 case EXCA_IDENT_REV_I82365SLDF:
746 /*
747 * Intel i82365sl-DF step or maybe a vlsi 82c146
748 * we detected the vlsi case earlier, so if the controller
749 * isn't set, we know it is a i82365sl step D.
750 * XXXX Except we didn't -- this is a regression but VLSI
751 * controllers are super hard to find these days for testing.
752 */
753 exca->chipset = EXCA_I82365SL_DF;
754 break;
755 case EXCA_IDENT_REV_IBM1:
756 case EXCA_IDENT_REV_IBM2:
757 exca->chipset = EXCA_IBM;
758 break;
759 case EXCA_IDENT_REV_IBM_KING:
760 exca->chipset = EXCA_IBM_KING;
761 break;
762 default:
763 return (0);
764 }
765 return (1);
766 }
767
768 /*
769 * Probe the expected slots. We maybe should set the ID for each of these
770 * slots too while we're at it. But maybe that belongs to a separate
771 * function.
772 *
773 * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
774 */
775 int
776 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
777 bus_space_handle_t ioh)
778 {
779 int err;
780 int i;
781
782 err = ENXIO;
783 for (i = 0; i < EXCA_NSLOTS; i++) {
784 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE);
785 exca->getb = exca_io_getb;
786 exca->putb = exca_io_putb;
787 if (exca_valid_slot(&exca[i])) {
788 device_set_desc(dev, chip_names[exca[i].chipset]);
789 err = 0;
790 }
791 }
792 return (err);
793 }
794
795 void
796 exca_insert(struct exca_softc *exca)
797 {
798 if (device_is_attached(exca->pccarddev)) {
799 if (CARD_ATTACH_CARD(exca->pccarddev) != 0)
800 device_printf(exca->dev,
801 "PC Card card activation failed\n");
802 } else {
803 device_printf(exca->dev,
804 "PC Card inserted, but no pccard bus.\n");
805 }
806 }
807
808
809 void
810 exca_removal(struct exca_softc *exca)
811 {
812 if (device_is_attached(exca->pccarddev))
813 CARD_DETACH_CARD(exca->pccarddev);
814 }
815
816 int
817 exca_activate_resource(struct exca_softc *exca, device_t child, int type,
818 int rid, struct resource *res)
819 {
820 int err;
821
822 if (rman_get_flags(res) & RF_ACTIVE)
823 return (0);
824 err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
825 type, rid, res);
826 if (err)
827 return (err);
828 switch (type) {
829 case SYS_RES_IOPORT:
830 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res);
831 break;
832 case SYS_RES_MEMORY:
833 err = exca_mem_map(exca, 0, res);
834 break;
835 }
836 if (err)
837 BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
838 type, rid, res);
839 return (err);
840 }
841
842 int
843 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type,
844 int rid, struct resource *res)
845 {
846 if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */
847 switch (type) {
848 case SYS_RES_IOPORT:
849 if (exca_io_unmap_res(exca, res))
850 return (ENOENT);
851 break;
852 case SYS_RES_MEMORY:
853 if (exca_mem_unmap_res(exca, res))
854 return (ENOENT);
855 break;
856 }
857 }
858 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
859 type, rid, res));
860 }
861
862 #if 0
863 static struct resource *
864 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid,
865 u_long start, u_long end, u_long count, uint flags)
866 {
867 struct resource *res = NULL;
868 int tmp;
869
870 switch (type) {
871 case SYS_RES_MEMORY:
872 if (start < cbb_start_mem)
873 start = cbb_start_mem;
874 if (end < start)
875 end = start;
876 flags = (flags & ~RF_ALIGNMENT_MASK) |
877 rman_make_alignment_flags(CBB_MEMALIGN);
878 break;
879 case SYS_RES_IOPORT:
880 if (start < cbb_start_16_io)
881 start = cbb_start_16_io;
882 if (end < start)
883 end = start;
884 break;
885 case SYS_RES_IRQ:
886 tmp = rman_get_start(sc->irq_res);
887 if (start > tmp || end < tmp || count != 1) {
888 device_printf(child, "requested interrupt %ld-%ld,"
889 "count = %ld not supported by cbb\n",
890 start, end, count);
891 return (NULL);
892 }
893 flags |= RF_SHAREABLE;
894 start = end = rman_get_start(sc->irq_res);
895 break;
896 }
897 res = BUS_ALLOC_RESOURCE(up, child, type, rid,
898 start, end, count, flags & ~RF_ACTIVE);
899 if (res == NULL)
900 return (NULL);
901 cbb_insert_res(sc, res, type, *rid);
902 if (flags & RF_ACTIVE) {
903 if (bus_activate_resource(child, type, *rid, res) != 0) {
904 bus_release_resource(child, type, *rid, res);
905 return (NULL);
906 }
907 }
908
909 return (res);
910 }
911
912 static int
913 exca_release_resource(struct exca_softc *sc, device_t child, int type,
914 int rid, struct resource *res)
915 {
916 int error;
917
918 if (rman_get_flags(res) & RF_ACTIVE) {
919 error = bus_deactivate_resource(child, type, rid, res);
920 if (error != 0)
921 return (error);
922 }
923 cbb_remove_res(sc, res);
924 return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
925 type, rid, res));
926 }
927 #endif
928
929 static int
930 exca_modevent(module_t mod, int cmd, void *arg)
931 {
932 return 0;
933 }
934
935 DEV_MODULE(exca, exca_modevent, NULL);
936 MODULE_VERSION(exca, 1);
Cache object: 48e95d97af159590a1072117a0ae811b
|