Annotation of sys/dev/sdmmc/sdmmc_io.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sdmmc_io.c,v 1.9 2007/06/02 01:48:37 uwe Exp $ */
2:
3: /*
4: * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /* Routines for SD I/O cards. */
20:
21: #include <sys/param.h>
22: #include <sys/kernel.h>
23: #include <sys/malloc.h>
24: #include <sys/proc.h>
25: #include <sys/systm.h>
26:
27: #include <dev/sdmmc/sdmmc_ioreg.h>
28: #include <dev/sdmmc/sdmmcchip.h>
29: #include <dev/sdmmc/sdmmcreg.h>
30: #include <dev/sdmmc/sdmmcvar.h>
31:
32: struct sdmmc_intr_handler {
33: struct sdmmc_softc *ih_softc;
34: char *ih_name;
35: int (*ih_fun)(void *);
36: void *ih_arg;
37: TAILQ_ENTRY(sdmmc_intr_handler) entry;
38: };
39:
40: int sdmmc_submatch(struct device *, void *, void *);
41: int sdmmc_print(void *, const char *);
42: int sdmmc_io_rw_direct(struct sdmmc_softc *, struct sdmmc_function *,
43: int, u_char *, int);
44: int sdmmc_io_rw_extended(struct sdmmc_softc *, struct sdmmc_function *,
45: int, u_char *, int, int);
46: int sdmmc_io_xchg(struct sdmmc_softc *, struct sdmmc_function *,
47: int, u_char *);
48: void sdmmc_io_reset(struct sdmmc_softc *);
49: int sdmmc_io_send_op_cond(struct sdmmc_softc *, u_int32_t, u_int32_t *);
50:
51: #ifdef SDMMC_DEBUG
52: #define DPRINTF(s) printf s
53: #else
54: #define DPRINTF(s) /**/
55: #endif
56:
57: #ifdef SDMMC_DEBUG
58: int sdmmc_verbose = 1;
59: #else
60: int sdmmc_verbose = 0;
61: #endif
62:
63: /*
64: * Initialize SD I/O card functions (before memory cards). The host
65: * system and controller must support card interrupts in order to use
66: * I/O functions.
67: */
68: int
69: sdmmc_io_enable(struct sdmmc_softc *sc)
70: {
71: u_int32_t host_ocr;
72: u_int32_t card_ocr;
73:
74: /* Set host mode to SD "combo" card. */
75: SET(sc->sc_flags, SMF_SD_MODE|SMF_IO_MODE|SMF_MEM_MODE);
76:
77: /* Reset I/O functions. */
78: sdmmc_io_reset(sc);
79:
80: /*
81: * Read the I/O OCR value, determine the number of I/O
82: * functions and whether memory is also present (a "combo
83: * card") by issuing CMD5. SD memory-only and MMC cards
84: * do not respond to CMD5.
85: */
86: if (sdmmc_io_send_op_cond(sc, 0, &card_ocr) != 0) {
87: /* No SDIO card; switch to SD memory-only mode. */
88: CLR(sc->sc_flags, SMF_IO_MODE);
89: return 0;
90: }
91:
92: /* Parse the additional bits in the I/O OCR value. */
93: if (!ISSET(card_ocr, SD_IO_OCR_MEM_PRESENT)) {
94: /* SDIO card without memory (not a "combo card"). */
95: DPRINTF(("%s: no memory present\n", SDMMCDEVNAME(sc)));
96: CLR(sc->sc_flags, SMF_MEM_MODE);
97: }
98: sc->sc_function_count = SD_IO_OCR_NUM_FUNCTIONS(card_ocr);
99: if (sc->sc_function_count == 0) {
100: /* Useless SDIO card without any I/O functions. */
101: DPRINTF(("%s: no I/O functions\n", SDMMCDEVNAME(sc)));
102: CLR(sc->sc_flags, SMF_IO_MODE);
103: return 0;
104: }
105: card_ocr &= SD_IO_OCR_MASK;
106:
107: /* Set the lowest voltage supported by the card and host. */
108: host_ocr = sdmmc_chip_host_ocr(sc->sct, sc->sch);
109: if (sdmmc_set_bus_power(sc, host_ocr, card_ocr) != 0) {
110: printf("%s: can't supply voltage requested by card\n",
111: SDMMCDEVNAME(sc));
112: return 1;
113: }
114:
115: /* Reset I/O functions (again). */
116: sdmmc_io_reset(sc);
117:
118: /* Send the new OCR value until all cards are ready. */
119: if (sdmmc_io_send_op_cond(sc, host_ocr, NULL) != 0) {
120: printf("%s: can't send I/O OCR\n", SDMMCDEVNAME(sc));
121: return 1;
122: }
123: return 0;
124: }
125:
126: /*
127: * Allocate sdmmc_function structures for SD card I/O function
128: * (including function 0).
129: */
130: void
131: sdmmc_io_scan(struct sdmmc_softc *sc)
132: {
133: struct sdmmc_function *sf0, *sf;
134: int i;
135:
136: sf0 = sdmmc_function_alloc(sc);
137: sf0->number = 0;
138: if (sdmmc_set_relative_addr(sc, sf0) != 0) {
139: printf("%s: can't set I/O RCA\n", SDMMCDEVNAME(sc));
140: SET(sf0->flags, SFF_ERROR);
141: return;
142: }
143: sc->sc_fn0 = sf0;
144: SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf0, sf_list);
145:
146: /* Verify that the RCA has been set by selecting the card. */
147: if (sdmmc_select_card(sc, sf0) != 0) {
148: printf("%s: can't select I/O RCA %d\n", SDMMCDEVNAME(sc),
149: sf0->rca);
150: SET(sf0->flags, SFF_ERROR);
151: return;
152: }
153:
154: for (i = 1; i <= sc->sc_function_count; i++) {
155: sf = sdmmc_function_alloc(sc);
156: sf->number = i;
157: sf->rca = sf0->rca;
158:
159: SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf, sf_list);
160: }
161: }
162:
163: /*
164: * Initialize SDIO card functions.
165: */
166: int
167: sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
168: {
169: if (sf->number == 0) {
170: sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
171: CCCR_BUS_WIDTH_1);
172:
173: if (sdmmc_read_cis(sf, &sf->cis) != 0) {
174: printf("%s: can't read CIS\n", SDMMCDEVNAME(sc));
175: SET(sf->flags, SFF_ERROR);
176: return 1;
177: }
178:
179: sdmmc_check_cis_quirks(sf);
180:
181: if (sdmmc_verbose)
182: sdmmc_print_cis(sf);
183: }
184: return 0;
185: }
186:
187: /*
188: * Indicate whether the function is ready to operate.
189: */
190: int
191: sdmmc_io_function_ready(struct sdmmc_function *sf)
192: {
193: struct sdmmc_softc *sc = sf->sc;
194: struct sdmmc_function *sf0 = sc->sc_fn0;
195: u_int8_t rv;
196:
197: if (sf->number == 0)
198: return 1; /* FN0 is always ready */
199:
200: rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_READY);
201: return (rv & (1 << sf->number)) != 0;
202: }
203:
204: /*
205: * Enable the I/O function. Return zero if the function was
206: * enabled successfully.
207: */
208: int
209: sdmmc_io_function_enable(struct sdmmc_function *sf)
210: {
211: struct sdmmc_softc *sc = sf->sc;
212: struct sdmmc_function *sf0 = sc->sc_fn0;
213: u_int8_t rv;
214: int retry = 5;
215:
216: if (sf->number == 0)
217: return 0; /* FN0 is always enabled */
218:
219: SDMMC_LOCK(sc);
220: rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE);
221: rv |= (1<<sf->number);
222: sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv);
223: SDMMC_UNLOCK(sc);
224:
225: while (!sdmmc_io_function_ready(sf) && retry-- > 0)
226: tsleep(&lbolt, PPAUSE, "pause", 0);
227: return (retry >= 0) ? 0 : ETIMEDOUT;
228: }
229:
230: /*
231: * Disable the I/O function. Return zero if the function was
232: * disabled successfully.
233: */
234: void
235: sdmmc_io_function_disable(struct sdmmc_function *sf)
236: {
237: struct sdmmc_softc *sc = sf->sc;
238: struct sdmmc_function *sf0 = sc->sc_fn0;
239: u_int8_t rv;
240:
241: if (sf->number == 0)
242: return; /* FN0 is always enabled */
243:
244: SDMMC_LOCK(sc);
245: rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE);
246: rv &= ~(1<<sf->number);
247: sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv);
248: SDMMC_UNLOCK(sc);
249: }
250:
251: void
252: sdmmc_io_attach(struct sdmmc_softc *sc)
253: {
254: struct sdmmc_function *sf;
255: struct sdmmc_attach_args saa;
256:
257: SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
258: if (sf->number < 1)
259: continue;
260:
261: bzero(&saa, sizeof saa);
262: saa.sf = sf;
263:
264: sf->child = config_found_sm(&sc->sc_dev, &saa, sdmmc_print,
265: sdmmc_submatch);
266: }
267: }
268:
269: int
270: sdmmc_submatch(struct device *parent, void *match, void *aux)
271: {
272: struct cfdata *cf = match;
273:
274: /* Skip the scsibus, it is configured directly. */
275: if (strcmp(cf->cf_driver->cd_name, "scsibus") == 0)
276: return 0;
277:
278: return cf->cf_attach->ca_match(parent, cf, aux);
279: }
280:
281: int
282: sdmmc_print(void *aux, const char *pnp)
283: {
284: struct sdmmc_attach_args *sa = aux;
285: struct sdmmc_function *sf = sa->sf;
286: struct sdmmc_cis *cis = &sf->sc->sc_fn0->cis;
287: int i;
288:
289: if (pnp) {
290: if (sf->number == 0)
291: return QUIET;
292:
293: for (i = 0; i < 4 && cis->cis1_info[i]; i++)
294: printf("%s%s", i ? ", " : "\"", cis->cis1_info[i]);
295: if (i != 0)
296: printf("\"");
297:
298: if (cis->manufacturer != SDMMC_VENDOR_INVALID &&
299: cis->product != SDMMC_PRODUCT_INVALID) {
300: printf("%s(", i ? " " : "");
301: if (cis->manufacturer != SDMMC_VENDOR_INVALID)
302: printf("manufacturer 0x%x%s",
303: cis->manufacturer,
304: cis->product == SDMMC_PRODUCT_INVALID ?
305: "" : ", ");
306: if (cis->product != SDMMC_PRODUCT_INVALID)
307: printf("product 0x%x", cis->product);
308: printf(")");
309: }
310: printf("%sat %s", i ? " " : "", pnp);
311: }
312: printf(" function %d", sf->number);
313:
314: if (!pnp) {
315: for (i = 0; i < 3 && cis->cis1_info[i]; i++)
316: printf("%s%s", i ? ", " : " \"", cis->cis1_info[i]);
317: if (i != 0)
318: printf("\"");
319: }
320: return UNCONF;
321: }
322:
323: void
324: sdmmc_io_detach(struct sdmmc_softc *sc)
325: {
326: struct sdmmc_function *sf;
327:
328: SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
329: if (sf->child != NULL) {
330: config_detach(sf->child, DETACH_FORCE);
331: sf->child = NULL;
332: }
333: }
334:
335: KASSERT(TAILQ_EMPTY(&sc->sc_intrq));
336: }
337:
338: int
339: sdmmc_io_rw_direct(struct sdmmc_softc *sc, struct sdmmc_function *sf,
340: int reg, u_char *datap, int arg)
341: {
342: struct sdmmc_command cmd;
343: int error;
344:
345: SDMMC_LOCK(sc);
346:
347: /* Make sure the card is selected. */
348: if ((error = sdmmc_select_card(sc, sf)) != 0) {
349: SDMMC_UNLOCK(sc);
350: return error;
351: }
352:
353: arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD52_FUNC_MASK) <<
354: SD_ARG_CMD52_FUNC_SHIFT;
355: arg |= (reg & SD_ARG_CMD52_REG_MASK) <<
356: SD_ARG_CMD52_REG_SHIFT;
357: arg |= (*datap & SD_ARG_CMD52_DATA_MASK) <<
358: SD_ARG_CMD52_DATA_SHIFT;
359:
360: bzero(&cmd, sizeof cmd);
361: cmd.c_opcode = SD_IO_RW_DIRECT;
362: cmd.c_arg = arg;
363: cmd.c_flags = SCF_CMD_AC | SCF_RSP_R5;
364:
365: error = sdmmc_mmc_command(sc, &cmd);
366: *datap = SD_R5_DATA(cmd.c_resp);
367:
368: SDMMC_UNLOCK(sc);
369: return error;
370: }
371:
372: /*
373: * Useful values of `arg' to pass in are either SD_ARG_CMD53_READ or
374: * SD_ARG_CMD53_WRITE. SD_ARG_CMD53_INCREMENT may be ORed into `arg'
375: * to access successive register locations instead of accessing the
376: * same register many times.
377: */
378: int
379: sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf,
380: int reg, u_char *datap, int datalen, int arg)
381: {
382: struct sdmmc_command cmd;
383: int error;
384:
385: SDMMC_LOCK(sc);
386:
387: #if 0
388: /* Make sure the card is selected. */
389: if ((error = sdmmc_select_card(sc, sf)) != 0) {
390: SDMMC_UNLOCK(sc);
391: return error;
392: }
393: #endif
394:
395: arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD53_FUNC_MASK) <<
396: SD_ARG_CMD53_FUNC_SHIFT;
397: arg |= (reg & SD_ARG_CMD53_REG_MASK) <<
398: SD_ARG_CMD53_REG_SHIFT;
399: arg |= (datalen & SD_ARG_CMD53_LENGTH_MASK) <<
400: SD_ARG_CMD53_LENGTH_SHIFT;
401:
402: bzero(&cmd, sizeof cmd);
403: cmd.c_opcode = SD_IO_RW_EXTENDED;
404: cmd.c_arg = arg;
405: cmd.c_flags = SCF_CMD_AC | SCF_RSP_R5;
406: cmd.c_data = datap;
407: cmd.c_datalen = datalen;
408: cmd.c_blklen = MIN(datalen, sdmmc_chip_host_maxblklen(sc->sct, sc->sch));
409:
410: if (!ISSET(arg, SD_ARG_CMD53_WRITE))
411: cmd.c_flags |= SCF_CMD_READ;
412:
413: error = sdmmc_mmc_command(sc, &cmd);
414: SDMMC_UNLOCK(sc);
415: return error;
416: }
417:
418: u_int8_t
419: sdmmc_io_read_1(struct sdmmc_function *sf, int reg)
420: {
421: u_int8_t data = 0;
422:
423: (void)sdmmc_io_rw_direct(sf->sc, sf, reg, (u_char *)&data,
424: SD_ARG_CMD52_READ);
425: return data;
426: }
427:
428: void
429: sdmmc_io_write_1(struct sdmmc_function *sf, int reg, u_int8_t data)
430: {
431: (void)sdmmc_io_rw_direct(sf->sc, sf, reg, (u_char *)&data,
432: SD_ARG_CMD52_WRITE);
433: }
434:
435: u_int16_t
436: sdmmc_io_read_2(struct sdmmc_function *sf, int reg)
437: {
438: u_int16_t data = 0;
439:
440: (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2,
441: SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
442: return data;
443: }
444:
445: void
446: sdmmc_io_write_2(struct sdmmc_function *sf, int reg, u_int16_t data)
447: {
448: (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2,
449: SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
450: }
451:
452: u_int32_t
453: sdmmc_io_read_4(struct sdmmc_function *sf, int reg)
454: {
455: u_int32_t data = 0;
456:
457: (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4,
458: SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
459: return data;
460: }
461:
462: void
463: sdmmc_io_write_4(struct sdmmc_function *sf, int reg, u_int32_t data)
464: {
465: (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4,
466: SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
467: }
468:
469: int
470: sdmmc_io_read_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
471: int datalen)
472: {
473: int error;
474:
475: while (datalen > SD_ARG_CMD53_LENGTH_MAX) {
476: error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
477: SD_ARG_CMD53_LENGTH_MAX, SD_ARG_CMD53_READ);
478: if (error)
479: return error;
480: data += SD_ARG_CMD53_LENGTH_MAX;
481: datalen -= SD_ARG_CMD53_LENGTH_MAX;
482: }
483:
484: return sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
485: SD_ARG_CMD53_READ);
486: }
487:
488: int
489: sdmmc_io_write_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
490: int datalen)
491: {
492: int error;
493:
494: while (datalen > SD_ARG_CMD53_LENGTH_MAX) {
495: error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
496: SD_ARG_CMD53_LENGTH_MAX, SD_ARG_CMD53_WRITE);
497: if (error)
498: return error;
499: data += SD_ARG_CMD53_LENGTH_MAX;
500: datalen -= SD_ARG_CMD53_LENGTH_MAX;
501: }
502:
503: return sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
504: SD_ARG_CMD53_WRITE);
505: }
506:
507: int
508: sdmmc_io_xchg(struct sdmmc_softc *sc, struct sdmmc_function *sf,
509: int reg, u_char *datap)
510: {
511: return sdmmc_io_rw_direct(sc, sf, reg, datap,
512: SD_ARG_CMD52_WRITE|SD_ARG_CMD52_EXCHANGE);
513: }
514:
515: /*
516: * Reset the I/O functions of the card.
517: */
518: void
519: sdmmc_io_reset(struct sdmmc_softc *sc)
520: {
521: #if 0 /* XXX command fails */
522: (void)sdmmc_io_write(sc, NULL, SD_IO_REG_CCCR_CTL, CCCR_CTL_RES);
523: sdmmc_delay(100000);
524: #endif
525: }
526:
527: /*
528: * Get or set the card's I/O OCR value (SDIO).
529: */
530: int
531: sdmmc_io_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, u_int32_t *ocrp)
532: {
533: struct sdmmc_command cmd;
534: int error;
535: int i;
536:
537: SDMMC_LOCK(sc);
538:
539: /*
540: * If we change the OCR value, retry the command until the OCR
541: * we receive in response has the "CARD BUSY" bit set, meaning
542: * that all cards are ready for identification.
543: */
544: for (i = 0; i < 100; i++) {
545: bzero(&cmd, sizeof cmd);
546: cmd.c_opcode = SD_IO_SEND_OP_COND;
547: cmd.c_arg = ocr;
548: cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R4;
549:
550: error = sdmmc_mmc_command(sc, &cmd);
551: if (error != 0)
552: break;
553: if (ISSET(MMC_R4(cmd.c_resp), SD_IO_OCR_MEM_READY) ||
554: ocr == 0)
555: break;
556: error = ETIMEDOUT;
557: sdmmc_delay(10000);
558: }
559: if (error == 0 && ocrp != NULL)
560: *ocrp = MMC_R4(cmd.c_resp);
561:
562: SDMMC_UNLOCK(sc);
563: return error;
564: }
565:
566: /*
567: * Card interrupt handling
568: */
569:
570: void
571: sdmmc_intr_enable(struct sdmmc_function *sf)
572: {
573: struct sdmmc_softc *sc = sf->sc;
574: struct sdmmc_function *sf0 = sc->sc_fn0;
575: u_int8_t imask;
576:
577: SDMMC_LOCK(sc);
578: imask = sdmmc_io_read_1(sf0, SD_IO_CCCR_INT_ENABLE);
579: imask |= 1 << sf->number;
580: sdmmc_io_write_1(sf0, SD_IO_CCCR_INT_ENABLE, imask);
581: SDMMC_UNLOCK(sc);
582: }
583:
584: void
585: sdmmc_intr_disable(struct sdmmc_function *sf)
586: {
587: struct sdmmc_softc *sc = sf->sc;
588: struct sdmmc_function *sf0 = sc->sc_fn0;
589: u_int8_t imask;
590:
591: SDMMC_LOCK(sc);
592: imask = sdmmc_io_read_1(sf0, SD_IO_CCCR_INT_ENABLE);
593: imask &= ~(1 << sf->number);
594: sdmmc_io_write_1(sf0, SD_IO_CCCR_INT_ENABLE, imask);
595: SDMMC_UNLOCK(sc);
596: }
597:
598: /*
599: * Establish a handler for the SDIO card interrupt. Because the
600: * interrupt may be shared with different SDIO functions, multiple
601: * handlers can be established.
602: */
603: void *
604: sdmmc_intr_establish(struct device *sdmmc, int (*fun)(void *),
605: void *arg, const char *name)
606: {
607: struct sdmmc_softc *sc = (struct sdmmc_softc *)sdmmc;
608: struct sdmmc_intr_handler *ih;
609: int s;
610:
611: if (sc->sct->card_intr_mask == NULL)
612: return NULL;
613:
614: ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK | M_CANFAIL);
615: if (ih == NULL)
616: return NULL;
617:
618: bzero(ih, sizeof *ih);
619: ih->ih_name = malloc(strlen(name), M_DEVBUF, M_WAITOK | M_CANFAIL);
620: if (ih->ih_name == NULL) {
621: free(ih, M_DEVBUF);
622: return NULL;
623: }
624: strlcpy(ih->ih_name, name, strlen(name));
625: ih->ih_softc = sc;
626: ih->ih_fun = fun;
627: ih->ih_arg = arg;
628:
629: s = splhigh();
630: if (TAILQ_EMPTY(&sc->sc_intrq)) {
631: sdmmc_intr_enable(sc->sc_fn0);
632: sdmmc_chip_card_intr_mask(sc->sct, sc->sch, 1);
633: }
634: TAILQ_INSERT_TAIL(&sc->sc_intrq, ih, entry);
635: splx(s);
636: return ih;
637: }
638:
639: /*
640: * Disestablish the given handler.
641: */
642: void
643: sdmmc_intr_disestablish(void *cookie)
644: {
645: struct sdmmc_intr_handler *ih = cookie;
646: struct sdmmc_softc *sc = ih->ih_softc;
647: int s;
648:
649: if (sc->sct->card_intr_mask == NULL)
650: return;
651:
652: s = splhigh();
653: TAILQ_REMOVE(&sc->sc_intrq, ih, entry);
654: if (TAILQ_EMPTY(&sc->sc_intrq)) {
655: sdmmc_chip_card_intr_mask(sc->sct, sc->sch, 0);
656: sdmmc_intr_disable(sc->sc_fn0);
657: }
658: splx(s);
659:
660: free(ih->ih_name, M_DEVBUF);
661: free(ih, M_DEVBUF);
662: }
663:
664: /*
665: * Call established SDIO card interrupt handlers. The host controller
666: * must call this function from its own interrupt handler to handle an
667: * SDIO interrupt from the card.
668: */
669: void
670: sdmmc_card_intr(struct device *sdmmc)
671: {
672: struct sdmmc_softc *sc = (struct sdmmc_softc *)sdmmc;
673:
674: if (sc->sct->card_intr_mask == NULL)
675: return;
676:
677: if (!sdmmc_task_pending(&sc->sc_intr_task))
678: sdmmc_add_task(sc, &sc->sc_intr_task);
679: }
680:
681: void
682: sdmmc_intr_task(void *arg)
683: {
684: struct sdmmc_softc *sc = arg;
685: struct sdmmc_intr_handler *ih;
686: int s;
687:
688: s = splhigh();
689: TAILQ_FOREACH(ih, &sc->sc_intrq, entry) {
690: splx(s);
691:
692: /* XXX examine return value and do evcount stuff*/
693: (void)ih->ih_fun(ih->ih_arg);
694:
695: s = splhigh();
696: }
697: sdmmc_chip_card_intr_ack(sc->sct, sc->sch);
698: splx(s);
699: }
CVSweb