Annotation of sys/arch/sparc/dev/ts102.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ts102.c,v 1.18 2006/08/11 18:57:35 miod Exp $ */
2: /*
3: * Copyright (c) 2003, 2004, Miodrag Vallat.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24: * POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: /*
28: * Driver for the PCMCIA controller found in Tadpole SPARCbook 3 series
29: * notebooks.
30: *
31: * Based on the information provided in the SPARCbook 3 Technical Reference
32: * Manual (s3gxtrmb.pdf), chapter 7. A few ramblings against this document
33: * and/or the chip itself are scattered across this file.
34: *
35: * Implementation notes:
36: *
37: * - The TS102 exports its PCMCIA windows as SBus memory ranges: 64MB for
38: * the common memory window, and 16MB for the attribute and I/O windows.
39: *
40: * Mapping the whole windows would consume 192MB of address space, which
41: * is much more that what the iospace can offer.
42: *
43: * A best-effort solution would be to map the windows on demand. However,
44: * due to the way mapdev() works, the va used for the mappings would be
45: * lost after unmapping (although using an extent to register iospace memory
46: * usage would fix this). So, instead, we will do a fixed mapping of a subset
47: * of each window upon attach - this is similar to what the stp4020 driver
48: * does.
49: *
50: * - IPL for the cards interrupt handlers are not respected. See the stp4020
51: * driver source for comments about this.
52: *
53: * Endianness farce:
54: *
55: * - The documentation pretends that the endianness settings only affect the
56: * common memory window. Gee, thanks a lot. What about other windows, then?
57: * As a result, this driver runs with endianness conversions turned off.
58: *
59: * - One of the little-endian SBus and big-endian PCMCIA flags has the reverse
60: * meaning, actually. To achieve a ``no endianness conversion'' status,
61: * one has to be set and the other unset. It does not matter which one,
62: * though.
63: */
64:
65: #include <sys/param.h>
66: #include <sys/systm.h>
67: #include <sys/conf.h>
68: #include <sys/device.h>
69: #include <sys/kthread.h>
70: #include <sys/proc.h>
71: #include <sys/queue.h>
72:
73: #include <machine/bus.h>
74:
75: #include <uvm/uvm_extern.h>
76:
77: #include <dev/pcmcia/pcmciareg.h>
78: #include <dev/pcmcia/pcmciavar.h>
79: #include <dev/pcmcia/pcmciachip.h>
80:
81: #include <sparc/dev/sbusvar.h>
82: #include <sparc/dev/tctrlvar.h>
83: #include <sparc/dev/ts102reg.h>
84:
85: #define TS102_NUM_SLOTS 2
86:
87: /*
88: * Memory ranges
89: */
90: #define TS102_RANGE_COMMON 0
91: #define TS102_RANGE_ATTR 1
92: #define TS102_RANGE_IO 2
93:
94: #define TS102_RANGE_CNT 3
95: #define TS102_NUM_RANGES (TS102_RANGE_CNT * TS102_NUM_SLOTS)
96:
97: #define TS102_ARBITRARY_MAP_SIZE (1 * 1024 * 1024)
98:
99: struct tslot_softc;
100:
101: /*
102: * Per-slot data
103: */
104: struct tslot_data {
105: struct tslot_softc *td_parent;
106: struct device *td_pcmcia;
107:
108: volatile u_int8_t *td_regs;
109: struct rom_reg td_rr;
110: vaddr_t td_space[TS102_RANGE_CNT];
111:
112: /* Interrupt handler */
113: int (*td_intr)(void *);
114: void *td_intrarg;
115:
116: /* Socket status */
117: int td_slot;
118: int td_status;
119: #define TS_CARD 0x0001
120: };
121:
122: struct tslot_softc {
123: struct device sc_dev;
124:
125: struct intrhand sc_ih;
126:
127: pcmcia_chipset_tag_t sc_pct;
128:
129: struct proc *sc_thread; /* event thread */
130: unsigned int sc_events; /* sockets with pending events */
131:
132: struct tslot_data sc_slot[TS102_NUM_SLOTS];
133: };
134:
135: void tslot_attach(struct device *, struct device *, void *);
136: void tslot_create_event_thread(void *);
137: void tslot_event_thread(void *);
138: int tslot_intr(void *);
139: void tslot_intr_disestablish(pcmcia_chipset_handle_t, void *);
140: void *tslot_intr_establish(pcmcia_chipset_handle_t, struct pcmcia_function *,
141: int, int (*)(void *), void *, char *);
142: const char *tslot_intr_string(pcmcia_chipset_handle_t, void *);
143: int tslot_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t,
144: bus_size_t, struct pcmcia_io_handle *);
145: void tslot_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *);
146: int tslot_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
147: struct pcmcia_io_handle *, int *);
148: void tslot_io_unmap(pcmcia_chipset_handle_t, int);
149: int tslot_match(struct device *, void *, void *);
150: int tslot_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
151: struct pcmcia_mem_handle *);
152: void tslot_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *);
153: int tslot_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
154: struct pcmcia_mem_handle *, bus_size_t *, int *);
155: void tslot_mem_unmap(pcmcia_chipset_handle_t, int);
156: int tslot_print(void *, const char *);
157: void tslot_queue_event(struct tslot_softc *, int);
158: void tslot_reset(struct tslot_data *, u_int32_t);
159: void tslot_slot_disable(pcmcia_chipset_handle_t);
160: void tslot_slot_enable(pcmcia_chipset_handle_t);
161: void tslot_slot_intr(struct tslot_data *, int);
162:
163: struct cfattach tslot_ca = {
164: sizeof(struct tslot_softc), tslot_match, tslot_attach
165: };
166:
167: struct cfdriver tslot_cd = {
168: NULL, "tslot", DV_DULL
169: };
170:
171: /*
172: * PCMCIA chipset methods
173: */
174: struct pcmcia_chip_functions tslot_functions = {
175: tslot_mem_alloc,
176: tslot_mem_free,
177: tslot_mem_map,
178: tslot_mem_unmap,
179:
180: tslot_io_alloc,
181: tslot_io_free,
182: tslot_io_map,
183: tslot_io_unmap,
184:
185: tslot_intr_establish,
186: tslot_intr_disestablish,
187: tslot_intr_string,
188:
189: tslot_slot_enable,
190: tslot_slot_disable
191: };
192:
193: #define TSLOT_READ(slot, offset) \
194: *(volatile u_int16_t *)((slot)->td_regs + (offset))
195: #define TSLOT_WRITE(slot, offset, value) \
196: *(volatile u_int16_t *)((slot)->td_regs + (offset)) = (value)
197:
198: /*
199: * Attachment and initialization
200: */
201:
202: int
203: tslot_match(struct device *parent, void *vcf, void *aux)
204: {
205: struct confargs *ca = aux;
206:
207: return (strcmp("ts102", ca->ca_ra.ra_name) == 0);
208: }
209:
210: void
211: tslot_attach(struct device *parent, struct device *self, void *args)
212: {
213: struct confargs *ca = args;
214: struct tslot_softc *sc = (struct tslot_softc *)self;
215: struct romaux *ra;
216: struct rom_range ranges[TS102_NUM_RANGES], *range;
217: struct tslot_data *td;
218: volatile u_int8_t *regs;
219: int node, nranges, slot, rnum;
220:
221: ra = &ca->ca_ra;
222: node = ra->ra_node;
223: regs = mapiodev(&ra->ra_reg[0], 0, ra->ra_len);
224:
225: /*
226: * Find memory ranges
227: */
228: nranges = getproplen(node, "ranges") / sizeof(struct rom_range);
229: if (nranges < TS102_NUM_RANGES) {
230: printf(": expected %d memory ranges, got %d\n",
231: TS102_NUM_RANGES, nranges);
232: return;
233: }
234: getprop(node, "ranges", ranges, sizeof ranges);
235:
236: /*
237: * Ranges being relative to this sbus slot, turn them into absolute
238: * addresses.
239: */
240: for (rnum = 0; rnum < TS102_NUM_RANGES; rnum++) {
241: ranges[rnum].poffset -= TS102_OFFSET_REGISTERS;
242: }
243:
244: sc->sc_ih.ih_fun = tslot_intr;
245: sc->sc_ih.ih_arg = sc;
246: intr_establish(ra->ra_intr[0].int_pri, &sc->sc_ih, -1, self->dv_xname);
247: printf(" pri %d", ra->ra_intr[0].int_pri);
248:
249: printf(": %d slots\n", TS102_NUM_SLOTS);
250:
251: /*
252: * Setup asynchronous event handler
253: */
254: sc->sc_events = 0;
255: kthread_create_deferred(tslot_create_event_thread, sc);
256:
257: sc->sc_pct = (pcmcia_chipset_tag_t)&tslot_functions;
258:
259: /*
260: * Setup slots
261: */
262: for (slot = 0; slot < TS102_NUM_SLOTS; slot++) {
263: td = &sc->sc_slot[slot];
264: for (rnum = 0; rnum < TS102_RANGE_CNT; rnum++) {
265: range = ranges + (slot * TS102_RANGE_CNT + rnum);
266: td->td_rr = ra->ra_reg[0];
267: td->td_rr.rr_iospace = range->pspace;
268: td->td_rr.rr_paddr = (void *)
269: ((u_int32_t)td->td_rr.rr_paddr + range->poffset);
270: td->td_space[rnum] = (vaddr_t)mapiodev(&td->td_rr, 0,
271: TS102_ARBITRARY_MAP_SIZE);
272: }
273: td->td_parent = sc;
274: td->td_regs = regs +
275: slot * (TS102_REG_CARD_B_INT - TS102_REG_CARD_A_INT);
276: td->td_slot = slot;
277: SET_TAG_LITTLE_ENDIAN(&td->td_rr);
278: tslot_reset(td, TS102_ARBITRARY_MAP_SIZE);
279: }
280: }
281:
282: void
283: tslot_reset(struct tslot_data *td, u_int32_t iosize)
284: {
285: struct pcmciabus_attach_args paa;
286: int ctl, status;
287:
288: paa.paa_busname = "pcmcia";
289: paa.pct = (pcmcia_chipset_tag_t)td->td_parent->sc_pct;
290: paa.pch = (pcmcia_chipset_handle_t)td;
291: paa.iobase = 0;
292: paa.iosize = iosize;
293:
294: td->td_pcmcia = config_found(&td->td_parent->sc_dev, &paa, tslot_print);
295:
296: if (td->td_pcmcia == NULL) {
297: /*
298: * If no pcmcia attachment, power down the slot.
299: */
300: tslot_slot_disable((pcmcia_chipset_handle_t)td);
301: return;
302: }
303:
304: /*
305: * Initialize the slot
306: */
307:
308: ctl = TSLOT_READ(td, TS102_REG_CARD_A_CTL);
309: /* force low addresses */
310: ctl &= ~(TS102_CARD_CTL_AA_MASK | TS102_CARD_CTL_IA_MASK);
311: /* Put SBus and PCMCIA in their respective endian mode */
312: ctl |= TS102_CARD_CTL_SBLE; /* this is not what it looks like! */
313: ctl &= ~TS102_CARD_CTL_PCMBE;
314: /* disable read ahead and address increment */
315: ctl &= ~TS102_CARD_CTL_RAHD;
316: ctl |= TS102_CARD_CTL_INCDIS;
317: /* power on */
318: ctl &= ~TS102_CARD_CTL_PWRD;
319: TSLOT_WRITE(td, TS102_REG_CARD_A_CTL, ctl);
320:
321: /*
322: * Enable interrupt upon insertion/removal
323: */
324:
325: TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
326: TS102_CARD_INT_MASK_CARDDETECT_STATUS);
327:
328: status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
329: if (status & TS102_CARD_STS_PRES) {
330: tadpole_set_pcmcia(td->td_slot, 1);
331: td->td_status = TS_CARD;
332: pcmcia_card_attach(td->td_pcmcia);
333: } else {
334: tadpole_set_pcmcia(td->td_slot, 0);
335: td->td_status = 0;
336: }
337: }
338:
339: /* XXX there ought to be a common function for this... */
340: int
341: tslot_print(void *aux, const char *description)
342: {
343: struct pcmciabus_attach_args *paa = aux;
344: struct tslot_data *td = (struct tslot_data *)paa->pch;
345:
346: printf(" socket %d", td->td_slot);
347: return (UNCONF);
348: }
349:
350: /*
351: * PCMCIA Helpers
352: */
353:
354: int
355: tslot_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size,
356: bus_size_t align, struct pcmcia_io_handle *pih)
357: {
358: struct tslot_data *td = (struct tslot_data *)pch;
359:
360: #ifdef TSLOT_DEBUG
361: printf("[io alloc %x-%x]", start, size);
362: #endif
363:
364: pih->iot = &td->td_rr;
365: pih->ioh = (bus_space_handle_t)(td->td_space[TS102_RANGE_IO]);
366: pih->addr = start;
367: pih->size = size;
368: pih->flags = 0;
369:
370: return (0);
371: }
372:
373: void
374: tslot_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
375: {
376: #ifdef TSLOT_DEBUG
377: printf("[io free %x-%x]", pih->start, pih->size);
378: #endif
379: }
380:
381: int
382: tslot_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
383: bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
384: {
385: struct tslot_data *td = (struct tslot_data *)pch;
386:
387: #ifdef TSLOT_DEBUG
388: printf("[io map %x-%x", offset, size);
389: #endif
390:
391: pih->iot = &td->td_rr;
392: bus_space_subregion(&td->td_rr, td->td_space[TS102_RANGE_IO],
393: offset, size, &pih->ioh);
394: *windowp = TS102_RANGE_IO;
395:
396: #ifdef TSLOT_DEBUG
397: printf("->%p/%x]", pih->ioh, size);
398: #endif
399:
400: return (0);
401: }
402:
403: void
404: tslot_io_unmap(pcmcia_chipset_handle_t pch, int win)
405: {
406: #ifdef TSLOT_DEBUG
407: printf("[io unmap]");
408: #endif
409: }
410:
411: int
412: tslot_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
413: struct pcmcia_mem_handle *pmh)
414: {
415: struct tslot_data *td = (struct tslot_data *)pch;
416:
417: #ifdef TSLOT_DEBUG
418: printf("[mem alloc %x]", size);
419: #endif
420: pmh->memt = &td->td_rr;
421: pmh->size = round_page(size);
422: pmh->addr = 0;
423: pmh->mhandle = 0;
424: pmh->realsize = 0; /* nothing so far! */
425:
426: return (0);
427: }
428:
429: void
430: tslot_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
431: {
432: #ifdef TSLOT_DEBUG
433: printf("[mem free %x]", pmh->size);
434: #endif
435: }
436:
437: int
438: tslot_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr,
439: bus_size_t size, struct pcmcia_mem_handle *pmh, bus_size_t *offsetp,
440: int *windowp)
441: {
442: struct tslot_data *td = (struct tslot_data *)pch;
443: int slot;
444:
445: slot = kind & PCMCIA_MEM_ATTR ? TS102_RANGE_ATTR : TS102_RANGE_COMMON;
446: #ifdef TSLOT_DEBUG
447: printf("[mem map %d %x-%x", slot, addr, size);
448: #endif
449:
450: addr += pmh->addr;
451:
452: pmh->memt = &td->td_rr;
453: bus_space_subregion(&td->td_rr, td->td_space[slot],
454: addr, size, &pmh->memh);
455: pmh->realsize = TS102_ARBITRARY_MAP_SIZE - addr;
456: *offsetp = 0;
457: *windowp = slot;
458:
459: #ifdef TSLOT_DEBUG
460: printf("->%p/%x]", pmh->memh, size);
461: #endif
462:
463: return (0);
464: }
465:
466: void
467: tslot_mem_unmap(pcmcia_chipset_handle_t pch, int win)
468: {
469: #ifdef TSLOT_DEBUG
470: printf("[mem unmap %d]", win);
471: #endif
472: }
473:
474: void
475: tslot_slot_disable(pcmcia_chipset_handle_t pch)
476: {
477: struct tslot_data *td = (struct tslot_data *)pch;
478:
479: #ifdef TSLOT_DEBUG
480: printf("%s: disable slot %d\n",
481: td->td_parent->sc_dev.dv_xname, td->td_slot);
482: #endif
483:
484: /*
485: * Disable card access.
486: */
487: TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
488: TSLOT_READ(td, TS102_REG_CARD_A_STS) & ~TS102_CARD_STS_ACEN);
489:
490: /*
491: * Disable interrupts, except for insertion.
492: */
493: TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
494: TS102_CARD_INT_MASK_CARDDETECT_STATUS);
495: }
496:
497: void
498: tslot_slot_enable(pcmcia_chipset_handle_t pch)
499: {
500: struct tslot_data *td = (struct tslot_data *)pch;
501: int status, intr, i;
502:
503: #ifdef TSLOT_DEBUG
504: printf("%s: enable slot %d\n",
505: td->td_parent->sc_dev.dv_xname, td->td_slot);
506: #endif
507:
508: /* Power down the socket to reset it */
509: status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
510: TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status | TS102_CARD_STS_VCCEN);
511:
512: /*
513: * wait 300ms until power fails (Tpf). Then, wait 100ms since we
514: * are changing Vcc (Toff).
515: */
516: DELAY((300 + 100) * 1000);
517:
518: /*
519: * Power on the card if not already done, and enable card access
520: */
521: status |= TS102_CARD_STS_ACEN;
522: status &= ~TS102_CARD_STS_VCCEN;
523: TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
524:
525: /*
526: * wait 100ms until power raise (Tpr) and 20ms to become
527: * stable (Tsu(Vcc)).
528: */
529: DELAY((100 + 20) * 1000);
530:
531: status &= ~TS102_CARD_STS_VPP1_MASK;
532: status |= TS102_CARD_STS_VPP1_VCC;
533: TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
534:
535: /*
536: * hold RESET at least 20us.
537: */
538: intr = TSLOT_READ(td, TS102_REG_CARD_A_INT);
539: TSLOT_WRITE(td, TS102_REG_CARD_A_INT, TS102_CARD_INT_SOFT_RESET);
540: DELAY(20);
541: TSLOT_WRITE(td, TS102_REG_CARD_A_INT, intr);
542:
543: /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
544: DELAY(20 * 1000);
545:
546: /* We need level-triggered interrupts for PC Card hardware */
547: TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
548: TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_LVL);
549:
550: /*
551: * Wait until the card is unbusy. If it is still busy after 3 seconds,
552: * give up. We could enable card interrupts and wait for the interrupt
553: * to happen when BUSY is released, but the interrupt could also be
554: * triggered by the card itself if it's an I/O card, so better poll
555: * here.
556: */
557: for (i = 30000; i != 0; i--) {
558: status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
559: /* If the card has been removed, abort */
560: if ((status & TS102_CARD_STS_PRES) == 0) {
561: tslot_slot_disable(pch);
562: return;
563: }
564: if (status & TS102_CARD_STS_RDY)
565: break;
566: else
567: DELAY(100);
568: }
569:
570: if (i == 0) {
571: printf("%s: slot %d still busy after 3 seconds, status 0x%x\n",
572: td->td_parent->sc_dev.dv_xname, td->td_slot,
573: TSLOT_READ(td, TS102_REG_CARD_A_STS));
574: return;
575: }
576:
577: /*
578: * Enable the card interrupts if this is an I/O card.
579: * Note that the TS102_CARD_STS_IO bit in the status register will
580: * never get set, despite what the documentation says!
581: */
582: if (pcmcia_card_gettype(td->td_pcmcia) == PCMCIA_IFTYPE_IO) {
583: TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
584: TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_IO);
585: TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
586: TS102_CARD_INT_MASK_CARDDETECT_STATUS |
587: TS102_CARD_INT_MASK_IRQ);
588: }
589: }
590:
591: /*
592: * Event management
593: */
594: void
595: tslot_create_event_thread(void *v)
596: {
597: struct tslot_softc *sc = v;
598: const char *name = sc->sc_dev.dv_xname;
599:
600: if (kthread_create(tslot_event_thread, sc, &sc->sc_thread, "%s",
601: name) != 0) {
602: panic("%s: unable to create event kthread", name);
603: }
604: }
605:
606: void
607: tslot_event_thread(void *v)
608: {
609: struct tslot_softc *sc = v;
610: struct tslot_data *td;
611: int s, status;
612: unsigned int socket;
613:
614: for (;;) {
615: s = splhigh();
616:
617: if ((socket = ffs(sc->sc_events)) == 0) {
618: splx(s);
619: tsleep(&sc->sc_events, PWAIT, "tslot_event", 0);
620: continue;
621: }
622: socket--;
623: sc->sc_events &= ~(1 << socket);
624: splx(s);
625:
626: if (socket >= TS102_NUM_SLOTS) {
627: #ifdef DEBUG
628: printf("%s: invalid slot number %d\n",
629: sc->sc_dev.dv_xname, te->te_slot);
630: #endif
631: continue;
632: }
633:
634: td = &sc->sc_slot[socket];
635: status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
636:
637: if (status & TS102_CARD_STS_PRES) {
638: /* Card insertion */
639: if ((td->td_status & TS_CARD) == 0) {
640: td->td_status |= TS_CARD;
641: tadpole_set_pcmcia(td->td_slot, 1);
642: pcmcia_card_attach(td->td_pcmcia);
643: }
644: } else {
645: /* Card removal */
646: if ((td->td_status & TS_CARD) != 0) {
647: td->td_status &= ~TS_CARD;
648: tadpole_set_pcmcia(td->td_slot, 0);
649: pcmcia_card_detach(td->td_pcmcia,
650: DETACH_FORCE);
651: }
652: }
653: }
654: }
655:
656: /*
657: * Interrupt handling
658: */
659:
660: int
661: tslot_intr(void *v)
662: {
663: struct tslot_softc *sc = v;
664: struct tslot_data *td;
665: int intregs[TS102_NUM_SLOTS], *intreg;
666: int i, rc = 0;
667:
668: /*
669: * Scan slots, and acknowledge the interrupt if necessary first
670: */
671: for (i = 0; i < TS102_NUM_SLOTS; i++) {
672: td = &sc->sc_slot[i];
673: intreg = &intregs[i];
674: *intreg = TSLOT_READ(td, TS102_REG_CARD_A_INT);
675:
676: /*
677: * Acknowledge all interrupt situations at once, even if they
678: * did not occur.
679: */
680: if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
681: TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
682: TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
683: TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0) {
684: rc = 1;
685: TSLOT_WRITE(td, TS102_REG_CARD_A_INT, *intreg |
686: TS102_CARD_INT_RQST_IRQ |
687: TS102_CARD_INT_RQST_WP_STATUS_CHANGED |
688: TS102_CARD_INT_RQST_BATTERY_STATUS_CHANGED |
689: TS102_CARD_INT_RQST_CARDDETECT_STATUS_CHANGED);
690: }
691: }
692:
693: /*
694: * Invoke the interrupt handler for each slot
695: */
696: for (i = 0; i < TS102_NUM_SLOTS; i++) {
697: td = &sc->sc_slot[i];
698: intreg = &intregs[i];
699:
700: if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
701: TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
702: TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
703: TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0)
704: tslot_slot_intr(td, *intreg);
705: }
706:
707: return (rc);
708: }
709:
710: void
711: tslot_queue_event(struct tslot_softc *sc, int slot)
712: {
713: int s;
714:
715: s = splhigh();
716: sc->sc_events |= (1 << slot);
717: splx(s);
718: wakeup(&sc->sc_events);
719: }
720:
721: void
722: tslot_slot_intr(struct tslot_data *td, int intreg)
723: {
724: struct tslot_softc *sc = td->td_parent;
725: int status, sockstat;
726:
727: status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
728: #ifdef TSLOT_DEBUG
729: printf("%s: interrupt on socket %d ir %x sts %x\n",
730: sc->sc_dev.dv_xname, td->td_slot, intreg, status);
731: #endif
732:
733: sockstat = td->td_status;
734:
735: /*
736: * The TS102 queues interrupt requests, and may trigger an interrupt
737: * for a condition the driver does not want to receive anymore (for
738: * example, after a card gets removed).
739: * Thus, only proceed if the driver is currently allowing a particular
740: * condition.
741: */
742:
743: if ((intreg & TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED) != 0 &&
744: (intreg & TS102_CARD_INT_MASK_CARDDETECT_STATUS) != 0) {
745: tslot_queue_event(sc, td->td_slot);
746: #ifdef TSLOT_DEBUG
747: printf("%s: slot %d status changed from %d to %d\n",
748: sc->sc_dev.dv_xname, td->td_slot, sockstat, td->td_status);
749: #endif
750: /*
751: * Ignore extra interrupt bits, they are part of the change.
752: */
753: return;
754: }
755:
756: if ((intreg & TS102_CARD_INT_STATUS_IRQ) != 0 &&
757: (intreg & TS102_CARD_INT_MASK_IRQ) != 0) {
758: /* ignore interrupts if we have a pending state change */
759: if (sc->sc_events & (1 << td->td_slot))
760: return;
761:
762: if ((sockstat & TS_CARD) == 0) {
763: printf("%s: spurious interrupt on slot %d isr %x\n",
764: sc->sc_dev.dv_xname, td->td_slot, intreg);
765: return;
766: }
767:
768: if (td->td_intr != NULL) {
769: /*
770: * XXX There is no way to honour the interrupt handler
771: * requested IPL level...
772: */
773: (*td->td_intr)(td->td_intrarg);
774: }
775: }
776: }
777:
778: void
779: tslot_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
780: {
781: struct tslot_data *td = (struct tslot_data *)pch;
782:
783: td->td_intr = NULL;
784: td->td_intrarg = NULL;
785: }
786:
787: const char *
788: tslot_intr_string(pcmcia_chipset_handle_t pch, void *ih)
789: {
790: if (ih == NULL)
791: return ("couldn't establish interrupt");
792: else
793: return (""); /* nothing for now */
794: }
795:
796:
797: void *
798: tslot_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf,
799: int ipl, int (*handler)(void *), void *arg, char *xname)
800: {
801: struct tslot_data *td = (struct tslot_data *)pch;
802:
803: td->td_intr = handler;
804: td->td_intrarg = arg;
805:
806: return (td);
807: }
CVSweb