Home | History | Annotate | Line # | Download | only in bluetooth
btuart.c revision 1.26.12.1
      1       1.25  uebayasi /*	$NetBSD: btuart.c,v 1.26.12.1 2014/08/20 00:03:36 tls 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.25  uebayasi __KERNEL_RCSID(0, "$NetBSD: btuart.c,v 1.26.12.1 2014/08/20 00:03:36 tls 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.1  kiyohara void btuartattach(int);
     85       1.23    cegger static int btuart_match(device_t, cfdata_t, void *);
     86       1.10    plunky static void btuart_attach(device_t, device_t, void *);
     87       1.10    plunky static int btuart_detach(device_t, int);
     88        1.1  kiyohara 
     89       1.18    plunky static int btuartopen(dev_t, struct tty *);
     90       1.18    plunky static int btuartclose(struct tty *, int);
     91       1.18    plunky static int btuartioctl(struct tty *, u_long, void *, int, struct lwp *);
     92       1.18    plunky static int btuartinput(int, struct tty *);
     93       1.18    plunky static int btuartstart(struct tty *);
     94       1.18    plunky 
     95       1.18    plunky static int btuart_enable(device_t);
     96       1.18    plunky static void btuart_disable(device_t);
     97       1.18    plunky static void btuart_output_cmd(device_t, struct mbuf *);
     98       1.18    plunky static void btuart_output_acl(device_t, struct mbuf *);
     99       1.18    plunky static void btuart_output_sco(device_t, struct mbuf *);
    100       1.18    plunky static void btuart_stats(device_t, struct bt_stats *, int);
    101        1.1  kiyohara 
    102        1.1  kiyohara /*
    103        1.1  kiyohara  * It doesn't need to be exported, as only btuartattach() uses it,
    104        1.1  kiyohara  * but there's no "official" way to make it static.
    105        1.1  kiyohara  */
    106       1.10    plunky CFATTACH_DECL_NEW(btuart, sizeof(struct btuart_softc),
    107        1.1  kiyohara     btuart_match, btuart_attach, btuart_detach, NULL);
    108        1.1  kiyohara 
    109       1.18    plunky static struct linesw btuart_disc = {
    110       1.18    plunky 	.l_name =	"btuart",
    111       1.18    plunky 	.l_open =	btuartopen,
    112       1.18    plunky 	.l_close =	btuartclose,
    113       1.18    plunky 	.l_read =	ttyerrio,
    114       1.18    plunky 	.l_write =	ttyerrio,
    115       1.18    plunky 	.l_ioctl =	btuartioctl,
    116       1.18    plunky 	.l_rint =	btuartinput,
    117       1.18    plunky 	.l_start =	btuartstart,
    118       1.18    plunky 	.l_modem =	ttymodem,
    119       1.18    plunky 	.l_poll =	ttyerrpoll,
    120        1.1  kiyohara };
    121        1.1  kiyohara 
    122       1.14    plunky static const struct hci_if btuart_hci = {
    123       1.18    plunky 	.enable =	btuart_enable,
    124       1.18    plunky 	.disable =	btuart_disable,
    125       1.18    plunky 	.output_cmd =	btuart_output_cmd,
    126       1.18    plunky 	.output_acl =	btuart_output_acl,
    127       1.18    plunky 	.output_sco =	btuart_output_sco,
    128       1.18    plunky 	.get_stats =	btuart_stats,
    129       1.18    plunky 	.ipl =		IPL_TTY,
    130       1.14    plunky };
    131       1.14    plunky 
    132       1.18    plunky /*****************************************************************************
    133       1.18    plunky  *
    134       1.18    plunky  *	autoconf(9) functions
    135       1.18    plunky  */
    136        1.1  kiyohara 
    137       1.18    plunky /*
    138       1.18    plunky  * pseudo-device attach routine.
    139       1.18    plunky  */
    140        1.1  kiyohara void
    141        1.1  kiyohara btuartattach(int num __unused)
    142        1.1  kiyohara {
    143        1.1  kiyohara 	int error;
    144        1.1  kiyohara 
    145       1.18    plunky 	error = ttyldisc_attach(&btuart_disc);
    146        1.1  kiyohara 	if (error) {
    147        1.1  kiyohara 		aprint_error("%s: unable to register line discipline, "
    148        1.1  kiyohara 		    "error = %d\n", btuart_cd.cd_name, error);
    149       1.18    plunky 
    150        1.1  kiyohara 		return;
    151        1.1  kiyohara 	}
    152        1.1  kiyohara 
    153        1.1  kiyohara 	error = config_cfattach_attach(btuart_cd.cd_name, &btuart_ca);
    154        1.1  kiyohara 	if (error) {
    155        1.1  kiyohara 		aprint_error("%s: unable to register cfattach, error = %d\n",
    156        1.1  kiyohara 		    btuart_cd.cd_name, error);
    157       1.18    plunky 
    158        1.1  kiyohara 		config_cfdriver_detach(&btuart_cd);
    159       1.18    plunky 		(void) ttyldisc_detach(&btuart_disc);
    160        1.1  kiyohara 	}
    161        1.1  kiyohara }
    162        1.1  kiyohara 
    163        1.1  kiyohara /*
    164        1.1  kiyohara  * Autoconf match routine.
    165        1.1  kiyohara  */
    166        1.1  kiyohara static int
    167       1.23    cegger btuart_match(device_t self __unused, cfdata_t cfdata __unused,
    168       1.15  kiyohara 	     void *arg __unused)
    169        1.1  kiyohara {
    170        1.1  kiyohara 
    171        1.1  kiyohara 	/* pseudo-device; always present */
    172        1.1  kiyohara 	return 1;
    173        1.1  kiyohara }
    174        1.1  kiyohara 
    175        1.1  kiyohara /*
    176       1.18    plunky  * Autoconf attach routine.
    177       1.18    plunky  * Called by config_attach_pseudo(9) when we open the line discipline.
    178        1.1  kiyohara  */
    179        1.1  kiyohara static void
    180       1.15  kiyohara btuart_attach(device_t parent __unused, device_t self, void *aux __unused)
    181        1.1  kiyohara {
    182        1.1  kiyohara 	struct btuart_softc *sc = device_private(self);
    183        1.1  kiyohara 
    184       1.10    plunky 	sc->sc_dev = self;
    185       1.10    plunky 
    186       1.14    plunky 	MBUFQ_INIT(&sc->sc_cmdq);
    187       1.14    plunky 	MBUFQ_INIT(&sc->sc_aclq);
    188       1.14    plunky 	MBUFQ_INIT(&sc->sc_scoq);
    189       1.14    plunky 
    190        1.1  kiyohara 	/* Attach Bluetooth unit */
    191  1.26.12.1       tls 	sc->sc_unit = hci_attach_pcb(&btuart_hci, self, 0);
    192       1.18    plunky 	if (sc->sc_unit == NULL)
    193       1.18    plunky 		aprint_error_dev(self, "HCI attach failed\n");
    194        1.1  kiyohara }
    195        1.1  kiyohara 
    196        1.1  kiyohara /*
    197       1.18    plunky  * Autoconf detach routine.
    198       1.18    plunky  * Called when we close the line discipline.
    199        1.1  kiyohara  */
    200        1.1  kiyohara static int
    201       1.10    plunky btuart_detach(device_t self, int flags __unused)
    202        1.1  kiyohara {
    203        1.1  kiyohara 	struct btuart_softc *sc = device_private(self);
    204        1.1  kiyohara 
    205       1.18    plunky 	btuart_disable(self);
    206       1.18    plunky 
    207       1.14    plunky 	if (sc->sc_unit) {
    208  1.26.12.1       tls 		hci_detach_pcb(sc->sc_unit);
    209       1.14    plunky 		sc->sc_unit = NULL;
    210       1.14    plunky 	}
    211        1.1  kiyohara 
    212        1.1  kiyohara 	return 0;
    213        1.1  kiyohara }
    214        1.1  kiyohara 
    215       1.18    plunky /*****************************************************************************
    216       1.18    plunky  *
    217       1.18    plunky  *	Line discipline functions.
    218        1.1  kiyohara  */
    219        1.1  kiyohara 
    220        1.1  kiyohara static int
    221       1.18    plunky btuartopen(dev_t devno __unused, struct tty *tp)
    222        1.1  kiyohara {
    223        1.1  kiyohara 	struct btuart_softc *sc;
    224       1.15  kiyohara 	device_t dev;
    225       1.23    cegger 	cfdata_t cfdata;
    226        1.1  kiyohara 	struct lwp *l = curlwp;		/* XXX */
    227        1.1  kiyohara 	int error, unit, s;
    228        1.1  kiyohara 
    229       1.22      elad 	error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_BLUETOOTH_BTUART,
    230       1.22      elad 	    KAUTH_ARG(KAUTH_REQ_DEVICE_BLUETOOTH_BTUART_ADD), NULL, NULL, NULL);
    231       1.22      elad 	if (error)
    232       1.22      elad 		return (error);
    233        1.1  kiyohara 
    234        1.1  kiyohara 	s = spltty();
    235        1.1  kiyohara 
    236       1.18    plunky 	if (tp->t_linesw == &btuart_disc) {
    237       1.18    plunky 		sc = tp->t_sc;
    238        1.1  kiyohara 		if (sc != NULL) {
    239        1.1  kiyohara 			splx(s);
    240        1.1  kiyohara 			return EBUSY;
    241        1.1  kiyohara 		}
    242        1.1  kiyohara 	}
    243        1.1  kiyohara 
    244        1.1  kiyohara 	KASSERT(tp->t_oproc != NULL);
    245        1.1  kiyohara 
    246        1.1  kiyohara 	cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
    247        1.1  kiyohara 	for (unit = 0; unit < btuart_cd.cd_ndevs; unit++)
    248       1.19    cegger 		if (device_lookup(&btuart_cd, unit) == NULL)
    249        1.1  kiyohara 			break;
    250       1.18    plunky 
    251       1.18    plunky 	cfdata->cf_name = btuart_cd.cd_name;
    252       1.18    plunky 	cfdata->cf_atname = btuart_cd.cd_name;
    253        1.1  kiyohara 	cfdata->cf_unit = unit;
    254        1.3    plunky 	cfdata->cf_fstate = FSTATE_STAR;
    255        1.1  kiyohara 
    256       1.15  kiyohara 	dev = config_attach_pseudo(cfdata);
    257       1.15  kiyohara 	if (dev == NULL) {
    258       1.18    plunky 		free(cfdata, M_DEVBUF);
    259        1.1  kiyohara 		splx(s);
    260        1.1  kiyohara 		return EIO;
    261        1.1  kiyohara 	}
    262       1.15  kiyohara 	sc = device_private(dev);
    263       1.18    plunky 
    264       1.20  christos 	aprint_normal_dev(dev, "major %llu minor %llu\n",
    265       1.20  christos 	    (unsigned long long)major(tp->t_dev),
    266       1.20  christos 	    (unsigned long long)minor(tp->t_dev));
    267       1.18    plunky 
    268       1.18    plunky 	sc->sc_tp = tp;
    269       1.18    plunky 	tp->t_sc = sc;
    270       1.18    plunky 
    271       1.11        ad 	mutex_spin_enter(&tty_lock);
    272        1.1  kiyohara 	ttyflush(tp, FREAD | FWRITE);
    273       1.11        ad 	mutex_spin_exit(&tty_lock);
    274        1.1  kiyohara 
    275        1.1  kiyohara 	splx(s);
    276        1.1  kiyohara 
    277        1.1  kiyohara 	return 0;
    278        1.1  kiyohara }
    279        1.1  kiyohara 
    280        1.1  kiyohara static int
    281       1.18    plunky btuartclose(struct tty *tp, int flag __unused)
    282        1.1  kiyohara {
    283       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    284       1.23    cegger 	cfdata_t cfdata;
    285       1.18    plunky 	int s;
    286        1.1  kiyohara 
    287       1.18    plunky 	s = spltty();
    288        1.1  kiyohara 
    289       1.11        ad 	mutex_spin_enter(&tty_lock);
    290        1.1  kiyohara 	ttyflush(tp, FREAD | FWRITE);
    291       1.11        ad 	mutex_spin_exit(&tty_lock);	/* XXX */
    292       1.18    plunky 
    293        1.1  kiyohara 	ttyldisc_release(tp->t_linesw);
    294        1.1  kiyohara 	tp->t_linesw = ttyldisc_default();
    295       1.18    plunky 
    296        1.1  kiyohara 	if (sc != NULL) {
    297        1.1  kiyohara 		tp->t_sc = NULL;
    298        1.1  kiyohara 		if (sc->sc_tp == tp) {
    299       1.10    plunky 			cfdata = device_cfdata(sc->sc_dev);
    300       1.10    plunky 			config_detach(sc->sc_dev, 0);
    301        1.1  kiyohara 			free(cfdata, M_DEVBUF);
    302        1.1  kiyohara 		}
    303       1.18    plunky 	}
    304        1.1  kiyohara 
    305        1.1  kiyohara 	splx(s);
    306       1.18    plunky 
    307        1.1  kiyohara 	return 0;
    308        1.1  kiyohara }
    309        1.1  kiyohara 
    310        1.1  kiyohara static int
    311       1.18    plunky btuartioctl(struct tty *tp, u_long cmd, void *data __unused,
    312        1.1  kiyohara     int flag __unused, struct lwp *l __unused)
    313        1.1  kiyohara {
    314       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    315       1.18    plunky 	int error;
    316        1.1  kiyohara 
    317        1.1  kiyohara 	if (sc == NULL || tp != sc->sc_tp)
    318        1.1  kiyohara 		return EPASSTHROUGH;
    319        1.1  kiyohara 
    320       1.18    plunky 	switch(cmd) {
    321        1.1  kiyohara 	default:
    322        1.1  kiyohara 		error = EPASSTHROUGH;
    323        1.1  kiyohara 		break;
    324        1.1  kiyohara 	}
    325        1.1  kiyohara 
    326        1.1  kiyohara 	return error;
    327        1.1  kiyohara }
    328        1.1  kiyohara 
    329        1.1  kiyohara static int
    330       1.18    plunky btuartinput(int c, struct tty *tp)
    331        1.1  kiyohara {
    332       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    333        1.1  kiyohara 	struct mbuf *m = sc->sc_rxp;
    334        1.1  kiyohara 	int space = 0;
    335        1.1  kiyohara 
    336       1.18    plunky 	if (!sc->sc_enabled)
    337       1.18    plunky 		return 0;
    338       1.18    plunky 
    339        1.1  kiyohara 	c &= TTY_CHARMASK;
    340        1.1  kiyohara 
    341        1.1  kiyohara 	/* If we already started a packet, find the trailing end of it. */
    342        1.1  kiyohara 	if (m) {
    343        1.1  kiyohara 		while (m->m_next)
    344        1.1  kiyohara 			m = m->m_next;
    345        1.1  kiyohara 
    346        1.1  kiyohara 		space = M_TRAILINGSPACE(m);
    347        1.1  kiyohara 	}
    348        1.1  kiyohara 
    349        1.1  kiyohara 	if (space == 0) {
    350        1.1  kiyohara 		if (m == NULL) {
    351        1.1  kiyohara 			/* new packet */
    352        1.1  kiyohara 			MGETHDR(m, M_DONTWAIT, MT_DATA);
    353        1.1  kiyohara 			if (m == NULL) {
    354       1.24  kiyohara 				aprint_error_dev(sc->sc_dev, "out of memory\n");
    355       1.14    plunky 				sc->sc_stats.err_rx++;
    356        1.1  kiyohara 				return 0;	/* (lost sync) */
    357        1.1  kiyohara 			}
    358        1.1  kiyohara 
    359        1.1  kiyohara 			sc->sc_rxp = m;
    360        1.1  kiyohara 			m->m_pkthdr.len = m->m_len = 0;
    361        1.1  kiyohara 			space = MHLEN;
    362        1.1  kiyohara 
    363        1.1  kiyohara 			sc->sc_state = BTUART_RECV_PKT_TYPE;
    364        1.1  kiyohara 			sc->sc_want = 1;
    365        1.1  kiyohara 		} else {
    366        1.1  kiyohara 			/* extend mbuf */
    367        1.1  kiyohara 			MGET(m->m_next, M_DONTWAIT, MT_DATA);
    368        1.1  kiyohara 			if (m->m_next == NULL) {
    369       1.24  kiyohara 				aprint_error_dev(sc->sc_dev, "out of memory\n");
    370       1.14    plunky 				sc->sc_stats.err_rx++;
    371        1.1  kiyohara 				return 0;	/* (lost sync) */
    372        1.1  kiyohara 			}
    373        1.1  kiyohara 
    374        1.1  kiyohara 			m = m->m_next;
    375        1.1  kiyohara 			m->m_len = 0;
    376        1.1  kiyohara 			space = MLEN;
    377        1.1  kiyohara 
    378        1.1  kiyohara 			if (sc->sc_want > MINCLSIZE) {
    379        1.1  kiyohara 				MCLGET(m, M_DONTWAIT);
    380        1.1  kiyohara 				if (m->m_flags & M_EXT)
    381        1.1  kiyohara 					space = MCLBYTES;
    382        1.1  kiyohara 			}
    383        1.1  kiyohara 		}
    384        1.1  kiyohara 	}
    385        1.1  kiyohara 
    386        1.1  kiyohara 	mtod(m, uint8_t *)[m->m_len++] = c;
    387        1.1  kiyohara 	sc->sc_rxp->m_pkthdr.len++;
    388       1.14    plunky 	sc->sc_stats.byte_rx++;
    389        1.1  kiyohara 
    390        1.1  kiyohara 	sc->sc_want--;
    391        1.1  kiyohara 	if (sc->sc_want > 0)
    392        1.1  kiyohara 		return 0;	/* want more */
    393        1.1  kiyohara 
    394        1.1  kiyohara 	switch (sc->sc_state) {
    395        1.1  kiyohara 	case BTUART_RECV_PKT_TYPE:	/* Got packet type */
    396        1.1  kiyohara 
    397        1.1  kiyohara 		switch (c) {
    398        1.1  kiyohara 		case HCI_ACL_DATA_PKT:
    399        1.1  kiyohara 			sc->sc_state = BTUART_RECV_ACL_HDR;
    400        1.1  kiyohara 			sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
    401        1.1  kiyohara 			break;
    402        1.1  kiyohara 
    403        1.1  kiyohara 		case HCI_SCO_DATA_PKT:
    404        1.1  kiyohara 			sc->sc_state = BTUART_RECV_SCO_HDR;
    405        1.1  kiyohara 			sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
    406        1.1  kiyohara 			break;
    407        1.1  kiyohara 
    408        1.1  kiyohara 		case HCI_EVENT_PKT:
    409        1.1  kiyohara 			sc->sc_state = BTUART_RECV_EVENT_HDR;
    410        1.1  kiyohara 			sc->sc_want = sizeof(hci_event_hdr_t) - 1;
    411        1.1  kiyohara 			break;
    412        1.1  kiyohara 
    413        1.1  kiyohara 		default:
    414       1.13    plunky 			aprint_error_dev(sc->sc_dev,
    415       1.13    plunky 			    "Unknown packet type=%#x!\n", c);
    416       1.14    plunky 			sc->sc_stats.err_rx++;
    417        1.1  kiyohara 			m_freem(sc->sc_rxp);
    418        1.1  kiyohara 			sc->sc_rxp = NULL;
    419        1.1  kiyohara 			return 0;	/* (lost sync) */
    420        1.1  kiyohara 		}
    421        1.1  kiyohara 
    422        1.1  kiyohara 		break;
    423        1.1  kiyohara 
    424        1.1  kiyohara 	/*
    425        1.1  kiyohara 	 * we assume (correctly of course :) that the packet headers all fit
    426        1.1  kiyohara 	 * into a single pkthdr mbuf
    427        1.1  kiyohara 	 */
    428        1.1  kiyohara 	case BTUART_RECV_ACL_HDR:	/* Got ACL Header */
    429        1.1  kiyohara 		sc->sc_state = BTUART_RECV_ACL_DATA;
    430        1.1  kiyohara 		sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
    431        1.1  kiyohara 		sc->sc_want = le16toh(sc->sc_want);
    432        1.1  kiyohara 		break;
    433        1.1  kiyohara 
    434        1.1  kiyohara 	case BTUART_RECV_SCO_HDR:	/* Got SCO Header */
    435        1.1  kiyohara 		sc->sc_state = BTUART_RECV_SCO_DATA;
    436        1.1  kiyohara 		sc->sc_want =  mtod(m, hci_scodata_hdr_t *)->length;
    437        1.1  kiyohara 		break;
    438        1.1  kiyohara 
    439        1.1  kiyohara 	case BTUART_RECV_EVENT_HDR:	/* Got Event Header */
    440        1.1  kiyohara 		sc->sc_state = BTUART_RECV_EVENT_DATA;
    441        1.1  kiyohara 		sc->sc_want =  mtod(m, hci_event_hdr_t *)->length;
    442        1.1  kiyohara 		break;
    443        1.1  kiyohara 
    444        1.1  kiyohara 	case BTUART_RECV_ACL_DATA:	/* ACL Packet Complete */
    445       1.18    plunky 		if (!hci_input_acl(sc->sc_unit, sc->sc_rxp))
    446       1.14    plunky 			sc->sc_stats.err_rx++;
    447       1.14    plunky 
    448       1.14    plunky 		sc->sc_stats.acl_rx++;
    449        1.1  kiyohara 		sc->sc_rxp = m = NULL;
    450        1.1  kiyohara 		break;
    451        1.1  kiyohara 
    452        1.1  kiyohara 	case BTUART_RECV_SCO_DATA:	/* SCO Packet Complete */
    453       1.18    plunky 		if (!hci_input_sco(sc->sc_unit, sc->sc_rxp))
    454       1.14    plunky 			sc->sc_stats.err_rx++;
    455       1.14    plunky 
    456       1.14    plunky 		sc->sc_stats.sco_rx++;
    457        1.1  kiyohara 		sc->sc_rxp = m = NULL;
    458        1.1  kiyohara 		break;
    459        1.1  kiyohara 
    460        1.1  kiyohara 	case BTUART_RECV_EVENT_DATA:	/* Event Packet Complete */
    461       1.18    plunky 		if (!hci_input_event(sc->sc_unit, sc->sc_rxp))
    462       1.14    plunky 			sc->sc_stats.err_rx++;
    463       1.14    plunky 
    464       1.14    plunky 		sc->sc_stats.evt_rx++;
    465        1.1  kiyohara 		sc->sc_rxp = m = NULL;
    466        1.1  kiyohara 		break;
    467        1.1  kiyohara 
    468        1.1  kiyohara 	default:
    469        1.1  kiyohara 		panic("%s: invalid state %d!\n",
    470       1.10    plunky 		    device_xname(sc->sc_dev), sc->sc_state);
    471        1.1  kiyohara 	}
    472        1.1  kiyohara 
    473        1.1  kiyohara 	return 0;
    474        1.1  kiyohara }
    475        1.1  kiyohara 
    476        1.1  kiyohara static int
    477       1.18    plunky btuartstart(struct tty *tp)
    478        1.1  kiyohara {
    479       1.18    plunky 	struct btuart_softc *sc = tp->t_sc;
    480        1.1  kiyohara 	struct mbuf *m;
    481        1.1  kiyohara 	int count, rlen;
    482        1.1  kiyohara 	uint8_t *rptr;
    483        1.1  kiyohara 
    484       1.18    plunky 	if (!sc->sc_enabled)
    485       1.18    plunky 		return 0;
    486       1.18    plunky 
    487        1.1  kiyohara 	m = sc->sc_txp;
    488        1.1  kiyohara 	if (m == NULL) {
    489       1.18    plunky 		if (MBUFQ_FIRST(&sc->sc_cmdq)) {
    490       1.18    plunky 			MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
    491       1.18    plunky 			sc->sc_stats.cmd_tx++;
    492       1.18    plunky 		} else if (MBUFQ_FIRST(&sc->sc_scoq)) {
    493       1.18    plunky 			MBUFQ_DEQUEUE(&sc->sc_scoq, m);
    494       1.18    plunky 			sc->sc_stats.sco_tx++;
    495       1.18    plunky 		} else if (MBUFQ_FIRST(&sc->sc_aclq)) {
    496       1.18    plunky 			MBUFQ_DEQUEUE(&sc->sc_aclq, m);
    497       1.18    plunky 			sc->sc_stats.acl_tx++;
    498       1.18    plunky 		} else {
    499       1.18    plunky 			sc->sc_xmit = false;
    500       1.18    plunky 			return 0; /* no more to send */
    501       1.18    plunky 		}
    502       1.18    plunky 
    503       1.18    plunky 		sc->sc_txp = m;
    504       1.18    plunky 		sc->sc_xmit = true;
    505        1.1  kiyohara 	}
    506        1.1  kiyohara 
    507        1.1  kiyohara 	count = 0;
    508        1.1  kiyohara 	rlen = 0;
    509        1.1  kiyohara 	rptr = mtod(m, uint8_t *);
    510        1.1  kiyohara 
    511        1.1  kiyohara 	for(;;) {
    512        1.1  kiyohara 		if (rlen >= m->m_len) {
    513        1.1  kiyohara 			m = m->m_next;
    514        1.1  kiyohara 			if (m == NULL) {
    515        1.1  kiyohara 				m = sc->sc_txp;
    516        1.1  kiyohara 				sc->sc_txp = NULL;
    517        1.1  kiyohara 
    518        1.1  kiyohara 				if (M_GETCTX(m, void *) == NULL)
    519        1.1  kiyohara 					m_freem(m);
    520       1.14    plunky 				else if (!hci_complete_sco(sc->sc_unit, m))
    521       1.14    plunky 					sc->sc_stats.err_tx++;
    522        1.1  kiyohara 
    523        1.1  kiyohara 				break;
    524        1.1  kiyohara 			}
    525        1.1  kiyohara 
    526        1.1  kiyohara 			rlen = 0;
    527        1.1  kiyohara 			rptr = mtod(m, uint8_t *);
    528        1.1  kiyohara 			continue;
    529        1.1  kiyohara 		}
    530        1.1  kiyohara 
    531        1.1  kiyohara 		if (putc(*rptr++, &tp->t_outq) < 0) {
    532        1.1  kiyohara 			m_adj(m, rlen);
    533        1.1  kiyohara 			break;
    534        1.1  kiyohara 		}
    535        1.1  kiyohara 		rlen++;
    536        1.1  kiyohara 		count++;
    537        1.1  kiyohara 	}
    538        1.1  kiyohara 
    539       1.14    plunky 	sc->sc_stats.byte_tx += count;
    540        1.1  kiyohara 
    541        1.1  kiyohara 	if (tp->t_outq.c_cc != 0)
    542        1.1  kiyohara 		(*tp->t_oproc)(tp);
    543        1.1  kiyohara 
    544        1.1  kiyohara 	return 0;
    545        1.1  kiyohara }
    546        1.1  kiyohara 
    547       1.18    plunky /*****************************************************************************
    548       1.18    plunky  *
    549       1.18    plunky  *	bluetooth(9) functions
    550       1.18    plunky  */
    551        1.1  kiyohara 
    552        1.1  kiyohara static int
    553       1.18    plunky btuart_enable(device_t self)
    554        1.1  kiyohara {
    555       1.12    plunky 	struct btuart_softc *sc = device_private(self);
    556       1.14    plunky 	int s;
    557        1.1  kiyohara 
    558       1.18    plunky 	if (sc->sc_enabled)
    559        1.1  kiyohara 		return 0;
    560        1.1  kiyohara 
    561       1.14    plunky 	s = spltty();
    562       1.14    plunky 
    563       1.18    plunky 	sc->sc_enabled = true;
    564       1.18    plunky 	sc->sc_xmit = false;
    565       1.14    plunky 
    566       1.14    plunky 	splx(s);
    567        1.1  kiyohara 
    568        1.1  kiyohara 	return 0;
    569        1.1  kiyohara }
    570        1.1  kiyohara 
    571        1.1  kiyohara static void
    572       1.18    plunky btuart_disable(device_t self)
    573        1.1  kiyohara {
    574       1.12    plunky 	struct btuart_softc *sc = device_private(self);
    575       1.14    plunky 	int s;
    576        1.1  kiyohara 
    577       1.18    plunky 	if (!sc->sc_enabled)
    578        1.1  kiyohara 		return;
    579        1.1  kiyohara 
    580       1.14    plunky 	s = spltty();
    581       1.14    plunky 
    582        1.1  kiyohara 	if (sc->sc_rxp) {
    583        1.1  kiyohara 		m_freem(sc->sc_rxp);
    584        1.1  kiyohara 		sc->sc_rxp = NULL;
    585        1.1  kiyohara 	}
    586        1.1  kiyohara 
    587        1.1  kiyohara 	if (sc->sc_txp) {
    588        1.1  kiyohara 		m_freem(sc->sc_txp);
    589        1.1  kiyohara 		sc->sc_txp = NULL;
    590        1.1  kiyohara 	}
    591        1.1  kiyohara 
    592       1.14    plunky 	MBUFQ_DRAIN(&sc->sc_cmdq);
    593       1.14    plunky 	MBUFQ_DRAIN(&sc->sc_aclq);
    594       1.14    plunky 	MBUFQ_DRAIN(&sc->sc_scoq);
    595       1.14    plunky 
    596       1.18    plunky 	sc->sc_enabled = false;
    597       1.14    plunky 
    598       1.14    plunky 	splx(s);
    599        1.1  kiyohara }
    600        1.1  kiyohara 
    601        1.1  kiyohara static void
    602       1.18    plunky btuart_output_cmd(device_t self, struct mbuf *m)
    603       1.14    plunky {
    604       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    605       1.14    plunky 	int s;
    606       1.14    plunky 
    607       1.18    plunky 	KASSERT(sc->sc_enabled);
    608       1.14    plunky 
    609       1.14    plunky 	M_SETCTX(m, NULL);
    610       1.14    plunky 
    611       1.14    plunky 	s = spltty();
    612       1.14    plunky 	MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
    613       1.18    plunky 	if (!sc->sc_xmit)
    614       1.18    plunky 		btuartstart(sc->sc_tp);
    615       1.14    plunky 
    616       1.14    plunky 	splx(s);
    617       1.14    plunky }
    618       1.14    plunky 
    619       1.14    plunky static void
    620       1.18    plunky btuart_output_acl(device_t self, struct mbuf *m)
    621       1.14    plunky {
    622       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    623       1.14    plunky 	int s;
    624       1.14    plunky 
    625       1.18    plunky 	KASSERT(sc->sc_enabled);
    626       1.14    plunky 
    627       1.14    plunky 	M_SETCTX(m, NULL);
    628       1.14    plunky 
    629       1.14    plunky 	s = spltty();
    630       1.14    plunky 	MBUFQ_ENQUEUE(&sc->sc_aclq, m);
    631       1.18    plunky 	if (!sc->sc_xmit)
    632       1.18    plunky 		btuartstart(sc->sc_tp);
    633       1.14    plunky 
    634       1.14    plunky 	splx(s);
    635       1.14    plunky }
    636       1.14    plunky 
    637       1.14    plunky static void
    638       1.18    plunky btuart_output_sco(device_t self, struct mbuf *m)
    639       1.14    plunky {
    640       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    641       1.14    plunky 	int s;
    642       1.14    plunky 
    643       1.18    plunky 	KASSERT(sc->sc_enabled);
    644       1.14    plunky 
    645       1.14    plunky 	s = spltty();
    646       1.14    plunky 	MBUFQ_ENQUEUE(&sc->sc_scoq, m);
    647       1.18    plunky 	if (!sc->sc_xmit)
    648       1.18    plunky 		btuartstart(sc->sc_tp);
    649       1.14    plunky 
    650       1.14    plunky 	splx(s);
    651       1.14    plunky }
    652       1.14    plunky 
    653       1.14    plunky static void
    654       1.18    plunky btuart_stats(device_t self, struct bt_stats *dest, int flush)
    655       1.14    plunky {
    656       1.14    plunky 	struct btuart_softc *sc = device_private(self);
    657       1.14    plunky 	int s;
    658       1.14    plunky 
    659       1.14    plunky 	s = spltty();
    660       1.14    plunky 
    661       1.14    plunky 	memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
    662       1.14    plunky 
    663       1.14    plunky 	if (flush)
    664       1.14    plunky 		memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
    665       1.14    plunky 
    666       1.14    plunky 	splx(s);
    667       1.14    plunky }
    668