Annotation of sys/dev/sdmmc/sbt.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sbt.c,v 1.9 2007/06/19 07:59:57 uwe Exp $ */
2:
3: /*
4: * Copyright (c) 2007 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: /* Driver for Type-A/B SDIO Bluetooth cards */
20:
21: #include <sys/param.h>
22: #include <sys/device.h>
23: #include <sys/malloc.h>
24: #include <sys/mbuf.h>
25: #include <sys/proc.h>
26: #include <sys/queue.h>
27: #include <sys/socket.h>
28: #include <sys/systm.h>
29:
30: #include <netbt/hci.h>
31:
32: #include <dev/sdmmc/sdmmcdevs.h>
33: #include <dev/sdmmc/sdmmcvar.h>
34:
35: #define CSR_READ_1(sc, reg) sdmmc_io_read_1((sc)->sc_sf, (reg))
36: #define CSR_WRITE_1(sc, reg, val) sdmmc_io_write_1((sc)->sc_sf, (reg), (val))
37:
38: #define SBT_REG_DAT 0x00 /* receiver/transmitter data */
39: #define SBT_REG_RPC 0x10 /* read packet control */
40: #define RPC_PCRRT (1<<0) /* packet read retry */
41: #define SBT_REG_WPC 0x11 /* write packet control */
42: #define WPC_PCWRT (1<<0) /* packet write retry */
43: #define SBT_REG_RC 0x12 /* retry control status/set */
44: #define SBT_REG_ISTAT 0x13 /* interrupt status */
45: #define ISTAT_INTRD (1<<0) /* packet available for read */
46: #define SBT_REG_ICLR 0x13 /* interrupt clear */
47: #define SBT_REG_IENA 0x14 /* interrupt enable */
48: #define SBT_REG_BTMODE 0x20 /* SDIO Bluetooth card mode */
49: #define BTMODE_TYPEB (1<<0) /* 1=Type-B, 0=Type-A */
50:
51: #define SBT_PKT_BUFSIZ 65540
52: #define SBT_RXTRY_MAX 5
53:
54: struct sbt_softc {
55: struct device sc_dev; /* base device */
56: struct hci_unit sc_unit; /* MI host controller */
57: struct sdmmc_function *sc_sf; /* SDIO function */
58: struct proc *sc_thread; /* inquiry thread */
59: int sc_dying; /* shutdown in progress */
60: void *sc_ih;
61: u_char *sc_buf;
62: int sc_rxtry;
63: };
64:
65: int sbt_match(struct device *, void *, void *);
66: void sbt_attach(struct device *, struct device *, void *);
67: int sbt_detach(struct device *, int);
68:
69: int sbt_write_packet(struct sbt_softc *, u_char *, size_t);
70: int sbt_read_packet(struct sbt_softc *, u_char *, size_t *);
71:
72: int sbt_intr(void *);
73:
74: int sbt_enable(struct hci_unit *);
75: void sbt_disable(struct hci_unit *);
76: void sbt_start(struct hci_unit *, struct ifqueue *, int);
77: void sbt_start_cmd(struct hci_unit *);
78: void sbt_start_acl(struct hci_unit *);
79: void sbt_start_sco(struct hci_unit *);
80:
81: #undef DPRINTF
82: #define SBT_DEBUG
83: #ifdef SBT_DEBUG
84: int sbt_debug = 1;
85: #define DPRINTF(s) printf s
86: #define DNPRINTF(n, s) do { if ((n) <= sbt_debug) printf s; } while (0)
87: #else
88: #define DPRINTF(s) do {} while (0)
89: #define DNPRINTF(n, s) do {} while (0)
90: #endif
91:
92: #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
93:
94: struct cfattach sbt_ca = {
95: sizeof(struct sbt_softc), sbt_match, sbt_attach, sbt_detach
96: };
97:
98: struct cfdriver sbt_cd = {
99: NULL, "sbt", DV_DULL
100: };
101:
102:
103: /*
104: * Autoconf glue
105: */
106:
107: static const struct sbt_product {
108: u_int16_t sp_vendor;
109: u_int16_t sp_product;
110: const char *sp_cisinfo[4];
111: } sbt_products[] = {
112: { SDMMC_VENDOR_SOCKETCOM,
113: SDMMC_PRODUCT_SOCKETCOM_BTCARD,
114: SDMMC_CIS_SOCKETCOM_BTCARD }
115: };
116:
117: int
118: sbt_match(struct device *parent, void *match, void *aux)
119: {
120: struct sdmmc_attach_args *sa = aux;
121: const struct sbt_product *sp;
122: struct sdmmc_function *sf;
123: int i;
124:
125: if (sa->sf == NULL)
126: return 0; /* not SDIO */
127:
128: sf = sa->sf->sc->sc_fn0;
129: sp = &sbt_products[0];
130:
131: for (i = 0; i < sizeof(sbt_products) / sizeof(sbt_products[0]);
132: i++, sp = &sbt_products[i])
133: if (sp->sp_vendor == sf->cis.manufacturer &&
134: sp->sp_product == sf->cis.product)
135: return 1;
136: return 0;
137: }
138:
139: void
140: sbt_attach(struct device *parent, struct device *self, void *aux)
141: {
142: struct sbt_softc *sc = (struct sbt_softc *)self;
143: struct sdmmc_attach_args *sa = aux;
144:
145: printf("\n");
146:
147: sc->sc_sf = sa->sf;
148:
149: (void)sdmmc_io_function_disable(sc->sc_sf);
150: if (sdmmc_io_function_enable(sc->sc_sf)) {
151: printf("%s: function not ready\n", DEVNAME(sc));
152: return;
153: }
154:
155: /* It may be Type-B, but we use it only in Type-A mode. */
156: printf("%s: SDIO Bluetooth Type-A\n", DEVNAME(sc));
157:
158: sc->sc_buf = malloc(SBT_PKT_BUFSIZ, M_DEVBUF,
159: M_NOWAIT | M_CANFAIL);
160: if (sc->sc_buf == NULL) {
161: printf("%s: can't allocate cmd buffer\n", DEVNAME(sc));
162: return;
163: }
164:
165: /* Enable the HCI packet transport read interrupt. */
166: CSR_WRITE_1(sc, SBT_REG_IENA, ISTAT_INTRD);
167:
168: /* Enable the card interrupt for this function. */
169: sc->sc_ih = sdmmc_intr_establish(parent, sbt_intr, sc, DEVNAME(sc));
170: if (sc->sc_ih == NULL) {
171: printf("%s: can't establish interrupt\n", DEVNAME(sc));
172: return;
173: }
174: sdmmc_intr_enable(sc->sc_sf);
175:
176: /*
177: * Attach Bluetooth unit (machine-independent HCI).
178: */
179: sc->sc_unit.hci_softc = self;
180: sc->sc_unit.hci_devname = DEVNAME(sc);
181: sc->sc_unit.hci_enable = sbt_enable;
182: sc->sc_unit.hci_disable = sbt_disable;
183: sc->sc_unit.hci_start_cmd = sbt_start_cmd;
184: sc->sc_unit.hci_start_acl = sbt_start_acl;
185: sc->sc_unit.hci_start_sco = sbt_start_sco;
186: sc->sc_unit.hci_ipl = IPL_TTY; /* XXX */
187: hci_attach(&sc->sc_unit);
188: }
189:
190: int
191: sbt_detach(struct device *self, int flags)
192: {
193: struct sbt_softc *sc = (struct sbt_softc *)self;
194:
195: sc->sc_dying = 1;
196: while (sc->sc_thread != NULL)
197: tsleep(sc, PWAIT, "dying", 0);
198:
199: hci_detach(&sc->sc_unit);
200:
201: if (sc->sc_ih != NULL)
202: sdmmc_intr_disestablish(sc->sc_ih);
203:
204: return 0;
205: }
206:
207:
208: /*
209: * Bluetooth HCI packet transport
210: */
211:
212: int
213: sbt_write_packet(struct sbt_softc *sc, u_char *buf, size_t len)
214: {
215: u_char hdr[3];
216: size_t pktlen;
217: int error = EIO;
218: int retry = 3;
219:
220: again:
221: if (retry-- == 0) {
222: DPRINTF(("%s: sbt_write_cmd: giving up\n", DEVNAME(sc)));
223: return error;
224: }
225:
226: /* Restart the current packet. */
227: sdmmc_io_write_1(sc->sc_sf, SBT_REG_WPC, WPC_PCWRT);
228:
229: /* Write the packet length. */
230: pktlen = len + 3;
231: hdr[0] = pktlen & 0xff;
232: hdr[1] = (pktlen >> 8) & 0xff;
233: hdr[2] = (pktlen >> 16) & 0xff;
234: error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
235: if (error) {
236: DPRINTF(("%s: sbt_write_packet: failed to send length\n",
237: DEVNAME(sc)));
238: goto again;
239: }
240:
241: error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
242: if (error) {
243: DPRINTF(("%s: sbt_write_packet: failed to send packet data\n",
244: DEVNAME(sc)));
245: goto again;
246: }
247: return 0;
248: }
249:
250: int
251: sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp)
252: {
253: u_char hdr[3];
254: size_t len;
255: int error;
256:
257: error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
258: if (error) {
259: DPRINTF(("%s: sbt_read_packet: failed to read length\n",
260: DEVNAME(sc)));
261: goto out;
262: }
263: len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3;
264: if (len > *lenp) {
265: DPRINTF(("%s: sbt_read_packet: len %u > %u\n",
266: DEVNAME(sc), len, *lenp));
267: error = ENOBUFS;
268: goto out;
269: }
270:
271: DNPRINTF(2,("%s: sbt_read_packet: reading len %u bytes\n",
272: DEVNAME(sc), len));
273: error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
274: if (error) {
275: DPRINTF(("%s: sbt_read_packet: failed to read packet data\n",
276: DEVNAME(sc)));
277: goto out;
278: }
279:
280: out:
281: if (error) {
282: if (sc->sc_rxtry >= SBT_RXTRY_MAX) {
283: /* Drop and request the next packet. */
284: sc->sc_rxtry = 0;
285: CSR_WRITE_1(sc, SBT_REG_RPC, 0);
286: } else {
287: /* Request the current packet again. */
288: sc->sc_rxtry++;
289: CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT);
290: }
291: return error;
292: }
293:
294: /* acknowledge read packet */
295: CSR_WRITE_1(sc, SBT_REG_RPC, 0);
296:
297: *lenp = len;
298: return 0;
299: }
300:
301: /*
302: * Interrupt handling
303: */
304:
305: int
306: sbt_intr(void *arg)
307: {
308: struct sbt_softc *sc = arg;
309: struct mbuf *m = NULL;
310: u_int8_t status;
311: size_t len;
312: int s;
313:
314: s = splsdmmc();
315:
316: status = CSR_READ_1(sc, SBT_REG_ISTAT);
317: CSR_WRITE_1(sc, SBT_REG_ICLR, status);
318:
319: if ((status & ISTAT_INTRD) == 0)
320: return 0; /* shared SDIO card interrupt? */
321:
322: len = SBT_PKT_BUFSIZ;
323: if (sbt_read_packet(sc, sc->sc_buf, &len) != 0 || len == 0) {
324: DPRINTF(("%s: sbt_intr: read failed\n", DEVNAME(sc)));
325: goto eoi;
326: }
327:
328: MGETHDR(m, M_DONTWAIT, MT_DATA);
329: if (m == NULL) {
330: DPRINTF(("%s: sbt_intr: MGETHDR failed\n", DEVNAME(sc)));
331: goto eoi;
332: }
333:
334: m->m_pkthdr.len = m->m_len = MHLEN;
335: m_copyback(m, 0, len, sc->sc_buf);
336: if (m->m_pkthdr.len == MAX(MHLEN, len)) {
337: m->m_pkthdr.len = len;
338: m->m_len = MIN(MHLEN, m->m_pkthdr.len);
339: } else {
340: DPRINTF(("%s: sbt_intr: m_copyback failed\n", DEVNAME(sc)));
341: m_free(m);
342: m = NULL;
343: }
344:
345: eoi:
346: if (m != NULL) {
347: switch (sc->sc_buf[0]) {
348: case HCI_ACL_DATA_PKT:
349: DNPRINTF(1,("%s: recv ACL packet (%d bytes)\n",
350: DEVNAME(sc), m->m_pkthdr.len));
351: hci_input_acl(&sc->sc_unit, m);
352: break;
353: case HCI_SCO_DATA_PKT:
354: DNPRINTF(1,("%s: recv SCO packet (%d bytes)\n",
355: DEVNAME(sc), m->m_pkthdr.len));
356: hci_input_sco(&sc->sc_unit, m);
357: break;
358: case HCI_EVENT_PKT:
359: DNPRINTF(1,("%s: recv EVENT packet (%d bytes)\n",
360: DEVNAME(sc), m->m_pkthdr.len));
361: hci_input_event(&sc->sc_unit, m);
362: break;
363: default:
364: DPRINTF(("%s: recv 0x%x packet (%d bytes)\n",
365: DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len));
366: sc->sc_unit.hci_stats.err_rx++;
367: m_free(m);
368: break;
369: }
370: } else
371: sc->sc_unit.hci_stats.err_rx++;
372:
373: splx(s);
374:
375: /* Claim this interrupt. */
376: return 1;
377: }
378:
379:
380: /*
381: * Bluetooth HCI unit functions
382: */
383:
384: int
385: sbt_enable(struct hci_unit *unit)
386: {
387: if (unit->hci_flags & BTF_RUNNING)
388: return 0;
389:
390: unit->hci_flags |= BTF_RUNNING;
391: unit->hci_flags &= ~BTF_XMIT;
392: return 0;
393: }
394:
395: void
396: sbt_disable(struct hci_unit *unit)
397: {
398: if (!(unit->hci_flags & BTF_RUNNING))
399: return;
400:
401: #ifdef notyet /* XXX */
402: if (sc->sc_rxp) {
403: m_freem(sc->sc_rxp);
404: sc->sc_rxp = NULL;
405: }
406:
407: if (sc->sc_txp) {
408: m_freem(sc->sc_txp);
409: sc->sc_txp = NULL;
410: }
411: #endif
412:
413: unit->hci_flags &= ~BTF_RUNNING;
414: }
415:
416: void
417: sbt_start(struct hci_unit *unit, struct ifqueue *q, int xmit)
418: {
419: struct sbt_softc *sc = (struct sbt_softc *)unit->hci_softc;
420: struct mbuf *m;
421: int len;
422: #ifdef SBT_DEBUG
423: const char *what;
424: #endif
425:
426: if (sc->sc_dying || IF_IS_EMPTY(q))
427: return;
428:
429: IF_DEQUEUE(q, m);
430:
431: #ifdef SBT_DEBUG
432: switch (xmit) {
433: case BTF_XMIT_CMD:
434: what = "CMD";
435: break;
436: case BTF_XMIT_ACL:
437: what = "ACL";
438: break;
439: case BTF_XMIT_SCO:
440: what = "SCO";
441: break;
442: }
443: DNPRINTF(1,("%s: xmit %s packet (%d bytes)\n", DEVNAME(sc),
444: what, m->m_pkthdr.len));
445: #endif
446:
447: unit->hci_flags |= xmit;
448:
449: len = m->m_pkthdr.len;
450: m_copydata(m, 0, len, sc->sc_buf);
451: m_freem(m);
452:
453: if (sbt_write_packet(sc, sc->sc_buf, len))
454: DPRINTF(("%s: sbt_write_packet failed\n", DEVNAME(sc)));
455:
456: unit->hci_flags &= ~xmit;
457: }
458:
459: void
460: sbt_start_cmd(struct hci_unit *unit)
461: {
462: sbt_start(unit, &unit->hci_cmdq, BTF_XMIT_CMD);
463: }
464:
465: void
466: sbt_start_acl(struct hci_unit *unit)
467: {
468: sbt_start(unit, &unit->hci_acltxq, BTF_XMIT_ACL);
469: }
470:
471: void
472: sbt_start_sco(struct hci_unit *unit)
473: {
474: sbt_start(unit, &unit->hci_scotxq, BTF_XMIT_SCO);
475: }
CVSweb