Home | History | Annotate | Line # | Download | only in bluetooth
btuart.c revision 1.28.18.1
      1  1.28.18.1  christos /*	$NetBSD: btuart.c,v 1.28.18.1 2019/06/10 22:07:06 christos Exp $	*/
      2       1.18    plunky 
      3       1.18    plunky /*-
      4        1.1  kiyohara  * Copyright (c) 2006, 2007 KIYOHARA Takashi
      5        1.1  kiyohara  * All rights reserved.
      6        1.1  kiyohara  *
      7        1.1  kiyohara  * Redistribution and use in source and binary forms, with or without
      8        1.1  kiyohara  * modification, are permitted provided that the following conditions
      9        1.1  kiyohara  * are met:
     10        1.1  kiyohara  * 1. Redistributions of source code must retain the above copyright
     11        1.1  kiyohara  *    notice, this list of conditions and the following disclaimer.
     12        1.1  kiyohara  * 2. Redistributions in binary form must reproduce the above copyright
     13        1.1  kiyohara  *    notice, this list of conditions and the following disclaimer in the
     14        1.1  kiyohara  *    documentation and/or other materials provided with the distribution.
     15        1.1  kiyohara  *
     16        1.1  kiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17        1.1  kiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18        1.1  kiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19        1.1  kiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20        1.1  kiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21        1.1  kiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22        1.1  kiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23        1.1  kiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24        1.1  kiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     25        1.1  kiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26        1.1  kiyohara  * POSSIBILITY OF SUCH DAMAGE.
     27        1.1  kiyohara  */
     28        1.1  kiyohara 
     29        1.1  kiyohara #include <sys/cdefs.h>
     30  1.28.18.1  christos __KERNEL_RCSID(0, "$NetBSD: btuart.c,v 1.28.18.1 2019/06/10 22:07:06 christos Exp $");
     31        1.1  kiyohara 
     32        1.1  kiyohara #include <sys/param.h>
     33       1.18    plunky #include <sys/conf.h>
     34        1.1  kiyohara #include <sys/device.h>
     35        1.1  kiyohara #include <sys/errno.h>
     36        1.1  kiyohara #include <sys/fcntl.h>
     37        1.1  kiyohara #include <sys/kauth.h>
     38        1.1  kiyohara #include <sys/kernel.h>
     39        1.1  kiyohara #include <sys/malloc.h>
     40        1.1  kiyohara #include <sys/mbuf.h>
     41        1.1  kiyohara #include <sys/proc.h>
     42        1.1  kiyohara #include <sys/syslimits.h>
     43        1.1  kiyohara #include <sys/systm.h>
     44        1.1  kiyohara #include <sys/tty.h>
     45        1.1  kiyohara 
     46        1.9        ad #include <sys/bus.h>
     47        1.9        ad #include <sys/intr.h>
     48        1.1  kiyohara 
     49        1.1  kiyohara #include <netbt/bluetooth.h>
     50        1.1  kiyohara #include <netbt/hci.h>
     51        1.1  kiyohara 
     52       1.26  uebayasi #include "ioconf.h"
     53       1.26  uebayasi 
     54        1.1  kiyohara struct btuart_softc {
     55       1.10    plunky 	device_t	sc_dev;
     56       1.18    plunky 	struct tty *	sc_tp;		/* tty pointer */
     57        1.1  kiyohara 
     58       1.18    plunky 	bool		sc_enabled;	/* device is enabled */
     59       1.18    plunky 	struct hci_unit *sc_unit;	/* Bluetooth HCI handle */
     60       1.18    plunky 	struct bt_stats	sc_stats;
     61       1.18    plunky 
     62       1.18    plunky 	int		sc_state;	/* receive state */
     63       1.18    plunky 	int		sc_want;	/* how much we want */
     64       1.18    plunky 	struct mbuf *	sc_rxp;		/* incoming packet */
     65       1.18    plunky 
     66       1.18    plunky 	bool		sc_xmit;	/* transmit is active */
     67       1.18    plunky 	struct mbuf *	sc_txp;		/* outgoing packet */
     68       1.18    plunky 
     69       1.18    plunky 	/* transmit queues */
     70       1.18    plunky 	MBUFQ_HEAD()	sc_cmdq;
     71       1.18    plunky 	MBUFQ_HEAD()	sc_aclq;
     72       1.18    plunky 	MBUFQ_HEAD()	sc_scoq;
     73        1.1  kiyohara };
     74        1.1  kiyohara 
     75       1.18    plunky /* sc_state */
     76       1.18    plunky #define BTUART_RECV_PKT_TYPE	0	/* packet type */
     77       1.18    plunky #define BTUART_RECV_ACL_HDR	1	/* acl header */
     78       1.18    plunky #define BTUART_RECV_SCO_HDR	2	/* sco header */
     79       1.18    plunky #define BTUART_RECV_EVENT_HDR	3	/* event header */
     80       1.18    plunky #define BTUART_RECV_ACL_DATA	4	/* acl packet data */
     81       1.18    plunky #define BTUART_RECV_SCO_DATA	5	/* sco packet data */
     82       1.18    plunky #define BTUART_RECV_EVENT_DATA	6	/* event packet data */
     83       1.14    plunky 
     84       1.23    cegger static int btuart_match(device_t, cfdata_t, void *);
     85       1.10    plunky static void btuart_attach(device_t, device_t, void *);
     86       1.10    plunky static int btuart_detach(device_t, int);
     87        1.1  kiyohara 
     88       1.18    plunky static int btuartopen(dev_t, struct tty *);
     89       1.18    plunky static int btuartclose(struct tty *, int);
     90       1.18    plunky static int btuartioctl(struct tty *, u_long, void *, int, struct lwp *);
     91       1.18    plunky static int btuartinput(int, struct tty *);
     92       1.18    plunky static int btuartstart(struct tty *);
     93       1.18    plunky 
     94       1.18    plunky static int btuart_enable(device_t);
     95       1.18    plunky static void btuart_disable(device_t);
     96       1.18    plunky static void btuart_output_cmd(device_t, struct mbuf *);
     97       1.18    plunky static void btuart_output_acl(device_t, struct mbuf *);
     98       1.18    plunky static void btuart_output_sco(device_t, struct mbuf *);
     99       1.18    plunky static void btuart_stats(device_t, struct bt_stats *, int);
    100        1.1  kiyohara 
    101        1.1  kiyohara /*
    102        1.1  kiyohara  * It doesn't need to be exported, as only btuartattach() uses it,
    103        1.1  kiyohara  * but there's no "official" way to make it static.
    104        1.1  kiyohara  */
    105       1.10    plunky CFATTACH_DECL_NEW(btuart, sizeof(struct btuart_softc),
    106        1.1  kiyohara     btuart_match, btuart_attach, btuart_detach, NULL);
    107        1.1  kiyohara 
    108       1.18    plunky static struct linesw btuart_disc = {
    109       1.18    plunky 	.l_name =	"btuart",
    110       1.18    plunky 	.l_open =	btuartopen,
    111       1.18    plunky 	.l_close =	btuartclose,
    112       1.18    plunky 	.l_read =	ttyerrio,
    113       1.18    plunky 	.l_write =	ttyerrio,
    114       1.18    plunky 	.l_ioctl =	btuartioctl,
    115       1.18    plunky 	.l_rint =	btuartinput,
    116       1.18    plunky 	.l_start =	btuartstart,
    117       1.18    plunky 	.l_modem =	ttymodem,
    118       1.18    plunky 	.l_poll =	ttyerrpoll,
    119        1.1  kiyohara };
    120        1.1  kiyohara 
    121       1.14    plunky static const struct hci_if btuart_hci = {
    122       1.18    plunky 	.enable =	btuart_enable,
    123       1.18    plunky 	.disable =	btuart_disable,
    124       1.18    plunky 	.output_cmd =	btuart_output_cmd,
    125       1.18    plunky 	.output_acl =	btuart_output_acl,
    126       1.18    plunky 	.output_sco =	btuart_output_sco,
    127       1.18    plunky 	.get_stats =	btuart_stats,
    128       1.18    plunky 	.ipl =		IPL_TTY,
    129       1.14    plunky };
    130       1.14    plunky 
    131       1.18    plunky /*****************************************************************************
    132       1.18    plunky  *
    133       1.18    plunky  *	autoconf(9) functions
    134       1.18    plunky  */
    135        1.1  kiyohara 
    136       1.18    plunky /*
    137       1.18    plunky  * pseudo-device attach routine.
    138       1.18    plunky  */
    139        1.1  kiyohara void
    140        1.1  kiyohara btuartattach(int num __unused)
    141        1.1  kiyohara {
    142        1.1  kiyohara 	int error;
    143        1.1  kiyohara 
    144       1.18    plunky 	error = ttyldisc_attach(&btuart_disc);
    145        1.1  kiyohara 	if (error) {
    146        1.1  kiyohara 		aprint_error("%s: unable to register line discipline, "
    147        1.1  kiyohara 		    "error = %d\n", btuart_cd.cd_name, error);
    148       1.18    plunky 
    149        1.1  kiyohara 		return;
    150        1.1  kiyohara 	}
    151        1.1  kiyohara 
    152        1.1  kiyohara 	error = config_cfattach_attach(btuart_cd.cd_name, &btuart_ca);
    153        1.1  kiyohara 	if (error) {
    154        1.1  kiyohara 		aprint_error("%s: unable to register cfattach, error = %d\n",
    155        1.1  kiyohara 		    btuart_cd.cd_name, error);
    156       1.18    plunky 
    157        1.1  kiyohara 		config_cfdriver_detach(&btuart_cd);
    158       1.18    plunky 		(void) ttyldisc_detach(&btuart_disc);
    159        1.1  kiyohara 	}
    160        1.1  kiyohara }
    161        1.1  kiyohara 
    162        1.1  kiyohara /*
    163        1.1  kiyohara  * Autoconf match routine.
    164        1.1  kiyohara  */
    165        1.1  kiyohara static int
    166       1.23    cegger btuart_match(device_t self __unused, cfdata_t cfdata __unused,
    167       1.15  kiyohara 	     void *arg __unused)
    168        1.1  kiyohara {
    169        1.1  kiyohara 
    170        1.1  kiyohara 	/* pseudo-device; always present */
    171        1.1  kiyohara 	return 1;
    172        1.1  kiyohara }
    173        1.1  kiyohara 
    174        1.1  kiyohara /*
    175       1.18    plunky  * Autoconf attach routine.
    176       1.18    plunky  * Called by config_attach_pseudo(9) when we open the line discipline.
    177        1.1  kiyohara  */
    178        1.1  kiyohara static void
    179       1.15  kiyohara btuart_attach(device_t parent __unused, device_t self, void *aux __unused)
    180        1.1  kiyohara {
    181        1.1  kiyohara 	struct btuart_softc *sc = device_private(self);
    182        1.1  kiyohara 
    183       1.10    plunky 	sc->sc_dev = self;
    184       1.10    plunky 
    185       1.14    plunky 	MBUFQ_INIT(&sc->sc_cmdq);
    186       1.14    plunky 	MBUFQ_INIT(&sc->sc_aclq);
    187       1.14    plunky 	MBUFQ_INIT(&sc->sc_scoq);
    188       1.14    plunky 
    189        1.1  kiyohara 	/* Attach Bluetooth unit */
    190       1.27     rmind 	sc->sc_unit = hci_attach_pcb(&btuart_hci, self, 0);
    191       1.18    plunky 	if (sc->sc_unit == NULL)
    192       1.18    plunky 		aprint_error_dev(self, "HCI attach failed\n");
    193        1.1  kiyohara }
    194        1.1  kiyohara 
    195        1.1  kiyohara /*
    196       1.18    plunky  * Autoconf detach routine.
    197       1.18    plunky  * Called when we close the line discipline.
    198        1.1  kiyohara  */
    199        1.1  kiyohara static int
    200       1.10    plunky btuart_detach(device_t self, int flags __unused)
    201        1.1  kiyohara {
    202        1.1  kiyohara 	struct btuart_softc *sc = device_private(self);
    203        1.1  kiyohara 
    204       1.18    plunky 	btuart_disable(self);
    205       1.18    plunky 
    206       1.14    plunky 	if (sc->sc_unit) {
    207       1.27     rmind 		hci_detach_pcb(sc->sc_unit);
    208       1.14    plunky 		sc->sc_unit = NULL;
    209       1.14    plunky 	}
    210        1.1  kiyohara 
    211        1.1  kiyohara 	return 0;
    212        1.1  kiyohara }
    213        1.1  kiyohara 
    214       1.18    plunky /*****************************************************************************
    215       1.18    plunky  *
    216       1.18    plunky  *	Line discipline functions.
    217        1.1  kiyohara  */
    218        1.1  kiyohara 
    219        1.1  kiyohara static int
    220       1.18    plunky btuartopen(dev_t devno __unused, struct tty *tp)
    221        1.1  kiyohara {
    222        1.1  kiyohara 	struct btuart_softc *sc;
    223       1.15  kiyohara 	device_t dev;
    224       1.23    cegger 	cfdata_t cfdata;
    225        1.1  kiyohara 	struct lwp *l = curlwp;		/* XXX */
    226        1.1  kiyohara 	int error, unit, s;
    227        1.1  kiyohara 
    228       1.22      elad 	error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_BLUETOOTH_BTUART,
    229       1.22      elad 	    KAUTH_ARG(KAUTH_REQ_DEVICE_BLUETOOTH_BTUART_ADD), NULL, NULL, NULL);
    230       1.22      elad 	if (error)
    231       1.22      elad 		return (error);
    232        1.1  kiyohara 
    233        1.1  kiyohara 	s = spltty();
    234        1.1  kiyohara 
    235       1.18    plunky 	if (tp->t_linesw == &btuart_disc) {
    236       1.18    plunky 		sc = tp->t_sc;
    237        1.1  kiyohara 		if (sc != NULL) {
    238        1.1  kiyohara 			splx(s);
    239        1.1  kiyohara 			return EBUSY;
    240        1.1  kiyohara 		}
    241        1.1  kiyohara 	}
    242        1.1  kiyohara 
    243        1.1  kiyohara 	KASSERT(tp->t_oproc != NULL);
    244        1.1  kiyohara 
    245        1.1  kiyohara 	cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
    246        1.1  kiyohara 	for (unit = 0; unit < btuart_cd.cd_ndevs; unit++)
    247       1.19    cegger 		if (device_lookup(&btuart_cd, unit) == NULL)
    248        1.1  kiyohara 			break;
    249       1.18    plunky 
    250       1.18    plunky 	cfdata->cf_name = btuart_cd.cd_name;
    251       1.18    plunky 	cfdata->cf_atname = btuart_cd.cd_name;
    252        1.1  kiyohara 	cfdata->cf_unit = unit;
    253        1.3    plunky 	cfdata->cf_fstate = FSTATE_STAR;
    254        1.1  kiyohara 
    255       1.15  kiyohara 	dev = config_attach_pseudo(cfdata);
    256       1.15  kiyohara 	if (dev == NULL) {
    257       1.18    plunky 		free(cfdata, M_DEVBUF);
    258        1.1  kiyohara 		splx(s);
    259        1.1  kiyohara 		return EIO;
    260        1.1  kiyohara 	}
    261       1.15  kiyohara 	sc = device_private(dev);
    262       1.18    plunky 
    263       1.20  christos 	aprint_normal_dev(dev, "major %llu minor %llu\n",
    264       1.20  christos 	    (unsigned long long)major(tp->t_dev),
    265       1.20  christos 	    (unsigned long long)minor(tp->t_dev));
    266       1.18    plunky 
    267       1.18    plunky 	sc->sc_tp = tp;
    268       1.18    plunky 	tp->t_sc = sc;
    269       1.18    plunky 
    270       1.11        ad 	mutex_spin_enter(&tty_lock);
    271        1.1  kiyohara 	ttyflush(tp, FREAD | FWRITE);
    272       1.11        ad 	mutex_spin_exit(&tty_lock);
    273        1.1  kiyohara 
    274        1.1  kiyohara 	splx(s);
    275        1.1  kiyohara 
    276        1.1  kiyohara 	return 0;
    277        1.1  kiyohara }
    278        1.1  kiyohara 
    279        1.1  kiyohara static int
    280       1.18    plunky btuartclose(struct tty *tp, int flag __unused)
    281        1.1  kiyohara {
    282       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    283       1.23    cegger 	cfdata_t cfdata;
    284       1.18    plunky 	int s;
    285        1.1  kiyohara 
    286       1.18    plunky 	s = spltty();
    287        1.1  kiyohara 
    288       1.11        ad 	mutex_spin_enter(&tty_lock);
    289        1.1  kiyohara 	ttyflush(tp, FREAD | FWRITE);
    290       1.11        ad 	mutex_spin_exit(&tty_lock);	/* XXX */
    291       1.18    plunky 
    292        1.1  kiyohara 	ttyldisc_release(tp->t_linesw);
    293        1.1  kiyohara 	tp->t_linesw = ttyldisc_default();
    294       1.18    plunky 
    295        1.1  kiyohara 	if (sc != NULL) {
    296        1.1  kiyohara 		tp->t_sc = NULL;
    297        1.1  kiyohara 		if (sc->sc_tp == tp) {
    298       1.10    plunky 			cfdata = device_cfdata(sc->sc_dev);
    299       1.10    plunky 			config_detach(sc->sc_dev, 0);
    300        1.1  kiyohara 			free(cfdata, M_DEVBUF);
    301        1.1  kiyohara 		}
    302       1.18    plunky 	}
    303        1.1  kiyohara 
    304        1.1  kiyohara 	splx(s);
    305       1.18    plunky 
    306        1.1  kiyohara 	return 0;
    307        1.1  kiyohara }
    308        1.1  kiyohara 
    309        1.1  kiyohara static int
    310       1.18    plunky btuartioctl(struct tty *tp, u_long cmd, void *data __unused,
    311        1.1  kiyohara     int flag __unused, struct lwp *l __unused)
    312        1.1  kiyohara {
    313       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    314       1.18    plunky 	int error;
    315        1.1  kiyohara 
    316  1.28.18.1  christos 	/*
    317  1.28.18.1  christos 	 * XXX
    318  1.28.18.1  christos 	 * This function can be called without KERNEL_LOCK when caller's
    319  1.28.18.1  christos 	 * struct cdevsw is set D_MPSAFE. Is KERNEL_LOCK required?
    320  1.28.18.1  christos 	 */
    321  1.28.18.1  christos 
    322        1.1  kiyohara 	if (sc == NULL || tp != sc->sc_tp)
    323        1.1  kiyohara 		return EPASSTHROUGH;
    324        1.1  kiyohara 
    325       1.18    plunky 	switch(cmd) {
    326        1.1  kiyohara 	default:
    327        1.1  kiyohara 		error = EPASSTHROUGH;
    328        1.1  kiyohara 		break;
    329        1.1  kiyohara 	}
    330        1.1  kiyohara 
    331        1.1  kiyohara 	return error;
    332        1.1  kiyohara }
    333        1.1  kiyohara 
    334        1.1  kiyohara static int
    335       1.18    plunky btuartinput(int c, struct tty *tp)
    336        1.1  kiyohara {
    337       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    338        1.1  kiyohara 	struct mbuf *m = sc->sc_rxp;
    339        1.1  kiyohara 	int space = 0;
    340        1.1  kiyohara 
    341       1.18    plunky 	if (!sc->sc_enabled)
    342       1.18    plunky 		return 0;
    343       1.18    plunky 
    344        1.1  kiyohara 	c &= TTY_CHARMASK;
    345        1.1  kiyohara 
    346        1.1  kiyohara 	/* If we already started a packet, find the trailing end of it. */
    347        1.1  kiyohara 	if (m) {
    348        1.1  kiyohara 		while (m->m_next)
    349        1.1  kiyohara 			m = m->m_next;
    350        1.1  kiyohara 
    351        1.1  kiyohara 		space = M_TRAILINGSPACE(m);
    352        1.1  kiyohara 	}
    353        1.1  kiyohara 
    354        1.1  kiyohara 	if (space == 0) {
    355        1.1  kiyohara 		if (m == NULL) {
    356        1.1  kiyohara 			/* new packet */
    357        1.1  kiyohara 			MGETHDR(m, M_DONTWAIT, MT_DATA);
    358        1.1  kiyohara 			if (m == NULL) {
    359       1.24  kiyohara 				aprint_error_dev(sc->sc_dev, "out of memory\n");
    360       1.14    plunky 				sc->sc_stats.err_rx++;
    361        1.1  kiyohara 				return 0;	/* (lost sync) */
    362        1.1  kiyohara 			}
    363        1.1  kiyohara 
    364        1.1  kiyohara 			sc->sc_rxp = m;
    365        1.1  kiyohara 			m->m_pkthdr.len = m->m_len = 0;
    366        1.1  kiyohara 			space = MHLEN;
    367        1.1  kiyohara 
    368        1.1  kiyohara 			sc->sc_state = BTUART_RECV_PKT_TYPE;
    369        1.1  kiyohara 			sc->sc_want = 1;
    370        1.1  kiyohara 		} else {
    371        1.1  kiyohara 			/* extend mbuf */
    372        1.1  kiyohara 			MGET(m->m_next, M_DONTWAIT, MT_DATA);
    373        1.1  kiyohara 			if (m->m_next == NULL) {
    374       1.24  kiyohara 				aprint_error_dev(sc->sc_dev, "out of memory\n");
    375       1.14    plunky 				sc->sc_stats.err_rx++;
    376        1.1  kiyohara 				return 0;	/* (lost sync) */
    377        1.1  kiyohara 			}
    378        1.1  kiyohara 
    379        1.1  kiyohara 			m = m->m_next;
    380        1.1  kiyohara 			m->m_len = 0;
    381        1.1  kiyohara 			space = MLEN;
    382        1.1  kiyohara 
    383        1.1  kiyohara 			if (sc->sc_want > MINCLSIZE) {
    384        1.1  kiyohara 				MCLGET(m, M_DONTWAIT);
    385        1.1  kiyohara 				if (m->m_flags & M_EXT)
    386        1.1  kiyohara 					space = MCLBYTES;
    387        1.1  kiyohara 			}
    388        1.1  kiyohara 		}
    389        1.1  kiyohara 	}
    390        1.1  kiyohara 
    391        1.1  kiyohara 	mtod(m, uint8_t *)[m->m_len++] = c;
    392        1.1  kiyohara 	sc->sc_rxp->m_pkthdr.len++;
    393       1.14    plunky 	sc->sc_stats.byte_rx++;
    394        1.1  kiyohara 
    395        1.1  kiyohara 	sc->sc_want--;
    396        1.1  kiyohara 	if (sc->sc_want > 0)
    397        1.1  kiyohara 		return 0;	/* want more */
    398        1.1  kiyohara 
    399        1.1  kiyohara 	switch (sc->sc_state) {
    400        1.1  kiyohara 	case BTUART_RECV_PKT_TYPE:	/* Got packet type */
    401        1.1  kiyohara 
    402        1.1  kiyohara 		switch (c) {
    403        1.1  kiyohara 		case HCI_ACL_DATA_PKT:
    404        1.1  kiyohara 			sc->sc_state = BTUART_RECV_ACL_HDR;
    405        1.1  kiyohara 			sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
    406        1.1  kiyohara 			break;
    407        1.1  kiyohara 
    408        1.1  kiyohara 		case HCI_SCO_DATA_PKT:
    409        1.1  kiyohara 			sc->sc_state = BTUART_RECV_SCO_HDR;
    410        1.1  kiyohara 			sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
    411        1.1  kiyohara 			break;
    412        1.1  kiyohara 
    413        1.1  kiyohara 		case HCI_EVENT_PKT:
    414        1.1  kiyohara 			sc->sc_state = BTUART_RECV_EVENT_HDR;
    415        1.1  kiyohara 			sc->sc_want = sizeof(hci_event_hdr_t) - 1;
    416        1.1  kiyohara 			break;
    417        1.1  kiyohara 
    418        1.1  kiyohara 		default:
    419       1.13    plunky 			aprint_error_dev(sc->sc_dev,
    420       1.13    plunky 			    "Unknown packet type=%#x!\n", c);
    421       1.14    plunky 			sc->sc_stats.err_rx++;
    422        1.1  kiyohara 			m_freem(sc->sc_rxp);
    423        1.1  kiyohara 			sc->sc_rxp = NULL;
    424        1.1  kiyohara 			return 0;	/* (lost sync) */
    425        1.1  kiyohara 		}
    426        1.1  kiyohara 
    427        1.1  kiyohara 		break;
    428        1.1  kiyohara 
    429        1.1  kiyohara 	/*
    430        1.1  kiyohara 	 * we assume (correctly of course :) that the packet headers all fit
    431        1.1  kiyohara 	 * into a single pkthdr mbuf
    432        1.1  kiyohara 	 */
    433        1.1  kiyohara 	case BTUART_RECV_ACL_HDR:	/* Got ACL Header */
    434        1.1  kiyohara 		sc->sc_state = BTUART_RECV_ACL_DATA;
    435        1.1  kiyohara 		sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
    436        1.1  kiyohara 		sc->sc_want = le16toh(sc->sc_want);
    437        1.1  kiyohara 		break;
    438        1.1  kiyohara 
    439        1.1  kiyohara 	case BTUART_RECV_SCO_HDR:	/* Got SCO Header */
    440        1.1  kiyohara 		sc->sc_state = BTUART_RECV_SCO_DATA;
    441        1.1  kiyohara 		sc->sc_want =  mtod(m, hci_scodata_hdr_t *)->length;
    442        1.1  kiyohara 		break;
    443        1.1  kiyohara 
    444        1.1  kiyohara 	case BTUART_RECV_EVENT_HDR:	/* Got Event Header */
    445        1.1  kiyohara 		sc->sc_state = BTUART_RECV_EVENT_DATA;
    446        1.1  kiyohara 		sc->sc_want =  mtod(m, hci_event_hdr_t *)->length;
    447        1.1  kiyohara 		break;
    448        1.1  kiyohara 
    449        1.1  kiyohara 	case BTUART_RECV_ACL_DATA:	/* ACL Packet Complete */
    450       1.18    plunky 		if (!hci_input_acl(sc->sc_unit, sc->sc_rxp))
    451       1.14    plunky 			sc->sc_stats.err_rx++;
    452       1.14    plunky 
    453       1.14    plunky 		sc->sc_stats.acl_rx++;
    454        1.1  kiyohara 		sc->sc_rxp = m = NULL;
    455        1.1  kiyohara 		break;
    456        1.1  kiyohara 
    457        1.1  kiyohara 	case BTUART_RECV_SCO_DATA:	/* SCO Packet Complete */
    458       1.18    plunky 		if (!hci_input_sco(sc->sc_unit, sc->sc_rxp))
    459       1.14    plunky 			sc->sc_stats.err_rx++;
    460       1.14    plunky 
    461       1.14    plunky 		sc->sc_stats.sco_rx++;
    462        1.1  kiyohara 		sc->sc_rxp = m = NULL;
    463        1.1  kiyohara 		break;
    464        1.1  kiyohara 
    465        1.1  kiyohara 	case BTUART_RECV_EVENT_DATA:	/* Event Packet Complete */
    466       1.18    plunky 		if (!hci_input_event(sc->sc_unit, sc->sc_rxp))
    467       1.14    plunky 			sc->sc_stats.err_rx++;
    468       1.14    plunky 
    469       1.14    plunky 		sc->sc_stats.evt_rx++;
    470        1.1  kiyohara 		sc->sc_rxp = m = NULL;
    471        1.1  kiyohara 		break;
    472        1.1  kiyohara 
    473        1.1  kiyohara 	default:
    474        1.1  kiyohara 		panic("%s: invalid state %d!\n",
    475       1.10    plunky 		    device_xname(sc->sc_dev), sc->sc_state);
    476        1.1  kiyohara 	}
    477        1.1  kiyohara 
    478        1.1  kiyohara 	return 0;
    479        1.1  kiyohara }
    480        1.1  kiyohara 
    481        1.1  kiyohara static int
    482       1.18    plunky btuartstart(struct tty *tp)
    483        1.1  kiyohara {
    484       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    485        1.1  kiyohara 	struct mbuf *m;
    486        1.1  kiyohara 	int count, rlen;
    487        1.1  kiyohara 	uint8_t *rptr;
    488        1.1  kiyohara 
    489       1.18    plunky 	if (!sc->sc_enabled)
    490       1.18    plunky 		return 0;
    491       1.18    plunky 
    492        1.1  kiyohara 	m = sc->sc_txp;
    493        1.1  kiyohara 	if (m == NULL) {
    494       1.18    plunky 		if (MBUFQ_FIRST(&sc->sc_cmdq)) {
    495       1.18    plunky 			MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
    496       1.18    plunky 			sc->sc_stats.cmd_tx++;
    497       1.18    plunky 		} else if (MBUFQ_FIRST(&sc->sc_scoq)) {
    498       1.18    plunky 			MBUFQ_DEQUEUE(&sc->sc_scoq, m);
    499       1.18    plunky 			sc->sc_stats.sco_tx++;
    500       1.18    plunky 		} else if (MBUFQ_FIRST(&sc->sc_aclq)) {
    501       1.18    plunky 			MBUFQ_DEQUEUE(&sc->sc_aclq, m);
    502       1.18    plunky 			sc->sc_stats.acl_tx++;
    503       1.18    plunky 		} else {
    504       1.18    plunky 			sc->sc_xmit = false;
    505       1.18    plunky 			return 0; /* no more to send */
    506       1.18    plunky 		}
    507       1.18    plunky 
    508       1.18    plunky 		sc->sc_txp = m;
    509       1.18    plunky 		sc->sc_xmit = true;
    510        1.1  kiyohara 	}
    511        1.1  kiyohara 
    512        1.1  kiyohara 	count = 0;
    513        1.1  kiyohara 	rlen = 0;
    514        1.1  kiyohara 	rptr = mtod(m, uint8_t *);
    515        1.1  kiyohara 
    516        1.1  kiyohara 	for(;;) {
    517        1.1  kiyohara 		if (rlen >= m->m_len) {
    518        1.1  kiyohara 			m = m->m_next;
    519        1.1  kiyohara 			if (m == NULL) {
    520        1.1  kiyohara 				m = sc->sc_txp;
    521        1.1  kiyohara 				sc->sc_txp = NULL;
    522        1.1  kiyohara 
    523        1.1  kiyohara 				if (M_GETCTX(m, void *) == NULL)
    524        1.1  kiyohara 					m_freem(m);
    525       1.14    plunky 				else if (!hci_complete_sco(sc->sc_unit, m))
    526       1.14    plunky 					sc->sc_stats.err_tx++;
    527        1.1  kiyohara 
    528        1.1  kiyohara 				break;
    529        1.1  kiyohara 			}
    530        1.1  kiyohara 
    531        1.1  kiyohara 			rlen = 0;
    532        1.1  kiyohara 			rptr = mtod(m, uint8_t *);
    533        1.1  kiyohara 			continue;
    534        1.1  kiyohara 		}
    535        1.1  kiyohara 
    536        1.1  kiyohara 		if (putc(*rptr++, &tp->t_outq) < 0) {
    537        1.1  kiyohara 			m_adj(m, rlen);
    538        1.1  kiyohara 			break;
    539        1.1  kiyohara 		}
    540        1.1  kiyohara 		rlen++;
    541        1.1  kiyohara 		count++;
    542        1.1  kiyohara 	}
    543        1.1  kiyohara 
    544       1.14    plunky 	sc->sc_stats.byte_tx += count;
    545        1.1  kiyohara 
    546        1.1  kiyohara 	if (tp->t_outq.c_cc != 0)
    547        1.1  kiyohara 		(*tp->t_oproc)(tp);
    548        1.1  kiyohara 
    549        1.1  kiyohara 	return 0;
    550        1.1  kiyohara }
    551        1.1  kiyohara 
    552       1.18    plunky /*****************************************************************************
    553       1.18    plunky  *
    554       1.18    plunky  *	bluetooth(9) functions
    555       1.18    plunky  */
    556        1.1  kiyohara 
    557        1.1  kiyohara static int
    558       1.18    plunky btuart_enable(device_t self)
    559        1.1  kiyohara {
    560       1.12    plunky 	struct btuart_softc *sc = device_private(self);
    561       1.14    plunky 	int s;
    562        1.1  kiyohara 
    563       1.18    plunky 	if (sc->sc_enabled)
    564        1.1  kiyohara 		return 0;
    565        1.1  kiyohara 
    566       1.14    plunky 	s = spltty();
    567       1.14    plunky 
    568       1.18    plunky 	sc->sc_enabled = true;
    569       1.18    plunky 	sc->sc_xmit = false;
    570       1.14    plunky 
    571       1.14    plunky 	splx(s);
    572        1.1  kiyohara 
    573        1.1  kiyohara 	return 0;
    574        1.1  kiyohara }
    575        1.1  kiyohara 
    576        1.1  kiyohara static void
    577       1.18    plunky btuart_disable(device_t self)
    578        1.1  kiyohara {
    579       1.12    plunky 	struct btuart_softc *sc = device_private(self);
    580       1.14    plunky 	int s;
    581        1.1  kiyohara 
    582       1.18    plunky 	if (!sc->sc_enabled)
    583        1.1  kiyohara 		return;
    584        1.1  kiyohara 
    585       1.14    plunky 	s = spltty();
    586       1.14    plunky 
    587        1.1  kiyohara 	if (sc->sc_rxp) {
    588        1.1  kiyohara 		m_freem(sc->sc_rxp);
    589        1.1  kiyohara 		sc->sc_rxp = NULL;
    590        1.1  kiyohara 	}
    591        1.1  kiyohara 
    592        1.1  kiyohara 	if (sc->sc_txp) {
    593        1.1  kiyohara 		m_freem(sc->sc_txp);
    594        1.1  kiyohara 		sc->sc_txp = NULL;
    595        1.1  kiyohara 	}
    596        1.1  kiyohara 
    597       1.14    plunky 	MBUFQ_DRAIN(&sc->sc_cmdq);
    598       1.14    plunky 	MBUFQ_DRAIN(&sc->sc_aclq);
    599       1.14    plunky 	MBUFQ_DRAIN(&sc->sc_scoq);
    600       1.14    plunky 
    601       1.18    plunky 	sc->sc_enabled = false;
    602       1.14    plunky 
    603       1.14    plunky 	splx(s);
    604        1.1  kiyohara }
    605        1.1  kiyohara 
    606        1.1  kiyohara static void
    607       1.18    plunky btuart_output_cmd(device_t self, struct mbuf *m)
    608       1.14    plunky {
    609       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    610       1.14    plunky 	int s;
    611       1.14    plunky 
    612       1.18    plunky 	KASSERT(sc->sc_enabled);
    613       1.14    plunky 
    614       1.14    plunky 	M_SETCTX(m, NULL);
    615       1.14    plunky 
    616       1.14    plunky 	s = spltty();
    617       1.14    plunky 	MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
    618       1.18    plunky 	if (!sc->sc_xmit)
    619       1.18    plunky 		btuartstart(sc->sc_tp);
    620       1.14    plunky 
    621       1.14    plunky 	splx(s);
    622       1.14    plunky }
    623       1.14    plunky 
    624       1.14    plunky static void
    625       1.18    plunky btuart_output_acl(device_t self, struct mbuf *m)
    626       1.14    plunky {
    627       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    628       1.14    plunky 	int s;
    629       1.14    plunky 
    630       1.18    plunky 	KASSERT(sc->sc_enabled);
    631       1.14    plunky 
    632       1.14    plunky 	M_SETCTX(m, NULL);
    633       1.14    plunky 
    634       1.14    plunky 	s = spltty();
    635       1.14    plunky 	MBUFQ_ENQUEUE(&sc->sc_aclq, m);
    636       1.18    plunky 	if (!sc->sc_xmit)
    637       1.18    plunky 		btuartstart(sc->sc_tp);
    638       1.14    plunky 
    639       1.14    plunky 	splx(s);
    640       1.14    plunky }
    641       1.14    plunky 
    642       1.14    plunky static void
    643       1.18    plunky btuart_output_sco(device_t self, struct mbuf *m)
    644       1.14    plunky {
    645       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    646       1.14    plunky 	int s;
    647       1.14    plunky 
    648       1.18    plunky 	KASSERT(sc->sc_enabled);
    649       1.14    plunky 
    650       1.14    plunky 	s = spltty();
    651       1.14    plunky 	MBUFQ_ENQUEUE(&sc->sc_scoq, m);
    652       1.18    plunky 	if (!sc->sc_xmit)
    653       1.18    plunky 		btuartstart(sc->sc_tp);
    654       1.14    plunky 
    655       1.14    plunky 	splx(s);
    656       1.14    plunky }
    657       1.14    plunky 
    658       1.14    plunky static void
    659       1.18    plunky btuart_stats(device_t self, struct bt_stats *dest, int flush)
    660       1.14    plunky {
    661       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    662       1.14    plunky 	int s;
    663       1.14    plunky 
    664       1.14    plunky 	s = spltty();
    665       1.14    plunky 
    666       1.14    plunky 	memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
    667       1.14    plunky 
    668       1.14    plunky 	if (flush)
    669       1.14    plunky 		memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
    670       1.14    plunky 
    671       1.14    plunky 	splx(s);
    672       1.14    plunky }
    673