Home | History | Annotate | Line # | Download | only in sdmmc
      1 /*	$NetBSD: sbt.c,v 1.9 2024/07/05 04:31:52 rin 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.9 2024/07/05 04:31:52 rin 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, cfdata_t, 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, cfdata_t 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 		aprint_error("%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_WAITOK);
    186 
    187 	/* Enable the HCI packet transport read interrupt. */
    188 	CSR_WRITE_1(sc, SBT_REG_IENA, ISTAT_INTRD);
    189 
    190 	/* Enable the card interrupt for this function. */
    191 	sc->sc_ih = sdmmc_intr_establish(parent, sbt_intr, sc, DEVNAME(sc));
    192 	if (sc->sc_ih == NULL) {
    193 		aprint_error("%s: can't establish interrupt\n", DEVNAME(sc));
    194 		return;
    195 	}
    196 	sdmmc_intr_enable(sc->sc_sf);
    197 
    198 	/*
    199 	 * Attach Bluetooth unit (machine-independent HCI).
    200 	 */
    201 	sc->sc_unit = hci_attach_pcb(&sbt_hci, self, 0);
    202 }
    203 
    204 static int
    205 sbt_detach(device_t self, int flags)
    206 {
    207 	struct sbt_softc *sc = device_private(self);
    208 
    209 	sc->sc_dying = 1;
    210 
    211 	if (sc->sc_unit) {
    212 		hci_detach_pcb(sc->sc_unit);
    213 		sc->sc_unit = NULL;
    214 	}
    215 
    216 	if (sc->sc_ih != NULL)
    217 		sdmmc_intr_disestablish(sc->sc_ih);
    218 
    219 	return 0;
    220 }
    221 
    222 
    223 /*
    224  * Bluetooth HCI packet transport
    225  */
    226 
    227 static int
    228 sbt_write_packet(struct sbt_softc *sc, u_char *buf, size_t len)
    229 {
    230 	u_char hdr[3];
    231 	size_t pktlen;
    232 	int error = EIO;
    233 	int retry = 3;
    234 
    235 again:
    236 	if (retry-- == 0) {
    237 		DPRINTF(("%s: sbt_write_cmd: giving up\n", DEVNAME(sc)));
    238 		return error;
    239 	}
    240 
    241 	/* Restart the current packet. */
    242 	sdmmc_io_write_1(sc->sc_sf, SBT_REG_WPC, WPC_PCWRT);
    243 
    244 	/* Write the packet length. */
    245 	pktlen = len + 3;
    246 	hdr[0] = pktlen & 0xff;
    247 	hdr[1] = (pktlen >> 8) & 0xff;
    248 	hdr[2] = (pktlen >> 16) & 0xff;
    249 	error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
    250 	if (error) {
    251 		DPRINTF(("%s: sbt_write_packet: failed to send length\n",
    252 		    DEVNAME(sc)));
    253 		goto again;
    254 	}
    255 
    256 	error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
    257 	if (error) {
    258 		DPRINTF(("%s: sbt_write_packet: failed to send packet data\n",
    259 		    DEVNAME(sc)));
    260 		goto again;
    261 	}
    262 	return 0;
    263 }
    264 
    265 static int
    266 sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp)
    267 {
    268 	u_char hdr[3];
    269 	size_t len;
    270 	int error;
    271 
    272 	error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3);
    273 	if (error) {
    274 		DPRINTF(("%s: sbt_read_packet: failed to read length\n",
    275 		    DEVNAME(sc)));
    276 		goto out;
    277 	}
    278 	len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3;
    279 	if (len > *lenp) {
    280 		DPRINTF(("%s: sbt_read_packet: len %u > %u\n",
    281 		    DEVNAME(sc), len, *lenp));
    282 		error = ENOBUFS;
    283 		goto out;
    284 	}
    285 
    286 	DNPRINTF(2,("%s: sbt_read_packet: reading len %u bytes\n",
    287 	    DEVNAME(sc), len));
    288 	error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len);
    289 	if (error) {
    290 		DPRINTF(("%s: sbt_read_packet: failed to read packet data\n",
    291 		    DEVNAME(sc)));
    292 		goto out;
    293 	}
    294 
    295 out:
    296 	if (error) {
    297 		if (sc->sc_rxtry >= SBT_RXTRY_MAX) {
    298 			/* Drop and request the next packet. */
    299 			sc->sc_rxtry = 0;
    300 			CSR_WRITE_1(sc, SBT_REG_RPC, 0);
    301 		} else {
    302 			/* Request the current packet again. */
    303 			sc->sc_rxtry++;
    304 			CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT);
    305 		}
    306 		return error;
    307 	}
    308 
    309 	/* acknowledge read packet */
    310 	CSR_WRITE_1(sc, SBT_REG_RPC, 0);
    311 
    312 	*lenp = len;
    313 	return 0;
    314 }
    315 
    316 /*
    317  * Interrupt handling
    318  */
    319 
    320 static int
    321 sbt_intr(void *arg)
    322 {
    323 	struct sbt_softc *sc = arg;
    324 	struct mbuf *m = NULL;
    325 	u_int8_t status;
    326 	size_t len;
    327 	int s;
    328 
    329 	s = splsdmmc();
    330 
    331 	status = CSR_READ_1(sc, SBT_REG_ISTAT);
    332 	CSR_WRITE_1(sc, SBT_REG_ICLR, status);
    333 
    334 	if ((status & ISTAT_INTRD) == 0)
    335 		return 0;	/* shared SDIO card interrupt? */
    336 
    337 	len = SBT_PKT_BUFSIZ;
    338 	if (sbt_read_packet(sc, sc->sc_buf, &len) != 0 || len == 0) {
    339 		DPRINTF(("%s: sbt_intr: read failed\n", DEVNAME(sc)));
    340 		goto eoi;
    341 	}
    342 
    343 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    344 	if (m == NULL) {
    345 		DPRINTF(("%s: sbt_intr: MGETHDR failed\n", DEVNAME(sc)));
    346 		goto eoi;
    347 	}
    348 
    349 	m->m_pkthdr.len = m->m_len = MHLEN;
    350 	m_copyback(m, 0, len, sc->sc_buf);
    351 	if (m->m_pkthdr.len == MAX(MHLEN, len)) {
    352 		m->m_pkthdr.len = len;
    353 		m->m_len = MIN(MHLEN, m->m_pkthdr.len);
    354 	} else {
    355 		DPRINTF(("%s: sbt_intr: m_copyback failed\n", DEVNAME(sc)));
    356 		m_freem(m);
    357 		m = NULL;
    358 	}
    359 
    360 eoi:
    361 	if (m != NULL) {
    362 		switch (sc->sc_buf[0]) {
    363 		case HCI_ACL_DATA_PKT:
    364 			DNPRINTF(1,("%s: recv ACL packet (%d bytes)\n",
    365 			    DEVNAME(sc), m->m_pkthdr.len));
    366 			hci_input_acl(sc->sc_unit, m);
    367 			break;
    368 		case HCI_SCO_DATA_PKT:
    369 			DNPRINTF(1,("%s: recv SCO packet (%d bytes)\n",
    370 			    DEVNAME(sc), m->m_pkthdr.len));
    371 			hci_input_sco(sc->sc_unit, m);
    372 			break;
    373 		case HCI_EVENT_PKT:
    374 			DNPRINTF(1,("%s: recv EVENT packet (%d bytes)\n",
    375 			    DEVNAME(sc), m->m_pkthdr.len));
    376 			hci_input_event(sc->sc_unit, m);
    377 			break;
    378 		default:
    379 			DPRINTF(("%s: recv 0x%x packet (%d bytes)\n",
    380 			    DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len));
    381 			sc->sc_stats.err_rx++;
    382 			m_freem(m);
    383 			break;
    384 		}
    385 	} else
    386 		sc->sc_stats.err_rx++;
    387 
    388 	splx(s);
    389 
    390 	/* Claim this interrupt. */
    391 	return 1;
    392 }
    393 
    394 
    395 /*
    396  * Bluetooth HCI unit functions
    397  */
    398 
    399 static int
    400 sbt_enable(device_t self)
    401 {
    402 	struct sbt_softc *sc = device_private(self);
    403 	int s;
    404 
    405 	if (sc->sc_flags & SBT_ENABLED)
    406 		return 0;
    407 
    408 	s = spltty();
    409 
    410 	sc->sc_flags |= SBT_ENABLED;
    411 	sc->sc_flags &= ~SBT_XMIT;
    412 
    413 	splx(s);
    414 
    415 	return 0;
    416 }
    417 
    418 static void
    419 sbt_disable(device_t self)
    420 {
    421 	struct sbt_softc *sc = device_private(self);
    422 	int s;
    423 
    424 	if (!(sc->sc_flags & SBT_ENABLED))
    425 		return;
    426 
    427 	s = spltty();
    428 
    429 #ifdef notyet			/* XXX */
    430 	m_freem(sc->sc_rxp);
    431 	sc->sc_rxp = NULL;
    432 
    433 	m_freem(sc->sc_txp);
    434 	sc->sc_txp = NULL;
    435 #endif
    436 
    437 	MBUFQ_DRAIN(&sc->sc_cmdq);
    438 	MBUFQ_DRAIN(&sc->sc_aclq);
    439 	MBUFQ_DRAIN(&sc->sc_scoq);
    440 
    441 	sc->sc_flags &= ~SBT_ENABLED;
    442 
    443 	splx(s);
    444 }
    445 
    446 static void
    447 sbt_start(struct sbt_softc *sc)
    448 {
    449 	struct mbuf *m;
    450 	int len;
    451 #ifdef SBT_DEBUG
    452 	const char *what;
    453 #endif
    454 
    455 	KASSERT((sc->sc_flags & SBT_XMIT) == 0);
    456 
    457 	if (sc->sc_dying)
    458 		return;
    459 
    460 	if (MBUFQ_FIRST(&sc->sc_cmdq)) {
    461 		MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
    462 		sc->sc_stats.cmd_tx++;
    463 #ifdef SBT_DEBUG
    464 		what = "CMD";
    465 #endif
    466 		goto start;
    467 	}
    468 
    469 	if (MBUFQ_FIRST(&sc->sc_scoq)) {
    470 		MBUFQ_DEQUEUE(&sc->sc_scoq, m);
    471 		sc->sc_stats.sco_tx++;
    472 #ifdef SBT_DEBUG
    473 		what = "SCO";
    474 #endif
    475 		goto start;
    476 	}
    477 
    478 	if (MBUFQ_FIRST(&sc->sc_aclq)) {
    479 		MBUFQ_DEQUEUE(&sc->sc_aclq, m);
    480 		sc->sc_stats.acl_tx++;
    481 #ifdef SBT_DEBUG
    482 		what = "ACL";
    483 #endif
    484 		goto start;
    485 	}
    486 
    487 	/* Nothing to send */
    488 	return;
    489 
    490 start:
    491 	DNPRINTF(1,("%s: xmit %s packet (%d bytes)\n", DEVNAME(sc),
    492 	    what, m->m_pkthdr.len));
    493 
    494 	sc->sc_flags |= SBT_XMIT;
    495 
    496 	len = m->m_pkthdr.len;
    497 	m_copydata(m, 0, len, sc->sc_buf);
    498 	m_freem(m);
    499 
    500 	if (sbt_write_packet(sc, sc->sc_buf, len))
    501 		DPRINTF(("%s: sbt_write_packet failed\n", DEVNAME(sc)));
    502 
    503 	sc->sc_flags &= ~SBT_XMIT;
    504 }
    505 
    506 static void
    507 sbt_start_cmd(device_t self, struct mbuf *m)
    508 {
    509 	struct sbt_softc *sc = device_private(self);
    510 	int s;
    511 
    512 	KASSERT(sc->sc_flags & SBT_ENABLED);
    513 
    514 	M_SETCTX(m, NULL);
    515 
    516 	s = spltty();
    517 
    518 	MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
    519 	if ((sc->sc_flags & SBT_XMIT) == 0)
    520 		sbt_start(sc);
    521 
    522 	splx(s);
    523 }
    524 
    525 static void
    526 sbt_start_acl(device_t self, struct mbuf *m)
    527 {
    528 	struct sbt_softc *sc = device_private(self);
    529 	int s;
    530 
    531 	KASSERT(sc->sc_flags & SBT_ENABLED);
    532 
    533 	M_SETCTX(m, NULL);
    534 
    535 	s = spltty();
    536 
    537 	MBUFQ_ENQUEUE(&sc->sc_aclq, m);
    538 	if ((sc->sc_flags & SBT_XMIT) == 0)
    539 		sbt_start(sc);
    540 
    541 	splx(s);
    542 }
    543 
    544 static void
    545 sbt_start_sco(device_t self, struct mbuf *m)
    546 {
    547 	struct sbt_softc *sc = device_private(self);
    548 	int s;
    549 
    550 	KASSERT(sc->sc_flags & SBT_ENABLED);
    551 
    552 	s = spltty();
    553 
    554 	MBUFQ_ENQUEUE(&sc->sc_scoq, m);
    555 	if ((sc->sc_flags & SBT_XMIT) == 0)
    556 		sbt_start(sc);
    557 
    558 	splx(s);
    559 }
    560 
    561 static void
    562 sbt_stats(device_t self, struct bt_stats *dest, int flush)
    563 {
    564 	struct sbt_softc *sc = device_private(self);
    565 	int s;
    566 
    567 	s = spltty();
    568 
    569 	memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
    570 
    571 	if (flush)
    572 		memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
    573 
    574 	splx(s);
    575 }
    576