Home | History | Annotate | Line # | Download | only in sdmmc
sbt.c revision 1.1
      1 /*	$NetBSD: sbt.c,v 1.1 2009/04/21 03:00:30 nonaka Exp $	*/
      2 /*	$OpenBSD: sbt.c,v 1.9 2007/06/19 07:59:57 uwe Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2007 Uwe Stuehler <uwe (at) openbsd.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 /* Driver for Type-A/B SDIO Bluetooth cards */
     21 
     22 #include <sys/cdefs.h>
     23 __KERNEL_RCSID(0, "$NetBSD: sbt.c,v 1.1 2009/04/21 03:00:30 nonaka Exp $");
     24 
     25 #include <sys/param.h>
     26 #include <sys/device.h>
     27 #include <sys/malloc.h>
     28 #include <sys/mbuf.h>
     29 #include <sys/proc.h>
     30 #include <sys/queue.h>
     31 #include <sys/socket.h>
     32 #include <sys/systm.h>
     33 
     34 #include <netbt/hci.h>
     35 
     36 #include <dev/sdmmc/sdmmcdevs.h>
     37 #include <dev/sdmmc/sdmmcvar.h>
     38 
     39 #define CSR_READ_1(sc, reg)       sdmmc_io_read_1((sc)->sc_sf, (reg))
     40 #define CSR_WRITE_1(sc, reg, val) sdmmc_io_write_1((sc)->sc_sf, (reg), (val))
     41 
     42 #define SBT_REG_DAT	0x00		/* receiver/transmitter data */
     43 #define SBT_REG_RPC	0x10		/* read packet control */
     44 #define  RPC_PCRRT	(1<<0)		/* packet read retry */
     45 #define SBT_REG_WPC	0x11		/* write packet control */
     46 #define  WPC_PCWRT	(1<<0)		/* packet write retry */
     47 #define SBT_REG_RC	0x12		/* retry control status/set */
     48 #define SBT_REG_ISTAT	0x13		/* interrupt status */
     49 #define  ISTAT_INTRD	(1<<0)		/* packet available for read */
     50 #define SBT_REG_ICLR	0x13		/* interrupt clear */
     51 #define SBT_REG_IENA	0x14		/* interrupt enable */
     52 #define SBT_REG_BTMODE	0x20		/* SDIO Bluetooth card mode */
     53 #define  BTMODE_TYPEB	(1<<0)		/* 1=Type-B, 0=Type-A */
     54 
     55 #define SBT_PKT_BUFSIZ	65540
     56 #define SBT_RXTRY_MAX	5
     57 
     58 struct sbt_softc {
     59 	device_t sc_dev;		/* base device */
     60 	int sc_flags;
     61 	struct hci_unit *sc_unit;	/* Bluetooth HCI Unit */
     62 	struct bt_stats sc_stats;
     63 	struct sdmmc_function *sc_sf;	/* SDIO function */
     64 	int sc_dying;			/* shutdown in progress */
     65 	void *sc_ih;
     66 	u_char *sc_buf;
     67 	int sc_rxtry;
     68 
     69 	/* transmit queues */
     70 	MBUFQ_HEAD() sc_cmdq;
     71 	MBUFQ_HEAD() sc_aclq;
     72 	MBUFQ_HEAD() sc_scoq;
     73 };
     74 
     75 /* sc_flags */
     76 #define SBT_XMIT	(1 << 0)	/* transmit is active */
     77 #define SBT_ENABLED	(1 << 1)	/* device is enabled */
     78 
     79 static int	sbt_match(device_t, struct cfdata *, void *);
     80 static void	sbt_attach(device_t, device_t, void *);
     81 static int	sbt_detach(device_t, int);
     82 
     83 CFATTACH_DECL_NEW(sbt, sizeof(struct sbt_softc),
     84     sbt_match, sbt_attach, sbt_detach, NULL);
     85 
     86 static int	sbt_write_packet(struct sbt_softc *, u_char *, size_t);
     87 static int	sbt_read_packet(struct sbt_softc *, u_char *, size_t *);
     88 static void	sbt_start(struct sbt_softc *);
     89 
     90 static int	sbt_intr(void *);
     91 
     92 static int	sbt_enable(device_t);
     93 static void	sbt_disable(device_t);
     94 static void	sbt_start_cmd(device_t, struct mbuf *);
     95 static void	sbt_start_acl(device_t, struct mbuf *);
     96 static void	sbt_start_sco(device_t, struct mbuf *);
     97 static void	sbt_stats(device_t, struct bt_stats *, int);
     98 
     99 #undef DPRINTF	/* avoid redefine by bluetooth.h */
    100 #ifdef SBT_DEBUG
    101 int sbt_debug = 1;
    102 #define DPRINTF(s)	printf s
    103 #define DNPRINTF(n, s)	do { if ((n) <= sbt_debug) printf s; } while (0)
    104 #else
    105 #define DPRINTF(s)	do {} while (0)
    106 #define DNPRINTF(n, s)	do {} while (0)
    107 #endif
    108 
    109 #define DEVNAME(sc)	device_xname((sc)->sc_dev)
    110 
    111 
    112 /*
    113  * Autoconf glue
    114  */
    115 
    116 static const struct sbt_product {
    117 	uint16_t	sp_vendor;
    118 	uint16_t	sp_product;
    119 	const char	*sp_cisinfo[4];
    120 } sbt_products[] = {
    121 	{
    122 		SDMMC_VENDOR_SOCKETCOM,
    123 		SDMMC_PRODUCT_SOCKETCOM_BTCARD,
    124 		SDMMC_CIS_SOCKETCOM_BTCARD
    125 	},
    126 };
    127 
    128 static const struct hci_if sbt_hci = {
    129 	.enable = sbt_enable,
    130 	.disable = sbt_disable,
    131 	.output_cmd = sbt_start_cmd,
    132 	.output_acl = sbt_start_acl,
    133 	.output_sco = sbt_start_sco,
    134 	.get_stats = sbt_stats,
    135 	.ipl = IPL_TTY,			/* XXX */
    136 };
    137 
    138 
    139 static int
    140 sbt_match(device_t parent, struct cfdata *match, void *aux)
    141 {
    142 	struct sdmmc_attach_args *sa = aux;
    143 	const struct sbt_product *sp;
    144 	struct sdmmc_function *sf;
    145 	int i;
    146 
    147 	if (sa->sf == NULL)
    148 		return 0;	/* not SDIO */
    149 
    150 	sf = sa->sf->sc->sc_fn0;
    151 	sp = &sbt_products[0];
    152 
    153 	for (i = 0; i < sizeof(sbt_products) / sizeof(sbt_products[0]);
    154 	     i++, sp = &sbt_products[i])
    155 		if (sp->sp_vendor == sf->cis.manufacturer &&
    156 		    sp->sp_product == sf->cis.product)
    157 			return 1;
    158 	return 0;
    159 }
    160 
    161 static void
    162 sbt_attach(device_t parent, device_t self, void *aux)
    163 {
    164 	struct sbt_softc *sc = device_private(self);
    165 	struct sdmmc_attach_args *sa = aux;
    166 
    167 	aprint_normal("\n");
    168 	aprint_naive("\n");
    169 
    170 	sc->sc_dev = self;
    171 	sc->sc_sf = sa->sf;
    172 	MBUFQ_INIT(&sc->sc_cmdq);
    173 	MBUFQ_INIT(&sc->sc_aclq);
    174 	MBUFQ_INIT(&sc->sc_scoq);
    175 
    176 	(void)sdmmc_io_function_disable(sc->sc_sf);
    177 	if (sdmmc_io_function_enable(sc->sc_sf)) {
    178 		printf("%s: function not ready\n", DEVNAME(sc));
    179 		return;
    180 	}
    181 
    182 	/* It may be Type-B, but we use it only in Type-A mode. */
    183 	printf("%s: SDIO Bluetooth Type-A\n", DEVNAME(sc));
    184 
    185 	sc->sc_buf = malloc(SBT_PKT_BUFSIZ, M_DEVBUF, M_NOWAIT | M_CANFAIL);
    186 	if (sc->sc_buf == NULL) {
    187 		printf("%s: can't allocate cmd buffer\n", DEVNAME(sc));
    188 		return;
    189 	}
    190 
    191 	/* Enable the HCI packet transport read interrupt. */
    192 	CSR_WRITE_1(sc, SBT_REG_IENA, ISTAT_INTRD);
    193 
    194 	/* Enable the card interrupt for this function. */
    195 	sc->sc_ih = sdmmc_intr_establish(parent, sbt_intr, sc, DEVNAME(sc));
    196 	if (sc->sc_ih == NULL) {
    197 		printf("%s: can't establish interrupt\n", DEVNAME(sc));
    198 		return;
    199 	}
    200 	sdmmc_intr_enable(sc->sc_sf);
    201 
    202 	/*
    203 	 * Attach Bluetooth unit (machine-independent HCI).
    204 	 */
    205 	sc->sc_unit = hci_attach(&sbt_hci, self, 0);
    206 }
    207 
    208 static int
    209 sbt_detach(device_t self, int flags)
    210 {
    211 	struct sbt_softc *sc = (struct sbt_softc *)self;
    212 
    213 	sc->sc_dying = 1;
    214 
    215 	if (sc->sc_unit) {
    216 		hci_detach(sc->sc_unit);
    217 		sc->sc_unit = NULL;
    218 	}
    219 
    220 	if (sc->sc_ih != NULL)
    221 		sdmmc_intr_disestablish(sc->sc_ih);
    222 
    223 	return 0;
    224 }
    225 
    226 
    227 /*
    228  * Bluetooth HCI packet transport
    229  */
    230 
    231 static int
    232 sbt_write_packet(struct sbt_softc *sc, u_char *buf, size_t len)
    233 {
    234 	u_char hdr[3];
    235 	size_t pktlen;
    236 	int error = EIO;
    237 	int retry = 3;
    238 
    239 again:
    240 	if (retry-- == 0) {
    241 		DPRINTF(("%s: sbt_write_cmd: giving up\n", DEVNAME(sc)));
    242 		return error;
    243 	}
    244 
    245 	/* Restart the current packet. */
    246 	sdmmc_io_write_1(sc->sc_sf, SBT_REG_WPC, WPC_PCWRT);
    247 
    248 	/* Write the packet length. */
    249 	pktlen = len + 3;
    250 	hdr[0] = pktlen & 0xff;
    251 	hdr[1] = (pktlen >> 8) & 0xff;
    252 	hdr[2] = (pktlen >> 16) & 0xff;
    253 	error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
    254 	if (error) {
    255 		DPRINTF(("%s: sbt_write_packet: failed to send length\n",
    256 		    DEVNAME(sc)));
    257 		goto again;
    258 	}
    259 
    260 	error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
    261 	if (error) {
    262 		DPRINTF(("%s: sbt_write_packet: failed to send packet data\n",
    263 		    DEVNAME(sc)));
    264 		goto again;
    265 	}
    266 	return 0;
    267 }
    268 
    269 static int
    270 sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp)
    271 {
    272 	u_char hdr[3];
    273 	size_t len;
    274 	int error;
    275 
    276 	error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
    277 	if (error) {
    278 		DPRINTF(("%s: sbt_read_packet: failed to read length\n",
    279 		    DEVNAME(sc)));
    280 		goto out;
    281 	}
    282 	len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3;
    283 	if (len > *lenp) {
    284 		DPRINTF(("%s: sbt_read_packet: len %u > %u\n",
    285 		    DEVNAME(sc), len, *lenp));
    286 		error = ENOBUFS;
    287 		goto out;
    288 	}
    289 
    290 	DNPRINTF(2,("%s: sbt_read_packet: reading len %u bytes\n",
    291 	    DEVNAME(sc), len));
    292 	error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
    293 	if (error) {
    294 		DPRINTF(("%s: sbt_read_packet: failed to read packet data\n",
    295 		    DEVNAME(sc)));
    296 		goto out;
    297 	}
    298 
    299 out:
    300 	if (error) {
    301 		if (sc->sc_rxtry >= SBT_RXTRY_MAX) {
    302 			/* Drop and request the next packet. */
    303 			sc->sc_rxtry = 0;
    304 			CSR_WRITE_1(sc, SBT_REG_RPC, 0);
    305 		} else {
    306 			/* Request the current packet again. */
    307 			sc->sc_rxtry++;
    308 			CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT);
    309 		}
    310 		return error;
    311 	}
    312 
    313 	/* acknowledge read packet */
    314 	CSR_WRITE_1(sc, SBT_REG_RPC, 0);
    315 
    316 	*lenp = len;
    317 	return 0;
    318 }
    319 
    320 /*
    321  * Interrupt handling
    322  */
    323 
    324 static int
    325 sbt_intr(void *arg)
    326 {
    327 	struct sbt_softc *sc = arg;
    328 	struct mbuf *m = NULL;
    329 	u_int8_t status;
    330 	size_t len;
    331 	int s;
    332 
    333 	s = splsdmmc();
    334 
    335 	status = CSR_READ_1(sc, SBT_REG_ISTAT);
    336 	CSR_WRITE_1(sc, SBT_REG_ICLR, status);
    337 
    338 	if ((status & ISTAT_INTRD) == 0)
    339 		return 0;	/* shared SDIO card interrupt? */
    340 
    341 	len = SBT_PKT_BUFSIZ;
    342 	if (sbt_read_packet(sc, sc->sc_buf, &len) != 0 || len == 0) {
    343 		DPRINTF(("%s: sbt_intr: read failed\n", DEVNAME(sc)));
    344 		goto eoi;
    345 	}
    346 
    347 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    348 	if (m == NULL) {
    349 		DPRINTF(("%s: sbt_intr: MGETHDR failed\n", DEVNAME(sc)));
    350 		goto eoi;
    351 	}
    352 
    353 	m->m_pkthdr.len = m->m_len = MHLEN;
    354 	m_copyback(m, 0, len, sc->sc_buf);
    355 	if (m->m_pkthdr.len == MAX(MHLEN, len)) {
    356 		m->m_pkthdr.len = len;
    357 		m->m_len = MIN(MHLEN, m->m_pkthdr.len);
    358 	} else {
    359 		DPRINTF(("%s: sbt_intr: m_copyback failed\n", DEVNAME(sc)));
    360 		m_free(m);
    361 		m = NULL;
    362 	}
    363 
    364 eoi:
    365 	if (m != NULL) {
    366 		switch (sc->sc_buf[0]) {
    367 		case HCI_ACL_DATA_PKT:
    368 			DNPRINTF(1,("%s: recv ACL packet (%d bytes)\n",
    369 			    DEVNAME(sc), m->m_pkthdr.len));
    370 			hci_input_acl(sc->sc_unit, m);
    371 			break;
    372 		case HCI_SCO_DATA_PKT:
    373 			DNPRINTF(1,("%s: recv SCO packet (%d bytes)\n",
    374 			    DEVNAME(sc), m->m_pkthdr.len));
    375 			hci_input_sco(sc->sc_unit, m);
    376 			break;
    377 		case HCI_EVENT_PKT:
    378 			DNPRINTF(1,("%s: recv EVENT packet (%d bytes)\n",
    379 			    DEVNAME(sc), m->m_pkthdr.len));
    380 			hci_input_event(sc->sc_unit, m);
    381 			break;
    382 		default:
    383 			DPRINTF(("%s: recv 0x%x packet (%d bytes)\n",
    384 			    DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len));
    385 			sc->sc_stats.err_rx++;
    386 			m_free(m);
    387 			break;
    388 		}
    389 	} else
    390 		sc->sc_stats.err_rx++;
    391 
    392 	splx(s);
    393 
    394 	/* Claim this interrupt. */
    395 	return 1;
    396 }
    397 
    398 
    399 /*
    400  * Bluetooth HCI unit functions
    401  */
    402 
    403 static int
    404 sbt_enable(device_t self)
    405 {
    406 	struct sbt_softc *sc = device_private(self);
    407 	int s;
    408 
    409 	if (sc->sc_flags & SBT_ENABLED)
    410 		return 0;
    411 
    412 	s = spltty();
    413 
    414 	sc->sc_flags |= SBT_ENABLED;
    415 	sc->sc_flags &= ~SBT_XMIT;
    416 
    417 	splx(s);
    418 
    419 	return 0;
    420 }
    421 
    422 static void
    423 sbt_disable(device_t self)
    424 {
    425 	struct sbt_softc *sc = device_private(self);
    426 	int s;
    427 
    428 	if (!(sc->sc_flags & SBT_ENABLED))
    429 		return;
    430 
    431 	s = spltty();
    432 
    433 #ifdef notyet			/* XXX */
    434 	if (sc->sc_rxp) {
    435 		m_freem(sc->sc_rxp);
    436 		sc->sc_rxp = NULL;
    437 	}
    438 
    439 	if (sc->sc_txp) {
    440 		m_freem(sc->sc_txp);
    441 		sc->sc_txp = NULL;
    442 	}
    443 #endif
    444 
    445 	MBUFQ_DRAIN(&sc->sc_cmdq);
    446 	MBUFQ_DRAIN(&sc->sc_aclq);
    447 	MBUFQ_DRAIN(&sc->sc_scoq);
    448 
    449 	sc->sc_flags &= ~SBT_ENABLED;
    450 
    451 	splx(s);
    452 }
    453 
    454 static void
    455 sbt_start(struct sbt_softc *sc)
    456 {
    457 	struct mbuf *m;
    458 	int len;
    459 #ifdef SBT_DEBUG
    460 	const char *what;
    461 #endif
    462 
    463 	KASSERT((sc->sc_flags & SBT_XMIT) == 0);
    464 
    465 	if (sc->sc_dying)
    466 		return;
    467 
    468 	if (MBUFQ_FIRST(&sc->sc_cmdq)) {
    469 		MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
    470 		sc->sc_stats.cmd_tx++;
    471 #ifdef SBT_DEBUG
    472 		what = "CMD";
    473 #endif
    474 		goto start;
    475 	}
    476 
    477 	if (MBUFQ_FIRST(&sc->sc_scoq)) {
    478 		MBUFQ_DEQUEUE(&sc->sc_scoq, m);
    479 		sc->sc_stats.sco_tx++;
    480 #ifdef SBT_DEBUG
    481 		what = "SCO";
    482 #endif
    483 		goto start;
    484 	}
    485 
    486 	if (MBUFQ_FIRST(&sc->sc_aclq)) {
    487 		MBUFQ_DEQUEUE(&sc->sc_aclq, m);
    488 		sc->sc_stats.acl_tx++;
    489 #ifdef SBT_DEBUG
    490 		what = "ACL";
    491 #endif
    492 		goto start;
    493 	}
    494 
    495 	/* Nothing to send */
    496 	return;
    497 
    498 start:
    499 	DNPRINTF(1,("%s: xmit %s packet (%d bytes)\n", DEVNAME(sc),
    500 	    what, m->m_pkthdr.len));
    501 
    502 	sc->sc_flags |= SBT_XMIT;
    503 
    504 	len = m->m_pkthdr.len;
    505 	m_copydata(m, 0, len, sc->sc_buf);
    506 	m_freem(m);
    507 
    508 	if (sbt_write_packet(sc, sc->sc_buf, len))
    509 		DPRINTF(("%s: sbt_write_packet failed\n", DEVNAME(sc)));
    510 
    511 	sc->sc_flags &= ~SBT_XMIT;
    512 }
    513 
    514 static void
    515 sbt_start_cmd(device_t self, struct mbuf *m)
    516 {
    517 	struct sbt_softc *sc = device_private(self);
    518 	int s;
    519 
    520 	KASSERT(sc->sc_flags & SBT_ENABLED);
    521 
    522 	M_SETCTX(m, NULL);
    523 
    524 	s = spltty();
    525 
    526 	MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
    527 	if ((sc->sc_flags & SBT_XMIT) == 0)
    528 		sbt_start(sc);
    529 
    530 	splx(s);
    531 }
    532 
    533 static void
    534 sbt_start_acl(device_t self, struct mbuf *m)
    535 {
    536 	struct sbt_softc *sc = device_private(self);
    537 	int s;
    538 
    539 	KASSERT(sc->sc_flags & SBT_ENABLED);
    540 
    541 	M_SETCTX(m, NULL);
    542 
    543 	s = spltty();
    544 
    545 	MBUFQ_ENQUEUE(&sc->sc_aclq, m);
    546 	if ((sc->sc_flags & SBT_XMIT) == 0)
    547 		sbt_start(sc);
    548 
    549 	splx(s);
    550 }
    551 
    552 static void
    553 sbt_start_sco(device_t self, struct mbuf *m)
    554 {
    555 	struct sbt_softc *sc = device_private(self);
    556 	int s;
    557 
    558 	KASSERT(sc->sc_flags & SBT_ENABLED);
    559 
    560 	s = spltty();
    561 
    562 	MBUFQ_ENQUEUE(&sc->sc_scoq, m);
    563 	if ((sc->sc_flags & SBT_XMIT) == 0)
    564 		sbt_start(sc);
    565 
    566 	splx(s);
    567 }
    568 
    569 static void
    570 sbt_stats(device_t self, struct bt_stats *dest, int flush)
    571 {
    572 	struct sbt_softc *sc = device_private(self);
    573 	int s;
    574 
    575 	s = spltty();
    576 
    577 	memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
    578 
    579 	if (flush)
    580 		memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
    581 
    582 	splx(s);
    583 }
    584