Subject: Fw: BCSP (BlueCore Serial Protocol)
To: None <current-users@netbsd.org>
From: KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp>
List: current-users
Date: 09/24/2007 03:42:44
----Next_Part(Mon_Sep_24_03_42_44_2007_020)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi! all,


hmm...  The E-mail that I had posted this morning did lost?  X-<
It post again. 

Thanks,
--
kiyohara

----Next_Part(Mon_Sep_24_03_42_44_2007_020)--
Content-Type: Message/Rfc822
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Date: Sun, 23 Sep 2007 04:54:35 +0900 (JST)
Message-Id: <20070923.045435.133999804.kiyohara@kk.iij4u.or.jp>
To: current-users@netbsd.org
Subject: BCSP (BlueCore Serial Protocol)
From: KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp>
Mime-Version: 1.0
Content-Type: Multipart/Mixed;
 boundary="--Next_Part(Sun_Sep_23_04_54_36_2007_094)--"
Content-Transfer-Encoding: 7bit

----Next_Part(Sun_Sep_23_04_54_36_2007_094)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi! all,


BCSP is supported by bcsp(4).
I tested on hpcsh with 2 cards.  (only 'inq' ;-)
# TDK Bluetooth PC Card, BELKIN Bluetooth PDA Adapter Card.

You can try following command.

  # btuartd -p bcsp /dev/dty?? 115200 &
  # btconfig bcsp0 up

  # btconfig bcsp0 inq    (or other commands)


By the way, I think that the BCCMD utility (bccmdutil(8)) in addition to
the support of bcsp(4) is necessary.
LSI of BCSP and CSR changes the speed by BCCMD according to my memory.


An important thing is that I do not have time however.  For the support
of other machines and other devices.  ;-)
# MV88Fxx81 (KURO-BOX/PRO)

Thanks,
--
kiyohara


----Next_Part(Sun_Sep_23_04_54_36_2007_094)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="bcsp.diff"

? share/man/man4/bcsp.4
? sys/dev/bluetooth/bcsp.c
? sys/dev/bluetooth/bcsp.h
Index: distrib/sets/lists/man/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.1023
diff -u -r1.1023 mi
--- distrib/sets/lists/man/mi	3 Sep 2007 18:02:17 -0000	1.1023
+++ distrib/sets/lists/man/mi	22 Sep 2007 19:12:13 -0000
@@ -723,6 +723,7 @@
 ./usr/share/man/cat4/azalia.0			man-sys-catman		.cat
 ./usr/share/man/cat4/bba.0			man-sys-catman		.cat
 ./usr/share/man/cat4/bce.0			man-sys-catman		.cat
+./usr/share/man/cat4/bcsp.0			man-sys-catman		.cat
 ./usr/share/man/cat4/be.0			man-sys-catman		.cat
 ./usr/share/man/cat4/bge.0			man-sys-catman		.cat
 ./usr/share/man/cat4/bha.0			man-sys-catman		.cat
@@ -3208,6 +3209,7 @@
 ./usr/share/man/man4/azalia.4			man-sys-man		.man
 ./usr/share/man/man4/bba.4			man-sys-man		.man
 ./usr/share/man/man4/bce.4			man-sys-man		.man
+./usr/share/man/man4/bcsp.4			man-sys-man		.man
 ./usr/share/man/man4/be.4			man-sys-man		.man
 ./usr/share/man/man4/bge.4			man-sys-man		.man
 ./usr/share/man/man4/bha.4			man-sys-man		.man
Index: etc/bluetooth/btuartd.conf
===================================================================
RCS file: /cvsroot/src/etc/bluetooth/btuartd.conf,v
retrieving revision 1.1
diff -u -r1.1 btuartd.conf
--- etc/bluetooth/btuartd.conf	20 Feb 2007 16:56:10 -0000	1.1
+++ etc/bluetooth/btuartd.conf	22 Sep 2007 19:12:26 -0000
@@ -6,4 +6,50 @@
 #
 # See also btuartd(8)
 #
-#btuart	at </dev/dty00> type <*> speed <115200> [flow] [init_speed <57600>]
+#btuart	at </dev/dty00> type <*> speed <115200> \
+#                                       [flow|parity [odd]] [init_speed <57600>]
+#
+# Examples from hciattach(8) of bluez.
+#
+#btuart	at /dev/dty00 type bcm2035  speed 115200 flow init_speed 115200
+#btuart	at /dev/dty01 type bcsp     speed  38400 parity init_speed 115200
+#btuart	at /dev/dty02 type csr      speed 115200 flow init_speed 115200
+#btuart	at /dev/dty03 type digi     speed 115200 flow
+#btuart	at /dev/dty04 type ericsson speed 115200 flow init_speed 57600
+#btuart	at /dev/dty05 type texas    speed 115200 flow init_speed 115200
+#btuart	at /dev/dty06 type st       speed 115200 flow init_speed 57600
+#btuart	at /dev/dty07 type stlc2500 speed 115200 flow init_speed 115200
+#btuart	at /dev/dty08 type swave    speed 115200 flow init_speed 115200
+
+
+# Billionton PCBTC1 PCMCIA Card
+# BELKIN Bluetooth PDA Adapter Card F8T020
+# COM One Platinium Bluetooth PC Card
+# Sitecom CN-504 PCMCIA Card
+# TDK Bluetooth PC Card and IBM Bluetooth PC Card II
+# Zoom Bluetooth PCMCIA Card
+#
+#btuart	at /dev/dty01 type bcsp     speed 115200 parity init_speed 115200
+
+# Socket Bluetooth CF Card (Rev G)
+#
+#btuart	at /dev/dty01 type bcsp     speed 230400 parity init_speed 230400
+
+# 3Com Bluetooth Card (Version 3.0)
+#
+#btuart	at /dev/dty02 type csr      speed 115200 flow init_speed 115200
+
+# AmbiCom BT2000C Bluetooth PC/CF Card
+# 
+#btuart	at /dev/dty02 type csr      speed 460800 flow init_speed 57600
+
+# Gumstix
+#
+#btuart	at /dev/dty04 type ericsson speed 921600 init_speed 57600
+
+# Inventel BlueBird Module
+# Philips generic Ericsson IP core based
+# Sphinx Electronics PICO Card
+# Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter
+#
+#btuart	at /dev/dty09 type *        speed 115200 flow init_speed 115200
Index: share/man/man4/Makefile
===================================================================
RCS file: /cvsroot/src/share/man/man4/Makefile,v
retrieving revision 1.440
diff -u -r1.440 Makefile
--- share/man/man4/Makefile	3 Sep 2007 18:02:16 -0000	1.440
+++ share/man/man4/Makefile	22 Sep 2007 19:14:14 -0000
@@ -8,7 +8,8 @@
 	ath.4 atppc.4 attimer.4 atw.4 \
 	auacer.4 audio.4 audiocs.4 auich.4 \
 	auixp.4 autri.4 auvia.4 awi.4 azalia.4 \
-	bba.4 bce.4 be.4 bge.4 bnx.4 bha.4 bio.4 bktr.4 bluetooth.4 bmtphy.4 \
+	bba.4 bce.4 bcsp.4 be.4 bge.4 bnx.4 bha.4 \
+	bio.4 bktr.4 bluetooth.4 bmtphy.4 \
 	bpf.4 brgphy.4 bridge.4 bthidev.4 bthub.4 btkbd.4 btms.4 btsco.4 \
 	btuart.4 cac.4 cardbus.4 carp.4 ccd.4 cd.4 \
 	cec.4 cgd.4 cfb.4 ch.4 chipsfb.4 ciphy.4 ciss.4 clcs.4 clct.4 clnp.4 \
Index: share/man/man4/bluetooth.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/bluetooth.4,v
retrieving revision 1.6
diff -u -r1.6 bluetooth.4
--- share/man/man4/bluetooth.4	21 Aug 2007 10:56:11 -0000	1.6
+++ share/man/man4/bluetooth.4	22 Sep 2007 19:14:14 -0000
@@ -30,7 +30,7 @@
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\"
-.Dd August 21, 2007
+.Dd September 20, 2007
 .Dt BLUETOOTH 4
 .Os
 .Sh NAME
@@ -367,6 +367,7 @@
 .Xr bind 2 ,
 .Xr getsockname 2 ,
 .Xr bluetooth 3 ,
+.Xr bcsp 4 ,
 .Xr bt3c 4 ,
 .Xr btbc 4 ,
 .Xr btuart 4 ,
Index: share/man/man4/btuart.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/btuart.4,v
retrieving revision 1.3
diff -u -r1.3 btuart.4
--- share/man/man4/btuart.4	2 Mar 2007 20:13:33 -0000	1.3
+++ share/man/man4/btuart.4	22 Sep 2007 19:14:14 -0000
@@ -24,7 +24,7 @@
 .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd February 19, 2007
+.Dd September 20, 2007
 .Dt BTUART 4
 .Os
 .Sh NAME
@@ -90,6 +90,7 @@
 driver.
 .El
 .Sh SEE ALSO
+.Xr bcsp 4
 .Xr bluetooth 4 ,
 .Xr btuartd 8
 .Sh HISTORY
Index: sys/dev/bluetooth/btuart.h
===================================================================
RCS file: /cvsroot/src/sys/dev/bluetooth/btuart.h,v
retrieving revision 1.1
diff -u -r1.1 btuart.h
--- sys/dev/bluetooth/btuart.h	20 Feb 2007 16:53:21 -0000	1.1
+++ sys/dev/bluetooth/btuart.h	22 Sep 2007 19:14:58 -0000
@@ -39,6 +39,7 @@
 #define BTUART_HCITYPE_STLC2500		7
 #define BTUART_HCITYPE_BT2000C		8
 #define BTUART_HCITYPE_BCM2035		9
+#define BTUART_HCITYPE_BCSP		10
 
 #define BTUART_INITSPEED	_IOW ('H', 2, uint32_t)
 #define BTUART_START		_IO  ('H', 3)
Index: sys/dev/bluetooth/files.bluetooth
===================================================================
RCS file: /cvsroot/src/sys/dev/bluetooth/files.bluetooth,v
retrieving revision 1.11
diff -u -r1.11 files.bluetooth
--- sys/dev/bluetooth/files.bluetooth	20 Feb 2007 16:53:21 -0000	1.11
+++ sys/dev/bluetooth/files.bluetooth	22 Sep 2007 19:14:58 -0000
@@ -35,3 +35,7 @@
 # Bluetooth HCI UART (H4)
 defpseudo btuart: btbus, bluetooth, firmload
 file dev/bluetooth/btuart.c		btuart
+
+# BlueCore Serial Protocol
+defpseudo bcsp: btbus, bluetooth
+file dev/bluetooth/bcsp.c		bcsp
Index: usr.sbin/btuartd/btuartd.8
===================================================================
RCS file: /cvsroot/src/usr.sbin/btuartd/btuartd.8,v
retrieving revision 1.4
diff -u -r1.4 btuartd.8
--- usr.sbin/btuartd/btuartd.8	12 Mar 2007 08:10:31 -0000	1.4
+++ usr.sbin/btuartd/btuartd.8	22 Sep 2007 19:15:43 -0000
@@ -26,7 +26,7 @@
 .\"
 .\" $Id: btuartd.8,v 1.4 2007/03/12 08:10:31 kiyohara Exp $
 .\"
-.Dd February 19, 2007
+.Dd September 22, 2007
 .Dt BTUARTD 8
 .Os
 .Sh NAME
@@ -38,6 +38,7 @@
 .Op Fl c Ar conffile
 .Nm
 .Op Fl f
+.Op Fl p Op Fl o
 .Op Fl i Ar init_speed
 .Op Ar type
 .Ar comdev speed
@@ -51,7 +52,7 @@
 .Xr com 4
 and compatible devices, also configures
 .Ar speed
-and flow.
+and flow, parity.
 The
 .Nm
 daemon supports HCI UART.
@@ -86,6 +87,8 @@
 Digianswer based cards
 .It Cm texas
 Texas Instruments
+.It Cm bcsp
+BCSP (BlueCore Serial Protocol)
 .It Cm csr
 Cambridge Silicon Radio Casira serial adapter or BrainBoxes serial dongle
 (BL642)
@@ -113,7 +116,13 @@
 Enable flow control as
 .Xr com 4 .
 .It Fl i Ar init_speed
-Specify the initial speed for the Bluetooth module.
+Specify the initial speed for the Bluetooth module. It first sets to this
+value, and it initializes it if specified. Afterwards, the speed is set to
+.Ar speed. 
+.It Fl o
+Enable odd parity, if enabled parity.
+.It Fl p
+Enable parity (even parity).
 .El
 .Sh FILES
 .Bl -tag -compact
@@ -121,6 +130,7 @@
 .It Pa /var/run/btuartd.pid
 .El
 .Sh SEE ALSO
+.Xr bcsp 4 ,
 .Xr bluetooth 4 ,
 .Xr btuart 4 ,
 .Xr btconfig 8
Index: usr.sbin/btuartd/btuartd.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/btuartd/btuartd.c,v
retrieving revision 1.2
diff -u -r1.2 btuartd.c
--- usr.sbin/btuartd/btuartd.c	12 Jun 2007 10:05:24 -0000	1.2
+++ usr.sbin/btuartd/btuartd.c	22 Sep 2007 19:15:44 -0000
@@ -58,13 +58,15 @@
 	char comdev[PATH_MAX];
 	int speed;
 	int flow;
+	int parity;
+	int odd;	/* odd parity */
 	int init_speed;
 };
 
 static void usage(void);
 static int read_config(int, struct btuartd_conf **, char *);
 static void btuartd_sigcaught(int);
-static int btuart_setting(int, int, int, int, int);
+static int btuart_setting(int, int, int, int, int, int, int);
 static int btuartd(int, struct btuartd_conf *);
 
 
@@ -83,6 +85,7 @@
 	{ "stlc2500",		BTUART_HCITYPE_STLC2500 },
 	{ "bt2000c",		BTUART_HCITYPE_BT2000C },
 	{ "bcm2035",		BTUART_HCITYPE_BCM2035 },
+	{ "bcsp",		BTUART_HCITYPE_BCSP },
 	{ "*",			BTUART_HCITYPE_ANY },
 	{ NULL },
 };
@@ -93,7 +96,7 @@
 {
 	const char *progname = getprogname();
 
-	printf("usage: %s [-f] [-i init_speed] [type] comdev speed\n",
+	printf("usage: %s [-f] [-p [-o]] [-i init_speed] [type] comdev speed\n",
 	    progname);
 	printf("       %s [-d] [-c conffile]\n", progname);
 	printf("    comdev: com device. e.g. /dev/dty00\n");
@@ -102,10 +105,12 @@
 }
 
 static int
-btuart_setting(int comfd, int type, int speed, int flow, int init_speed)
+btuart_setting(int comfd, int type, int speed, int flow, int parity, int odd,
+	       int init_speed)
 {
 	struct termios t;
 	int rv;
+	char *line;
 
 	tcflush(comfd, TCIOFLUSH);
 	if ((rv = tcgetattr(comfd, &t)) == -1) {
@@ -116,6 +121,11 @@
 	t.c_cflag |= CLOCAL;
 	if (flow)
 		t.c_cflag |= CRTSCTS;
+	if (parity) {
+		t.c_cflag |= PARENB;
+		if (odd)
+			t.c_cflag |= PARODD;
+	}
 
 	tcflush(comfd, TCIOFLUSH);
 	if ((rv = cfsetspeed(&t, speed)) == -1) {
@@ -127,12 +137,15 @@
 		return rv;
 	}
 
-	/* set btuart discipline */
-	if ((rv = ioctl(comfd, TIOCSLINED, "btuart")) == -1) {
+	/* set btuart or bcsp discipline */
+	line = (type != BTUART_HCITYPE_BCSP) ? "btuart" : "bcsp";
+	if ((rv = ioctl(comfd, TIOCSLINED, line)) == -1) {
 		syslog(LOG_ERR,
-		    "ioctl TIOCSLINE btuart failed: %s", strerror(errno));
+		    "ioctl TIOCSLINE %s failed: %s", line, strerror(errno));
 		return rv;
 	}
+	if (type == BTUART_HCITYPE_BCSP)
+		return rv;
 
 	if (init_speed != B0)
 		if ((rv = ioctl(comfd, BTUART_INITSPEED, &init_speed)) == -1) {
@@ -208,6 +221,8 @@
 		}
 		(*btuartd_conf)[nbtuart].type = hcitypetbl[j].hcitype;
 		(*btuartd_conf)[nbtuart].flow = 0;
+		(*btuartd_conf)[nbtuart].parity = 0;
+		(*btuartd_conf)[nbtuart].odd = 0;
 		(*btuartd_conf)[nbtuart].init_speed = B0;
 
 		while (1 /* CONSTCOND */) {
@@ -216,6 +231,10 @@
 
 			if (strstr(&buf[n], "flow") == &buf[n])
 				(*btuartd_conf)[nbtuart].flow = 1;
+			else if (strstr(&buf[n], "parity") == &buf[n])
+				(*btuartd_conf)[nbtuart].parity = 1;
+			else if (strstr(&buf[n], "odd") == &buf[n])
+				(*btuartd_conf)[nbtuart].odd = 1;
 			else if (strstr(&buf[n], "init_speed") == &buf[n]) {
 				n += strcspn(&buf[n], " \t");
 				n += strspn(&buf[n], " \t");
@@ -233,6 +252,8 @@
 		}
 		if (nbtuart == -1)
 			break;
+		if (!(*btuartd_conf)[nbtuart].parity)
+		    (*btuartd_conf)[nbtuart].odd = 0;
 		nbtuart++;
 	}
 	if (nbtuart < onbtuart && threshold > BTUARTD_CONF_MIN) {
@@ -284,7 +305,8 @@
 		    (btuartd_conf[i].flow == 1) ? " flow" : "", strbuf);
 		error = btuart_setting(comfd,
 		    btuartd_conf[i].type, btuartd_conf[i].speed,
-		    btuartd_conf[i].flow, btuartd_conf[i].init_speed);
+		    btuartd_conf[i].flow, btuartd_conf[i].parity,
+		    btuartd_conf[i].odd, btuartd_conf[i].init_speed);
 		if (error != 0) {
 			close(comfd);
 			syslog(LOG_ERR, "btuart setting failed: %s",
@@ -319,19 +341,19 @@
 	extern int optind;
 	struct btuartd_conf *btuartd_conf;
 	int nbtuart, ch, i, status;
-	int type, init_speed, flow, debug;
+	int type, init_speed, flow, parity, odd, debug;
 	char *conffile;
 	const char *progname = getprogname();
 
 	conffile = BTUARTD_CONFFILE;
 	init_speed = B0;
-	flow = 0;
+	flow = parity = odd = 0;
 	debug = 0;
 
 	nbtuart = 0;
 	btuartd_conf = malloc(sizeof(struct btuartd_conf) * BTUARTD_CONF_MIN);
 
-	while ((ch = getopt(argc, argv, "c:dfi:")) != -1) {
+	while ((ch = getopt(argc, argv, "c:dfi:op")) != -1) {
 		switch (ch) {
 		case 'c':
 			conffile = optarg;
@@ -349,6 +371,14 @@
 			init_speed = atoi(optarg);
 			break;
 
+		case 'o':
+			odd = 1;
+			break;
+
+		case 'p':
+			parity = 1;
+			break;
+
 		case '?':
 		default:
 			usage();
@@ -357,6 +387,9 @@
 	argc -= optind;
 	argv += optind;
 
+	if (!parity)
+		odd = 0;
+
 	openlog(progname, LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
 
 	if (argc == 0) {
@@ -403,6 +436,8 @@
 		    sizeof(btuartd_conf[0].comdev));;
 		btuartd_conf[0].speed = atoi(argv[1]);
 		btuartd_conf[0].flow = flow;
+		btuartd_conf[0].parity = parity;
+		btuartd_conf[0].odd = odd;
 		btuartd_conf[0].init_speed = init_speed;
 		nbtuart = 1;
 	}

----Next_Part(Sun_Sep_23_04_54_36_2007_094)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="bcsp.c"

/*	$NetBSD$	*/
/*
 * Copyright (c) 2007 KIYOHARA Takashi
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");

#include <sys/types.h>
#include <sys/param.h>
#include <sys/callout.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/kauth.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/syslimits.h>
#include <sys/systm.h>
#include <sys/tty.h>

#include <netbt/bluetooth.h>
#include <netbt/hci.h>

#include <dev/bluetooth/bcsp.h>
#include <dev/bluetooth/btuart.h>

#include "ioconf.h"

#ifdef BCSP_DEBUG
#undef DPRINTF
#undef DPRINTFN

#define DPRINTF(x)	printf x
#define DPRINTFN(n, x)	do { if (bcsp_debug > (n)) printf x; } while (0)
int bcsp_debug = 3;
#else
#undef DPRINTF
#undef DPRINTFN

#define DPRINTF(x)
#define DPRINTFN(n, x)
#endif

struct bcsp_softc {
	struct device sc_dev;

	struct tty *sc_tp;
	struct hci_unit sc_unit;		/* Bluetooth HCI Unit */

	int sc_baud;
	int sc_init_baud;

	/* variables of SLIP Layer */
	struct mbuf *sc_txp;			/* outgoing packet */
	struct mbuf *sc_rxp;			/* incoming packet */
	int sc_slip_txrsv;			/* reserved byte data */
	int sc_slip_rxexp;			/* expected byte data */
	void (*sc_transmit_callback)(struct bcsp_softc *, struct mbuf *);

	/* variables of Packet Integrity Layer */
	int sc_pi_txcrc;			/* use CRC, if true */

	/* variables of MUX Layer */
	bool sc_mux_send_ack;			/* flag for send_ack */
	bool sc_mux_choke;			/* Choke signal */
	struct timeval sc_mux_lastrx;		/* Last Rx Pkt Time */

	/* variables of Sequencing Layer */
	MBUFQ_HEAD() sc_seqq;			/* Sequencing Layer queue */
	MBUFQ_HEAD() sc_seq_retryq;		/* retry queue */
	uint32_t sc_seq_txseq;
	uint32_t sc_seq_txack;
	uint32_t sc_seq_expected_rxseq;
	uint32_t sc_seq_winspace;
	uint32_t sc_seq_retries;
	callout_t sc_seq_timer;
	uint32_t sc_seq_timeout;
	uint32_t sc_seq_winsize;
	uint32_t sc_seq_retry_limit;

	/* variables of Datagram Queue Layer */
	MBUFQ_HEAD() sc_dgq;			/* Datagram Queue Layer queue */

	/* variables of BCSP Link Establishment Protocol */
	bool sc_le_muzzled;
	bcsp_le_state_t sc_le_state;
	callout_t sc_le_timer;

	struct sysctllog *sc_log;		/* sysctl log */
};

void bcspattach(int);
static int bcsp_match(struct device *, struct cfdata *, void *);
static void bcsp_attach(struct device *, struct device *, void *);
static int bcsp_detach(struct device *, int);

/* tty functions */
static int bcspopen(dev_t, struct tty *);
static int bcspclose(struct tty *, int);
static int bcspioctl(struct tty *, u_long, void *, int, struct lwp *);

static int bcsp_slip_transmit(struct tty *);
static int bcsp_slip_receive(int, struct tty *);

static void bcsp_pktintegrity_transmit(struct bcsp_softc *);
static void bcsp_pktintegrity_receive(struct bcsp_softc *, struct mbuf *);
static void bcsp_crc_update(uint16_t *, uint8_t);
static uint16_t bcsp_crc_reverse(uint16_t);

static void bcsp_mux_transmit(struct bcsp_softc *sc);
static void bcsp_mux_receive(struct bcsp_softc *sc, struct mbuf *m);
static __inline void bcsp_send_ack_command(struct bcsp_softc *sc);
static __inline struct mbuf *bcsp_create_ackpkt(void);
static __inline void bcsp_set_choke(struct bcsp_softc *, bool);

static void bcsp_sequencing_receive(struct bcsp_softc *, struct mbuf *);
static bool bcsp_tx_reliable_pkt(struct bcsp_softc *, struct mbuf *, u_int);
static __inline u_int bcsp_get_txack(struct bcsp_softc *);
static void bcsp_signal_rxack(struct bcsp_softc *, uint32_t);
static void bcsp_reliabletx_callback(struct bcsp_softc *, struct mbuf *);
static void bcsp_timer_timeout(void *);
static void bcsp_sequencing_reset(struct bcsp_softc *);

static void bcsp_datagramq_receive(struct bcsp_softc *, struct mbuf *);
static bool bcsp_tx_unreliable_pkt(struct bcsp_softc *, struct mbuf *, u_int);
static void bcsp_unreliabletx_callback(struct bcsp_softc *, struct mbuf *);

static int bcsp_start_le(struct hci_unit *);
static void bcsp_terminate_le(struct hci_unit *);
static void bcsp_input_le(struct hci_unit *, struct mbuf *);
static void bcsp_le_timeout(void *);

/* bluetooth hci functions */
static int bcsp_enable(struct hci_unit *);
static void bcsp_disable(struct hci_unit *);
static void bcsp_start(struct hci_unit *);

#ifdef BCSP_DEBUG
static void bcsp_packet_print(struct mbuf *m);
#endif


/*
 * It doesn't need to be exported, as only bcspattach() uses it,
 * but there's no "official" way to make it static.
 */
CFATTACH_DECL(bcsp, sizeof(struct bcsp_softc),
    bcsp_match, bcsp_attach, bcsp_detach, NULL);

static struct linesw bcsp_disc = {
	.l_name = "bcsp",
	.l_open = bcspopen,
	.l_close = bcspclose,
	.l_read = ttyerrio,
	.l_write = ttyerrio,
	.l_ioctl = bcspioctl,
	.l_rint = bcsp_slip_receive,
	.l_start = bcsp_slip_transmit,
	.l_modem = ttymodem,
	.l_poll = ttyerrpoll
};


/* ARGSUSED */
void
bcspattach(int num __unused)
{
	int error;

	error = ttyldisc_attach(&bcsp_disc);
	if (error) {
		aprint_error("%s: unable to register line discipline, "
		    "error = %d\n", bcsp_cd.cd_name, error);
		return;
	}

	error = config_cfattach_attach(bcsp_cd.cd_name, &bcsp_ca);
	if (error) {
		aprint_error("%s: unable to register cfattach, error = %d\n",
		    bcsp_cd.cd_name, error);
		config_cfdriver_detach(&bcsp_cd);
		(void) ttyldisc_detach(&bcsp_disc);
	}
}

/*
 * Autoconf match routine.
 *
 * XXX: unused: config_attach_pseudo(9) does not call ca_match.
 */
/* ARGSUSED */
static int
bcsp_match(struct device *self __unused, struct cfdata *cfdata __unused,
	   void *arg __unused)
{

	/* pseudo-device; always present */
	return 1;
}

/*
 * Autoconf attach routine.  Called by config_attach_pseudo(9) when we
 * open the line discipline.
 */
/* ARGSUSED */
static void
bcsp_attach(struct device *parent __unused, struct device *self,
	    void *aux __unused)
{
	struct bcsp_softc *sc = device_private(self);
	const struct sysctlnode *node;
	int rc, bcsp_node_num;

	aprint_normal("\n");
	aprint_naive("\n");

	callout_init(&sc->sc_seq_timer, 0);
	callout_setfunc(&sc->sc_seq_timer, bcsp_timer_timeout, sc);
	callout_init(&sc->sc_le_timer, 0);
	callout_setfunc(&sc->sc_le_timer, bcsp_le_timeout, sc);
	sc->sc_seq_timeout = BCSP_SEQ_TX_TIMEOUT;
	sc->sc_seq_winsize = BCSP_SEQ_TX_WINSIZE;
	sc->sc_seq_retry_limit = BCSP_SEQ_TX_RETRY_LIMIT;
	MBUFQ_INIT(&sc->sc_seqq);
	MBUFQ_INIT(&sc->sc_seq_retryq);
	MBUFQ_INIT(&sc->sc_dgq);

	/* Attach Bluetooth unit */
	sc->sc_unit.hci_softc = sc;
	sc->sc_unit.hci_devname = sc->sc_dev.dv_xname;
	sc->sc_unit.hci_enable = bcsp_enable;
	sc->sc_unit.hci_disable = bcsp_disable;
	sc->sc_unit.hci_start_cmd = bcsp_start;
	sc->sc_unit.hci_start_acl = bcsp_start;
	sc->sc_unit.hci_start_sco = bcsp_start;
	sc->sc_unit.hci_ipl = makeiplcookie(IPL_TTY);
	hci_attach(&sc->sc_unit);

	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, NULL,
	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
	    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
		goto err;
	}
	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
	    0, CTLTYPE_NODE, sc->sc_dev.dv_xname,
	    SYSCTL_DESCR("bcsp controls"),
	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
		goto err;
	}
	bcsp_node_num = node->sysctl_num;
	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
	    CTLFLAG_READWRITE, CTLTYPE_INT,
	    "muzzled", SYSCTL_DESCR("muzzled for Link-establishment Layer"),
	    NULL, 0, &sc->sc_le_muzzled,
	    0, CTL_HW, bcsp_node_num, CTL_CREATE, CTL_EOL)) != 0) {
		goto err;
	}
	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
	    CTLFLAG_READWRITE, CTLTYPE_INT,
	    "txcrc", SYSCTL_DESCR("txcrc for Packet Integrity Layer"),
	    NULL, 0, &sc->sc_pi_txcrc,
	    0, CTL_HW, bcsp_node_num, CTL_CREATE, CTL_EOL)) != 0) {
		goto err;
	}
	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
	    CTLFLAG_READWRITE, CTLTYPE_INT,
	    "timeout", SYSCTL_DESCR("timeout for Sequencing Layer"),
	    NULL, 0, &sc->sc_seq_timeout,
	    0, CTL_HW, bcsp_node_num, CTL_CREATE, CTL_EOL)) != 0) {
		goto err;
	}
	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
	    CTLFLAG_READWRITE, CTLTYPE_INT,
	    "winsize", SYSCTL_DESCR("winsize for Sequencing Layer"),
	    NULL, 0, &sc->sc_seq_winsize,
	    0, CTL_HW, bcsp_node_num, CTL_CREATE, CTL_EOL)) != 0) {
		goto err;
	}
	if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
	    CTLFLAG_READWRITE, CTLTYPE_INT,
	    "retry_limit", SYSCTL_DESCR("retry limit for Sequencing Layer"),
	    NULL, 0, &sc->sc_seq_retry_limit,
	    0, CTL_HW, bcsp_node_num, CTL_CREATE, CTL_EOL)) != 0) {
		goto err;
	}
	return;

err:
	printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
}

/*
 * Autoconf detach routine.  Called when we close the line discipline.
 */
/* ARGSUSED */
static int
bcsp_detach(struct device *self, int flags __unused)
{
	struct bcsp_softc *sc = device_private(self);

	hci_detach(&sc->sc_unit);

	return 0;
}


/*
 * Line discipline functions.
 */
/* ARGSUSED */
static int
bcspopen(dev_t device __unused, struct tty *tp)
{
	struct bcsp_softc *sc;
	struct cfdata *cfdata;
	struct lwp *l = curlwp;		/* XXX */
	int error, unit, s;
	static char name[] = "bcsp";

	if ((error = kauth_authorize_device_tty(l->l_cred,
	    KAUTH_GENERIC_ISSUSER, tp)) != 0)
		return error;

	s = spltty();

	if (tp->t_linesw == &bcsp_disc) {
		sc = (struct bcsp_softc *)tp->t_sc;
		if (sc != NULL) {
			splx(s);
			return EBUSY;
		}
	}

	KASSERT(tp->t_oproc != NULL);

	cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
	for (unit = 0; unit < bcsp_cd.cd_ndevs; unit++)
		if (bcsp_cd.cd_devs[unit] == NULL)
			break;
	cfdata->cf_name = name;
	cfdata->cf_atname = name;
	cfdata->cf_unit = unit;
	cfdata->cf_fstate = FSTATE_STAR;

	printf("%s%d at tty major %d minor %d",
	    name, unit, major(tp->t_dev), minor(tp->t_dev));
	sc = (struct bcsp_softc *)config_attach_pseudo(cfdata);
	if (sc == NULL) {
		splx(s);
		return EIO;
	}
	tp->t_sc = sc;
	sc->sc_tp = tp;

	ttyflush(tp, FREAD | FWRITE);

	splx(s);

	sc->sc_slip_txrsv = BCSP_SLIP_PKTSTART;
	bcsp_sequencing_reset(sc);

	/* start link-establishment */
	bcsp_start_le(&sc->sc_unit);

	return 0;
}

/* ARGSUSED */
static int
bcspclose(struct tty *tp, int flag __unused)
{
	struct bcsp_softc *sc;
	struct cfdata *cfdata;
	int s;

	sc = tp->t_sc;

	/* terminate link-establishment */
	bcsp_terminate_le(&sc->sc_unit);

	s = spltty();

	MBUFQ_DRAIN(&sc->sc_dgq);
	bcsp_sequencing_reset(sc);

	ttyflush(tp, FREAD | FWRITE);
	ttyldisc_release(tp->t_linesw);
	tp->t_linesw = ttyldisc_default();
	if (sc != NULL) {
		tp->t_sc = NULL;
		if (sc->sc_tp == tp) {
			cfdata = sc->sc_dev.dv_cfdata;
			config_detach(&sc->sc_dev, 0);
			free(cfdata, M_DEVBUF);
		}

	}
	splx(s);
	return 0;
}

/* ARGSUSED */
static int
bcspioctl(struct tty *tp, u_long cmd, void *data, int flag __unused,
	  struct lwp *l __unused)
{
	struct bcsp_softc *sc = (struct bcsp_softc *)tp->t_sc;
	int error;

	if (sc == NULL || tp != sc->sc_tp)
		return EPASSTHROUGH;

	error = 0;
	switch (cmd) {
	default:
		error = EPASSTHROUGH;
		break;
	}

	return error;
}


/*
 * UART Driver Layer is supported by com-driver.
 */

/*
 * BCSP SLIP Layer functions:
 *   Supports to transmit/receive a byte stream.
 *   SLIP protocol described in Internet standard RFC 1055.
 */
static int
bcsp_slip_transmit(struct tty *tp)
{
	struct bcsp_softc *sc = (struct bcsp_softc *)tp->t_sc;
	struct mbuf *m;
	int count, rlen;
	uint8_t *rptr;

	m = sc->sc_txp;
	if (m == NULL) {
		sc->sc_unit.hci_flags &= ~BTF_XMIT;
		bcsp_mux_transmit(sc);
		return 0;
	}

	count = 0;
	rlen = 0;
	rptr = mtod(m, uint8_t *);

	if (sc->sc_slip_txrsv != 0) {
#ifdef BCSP_DEBUG
		if (sc->sc_slip_txrsv == BCSP_SLIP_PKTSTART)
			DPRINTFN(4, ("%s: slip transmit start\n",
			    sc->sc_dev.dv_xname));
		else
			DPRINTFN(4, ("0x%02x ", sc->sc_slip_txrsv));
#endif

		if (putc(sc->sc_slip_txrsv, &tp->t_outq) < 0)
			return 0;
		count++;

		if (sc->sc_slip_txrsv == BCSP_SLIP_ESCAPE_PKTEND ||
		    sc->sc_slip_txrsv == BCSP_SLIP_ESCAPE_ESCAPE) {
			rlen++;
			rptr++;
		}
		sc->sc_slip_txrsv = 0;
	}

	for(;;) {
		if (rlen >= m->m_len) {
			m = m->m_next;
			if (m == NULL) {
				if (putc(BCSP_SLIP_PKTEND, &tp->t_outq) < 0)
					break;

				DPRINTFN(4, ("\n%s: slip transmit end\n",
				    sc->sc_dev.dv_xname));

				m = sc->sc_txp;
				sc->sc_txp = NULL;
				sc->sc_slip_txrsv = BCSP_SLIP_PKTSTART;

				sc->sc_transmit_callback(sc, m);
				m = NULL;
				break;
			}

			rlen = 0;
			rptr = mtod(m, uint8_t *);
			continue;
		}

		if (*rptr == BCSP_SLIP_PKTEND) {
			if (putc(BCSP_SLIP_ESCAPE, &tp->t_outq) < 0)
				break;
			count++;
			DPRINTFN(4, (" esc "));

			if (putc(BCSP_SLIP_ESCAPE_PKTEND, &tp->t_outq) < 0) {
				sc->sc_slip_txrsv = BCSP_SLIP_ESCAPE_PKTEND;
				break;
			}
			DPRINTFN(4, ("0x%02x ", BCSP_SLIP_ESCAPE_PKTEND));
		} else if (*rptr == BCSP_SLIP_ESCAPE) {
			if (putc(BCSP_SLIP_ESCAPE, &tp->t_outq) < 0)
				break;
			count++;
			DPRINTFN(4, (" esc "));

			if (putc(BCSP_SLIP_ESCAPE_ESCAPE, &tp->t_outq) < 0) {
				sc->sc_slip_txrsv = BCSP_SLIP_ESCAPE_ESCAPE;
				break;
			}
			DPRINTFN(4, ("0x%02x ", BCSP_SLIP_ESCAPE_ESCAPE));
		} else {
			if (putc(*rptr++, &tp->t_outq) < 0)
				break;
			DPRINTFN(4, ("0x%02x ", *(rptr - 1)));
		}
		rlen++;
		count++;
	}
	if (m != NULL)
		m_adj(m, rlen);

	sc->sc_unit.hci_stats.byte_tx += count;

	if (tp->t_outq.c_cc != 0)
		(*tp->t_oproc)(tp);

	return 0;
}

static int
bcsp_slip_receive(int c, struct tty *tp)
{
	struct bcsp_softc *sc = (struct bcsp_softc *)tp->t_sc;
	struct mbuf *m = sc->sc_rxp;
	int discard = 0;
	const char *errstr;

	c &= TTY_CHARMASK;

	/* If we already started a packet, find the trailing end of it. */
	if (m) {
		while (m->m_next)
			m = m->m_next;

		if (M_TRAILINGSPACE(m) == 0) {
			/* extend mbuf */
			MGET(m->m_next, M_DONTWAIT, MT_DATA);
			if (m->m_next == NULL) {
				printf("%s: out of memory\n",
				    sc->sc_dev.dv_xname);
				++sc->sc_unit.hci_stats.err_rx;
				return 0;	/* (lost sync) */
			}

			m = m->m_next;
			m->m_len = 0;
		}
	} else
		if (c != BCSP_SLIP_PKTSTART) {
			discard = 1;
			errstr = "not sync";
			goto discarded;
		}

	switch (c) {
	case BCSP_SLIP_PKTSTART /* or _PKTEND */:
		if (m == NULL) {
			/* BCSP_SLIP_PKTSTART */

			DPRINTFN(4, ("%s: slip receive start\n",
			    sc->sc_dev.dv_xname));

			/* new packet */
			MGETHDR(m, M_DONTWAIT, MT_DATA);
			if (m == NULL) {
				printf("%s: out of memory\n",
				    sc->sc_dev.dv_xname);
				++sc->sc_unit.hci_stats.err_rx;
				return 0;	/* (lost sync) */
			}

			sc->sc_rxp = m;
			m->m_pkthdr.len = m->m_len = 0;
			sc->sc_slip_rxexp = 0;
		} else {
			/* BCSP_SLIP_PKTEND */

			if (m == sc->sc_rxp && m->m_len == 0) {
				DPRINTFN(4, ("%s: resynchronises\n",
				    sc->sc_dev.dv_xname));

				sc->sc_unit.hci_stats.byte_rx++;
				return 0;
			}

			DPRINTFN(4, ("%s%s: slip receive end\n",
			    (m->m_len % 16 != 0) ? "\n" :  "",
			    sc->sc_dev.dv_xname));

			bcsp_pktintegrity_receive(sc, sc->sc_rxp);
			sc->sc_rxp = NULL;
			sc->sc_slip_rxexp = BCSP_SLIP_PKTSTART;
		}
		sc->sc_unit.hci_stats.byte_rx++;
		return 0;

	case BCSP_SLIP_ESCAPE:

		DPRINTFN(4, ("  esc"));

		if (sc->sc_slip_rxexp == BCSP_SLIP_ESCAPE) {
			discard = 1;
			errstr = "waiting 0xdc or 0xdb"; 
		} else
			sc->sc_slip_rxexp = BCSP_SLIP_ESCAPE;
		break;

	default:
		DPRINTFN(4, (" 0x%02x%s",
		    c, (m->m_len % 16 == 15) ? "\n" :  ""));

		switch (sc->sc_slip_rxexp) {
		case BCSP_SLIP_PKTSTART:
			discard = 1;
			errstr = "waiting 0xc0";
			break;

		case BCSP_SLIP_ESCAPE:
			if (c == BCSP_SLIP_ESCAPE_PKTEND)
				mtod(m, uint8_t *)[m->m_len++] =
				    BCSP_SLIP_PKTEND;
			else if (c == BCSP_SLIP_ESCAPE_ESCAPE)
				mtod(m, uint8_t *)[m->m_len++] =
				    BCSP_SLIP_ESCAPE;
			else {
				discard = 1;
				errstr = "unknown escape";
			}
			sc->sc_slip_rxexp = 0;
			break;

		default:
			mtod(m, uint8_t *)[m->m_len++] = c;
		}
	}
	if (discard) {
discarded:
		DPRINTFN(4, ("%s: receives unexpected byte 0x%02x: %s\n",
		    sc->sc_dev.dv_xname, c, errstr));
	} else
		sc->sc_rxp->m_pkthdr.len++;
	sc->sc_unit.hci_stats.byte_rx++;

	return 0;
}


/*
 * BCSP Packet Integrity Layer functions:
 *   handling Payload Length, Checksum, CRC.
 */
static void
bcsp_pktintegrity_transmit(struct bcsp_softc *sc)
{
	struct mbuf *_m, *m = sc->sc_txp;
	bcsp_hdr_t *hdrp = mtod(m, bcsp_hdr_t *);
	int pktlen, pldlen;

	DPRINTFN(3, ("%s: pi transmit\n", sc->sc_dev.dv_xname));

	for (pktlen = 0, _m = m; _m != NULL; _m = _m->m_next)
		pktlen += _m->m_len;
	pldlen = pktlen - sizeof(bcsp_hdr_t);

	if (sc->sc_pi_txcrc)
		hdrp->flags |= BCSP_FLAGS_CRC_PRESENT;

	BCSP_SET_PLEN(hdrp, pldlen);
	BCSP_SET_CSUM(hdrp);

	if (sc->sc_pi_txcrc) {
		int n = 0;
		uint16_t crc = 0xffff;
		uint8_t *buf;

		for (_m = m; _m != NULL; _m = _m->m_next) {
			buf = mtod(_m, uint8_t *);
			for (n = 0; n < _m->m_len; n++)
				bcsp_crc_update(&crc, *(buf + n));
		}
		crc = htobe16(bcsp_crc_reverse(crc));
		m_copyback(m, pktlen, sizeof(crc), &crc);
	}

#ifdef BCSP_DEBUG
	if (bcsp_debug == 4)
		bcsp_packet_print(m);
#endif

	bcsp_slip_transmit(sc->sc_tp);
}

static void
bcsp_pktintegrity_receive(struct bcsp_softc *sc, struct mbuf *m)
{
	bcsp_hdr_t *hdrp;
	struct mbuf *_m;
	u_int pktlen, pldlen;
	int discard = 0;
	uint16_t crc = 0xffff;
	const char *errstr;

	DPRINTFN(3, ("%s: pi receive\n", sc->sc_dev.dv_xname));
#ifdef BCSP_DEBUG
	if (bcsp_debug == 4)
		bcsp_packet_print(m);
#endif

	KASSERT(m->m_len >= sizeof(bcsp_hdr_t));

	hdrp = mtod(m, bcsp_hdr_t *);
	for (pktlen = 0, _m = m; _m != NULL; _m = _m->m_next)
		pktlen += _m->m_len;
	pldlen = pktlen - sizeof(bcsp_hdr_t) -
	    ((hdrp->flags & BCSP_FLAGS_CRC_PRESENT) ? sizeof(crc) : 0);
	if (pldlen > 0xfff) {
		discard = 1;
		errstr = "Payload Length";
		goto discarded;
	}
	if (hdrp->csum != BCSP_GET_CSUM(hdrp)) {
		discard = 1;
		errstr = "Checksum";
		goto discarded;
	}
	if (BCSP_GET_PLEN(hdrp) != pldlen) {
		discard = 1;
		errstr = "Payload Length";
		goto discarded;
	}
	if (hdrp->flags & BCSP_FLAGS_CRC_PRESENT) {
		int i, n;
		uint16_t crc0;
		uint8_t *buf;

		i = 0;
		n = 0;
		for (_m = m; _m != NULL; _m = _m->m_next) {
			buf = mtod(m, uint8_t *);
			for (n = 0;
			    n < _m->m_len && i < sizeof(bcsp_hdr_t) + pldlen;
			    n++, i++)
				bcsp_crc_update(&crc, *(buf + n));
		}

		m_copydata(_m, n, sizeof(crc0), &crc0);
		if (be16toh(crc0) != bcsp_crc_reverse(crc)) {
			discard = 1;
			errstr = "CRC";
		} else
			/* Shaves CRC */
			m_adj(m, - sizeof(crc));
	}

	if (discard) {
discarded:
		DPRINTFN(3, ("%s: receives unexpected packet: %s\n",
		    sc->sc_dev.dv_xname, errstr));
		m_freem(m);
	} else
		bcsp_mux_receive(sc, m);
}

static const uint16_t crctbl[] = {
	0x0000, 0x1081, 0x2102, 0x3183,
	0x4204, 0x5285, 0x6306, 0x7387,
	0x8408, 0x9489, 0xa50a, 0xb58b,
	0xc60c, 0xd68d, 0xe70e, 0xf78f,
};

static void
bcsp_crc_update(uint16_t *crc, uint8_t d)
{
	uint16_t reg = *crc;

	reg = (reg >> 4) ^ crctbl[(reg ^ d) & 0x000f];
	reg = (reg >> 4) ^ crctbl[(reg ^ (d >> 4)) & 0x000f];

	*crc = reg;
}

static uint16_t
bcsp_crc_reverse(uint16_t crc)
{
	uint16_t b, rev;

	for (b = 0, rev = 0; b < 16; b++) {
		rev = rev << 1;
		rev |= (crc & 1);
		crc = crc >> 1;
	}

	return rev;
}


/*
 * BCSP MUX Layer functions
 */
static void
bcsp_mux_transmit(struct bcsp_softc *sc)
{
	struct hci_unit *unit = &sc->sc_unit;
	struct mbuf *m;
	bcsp_hdr_t *hdrp;

	DPRINTFN(2, ("%s: mux transmit: hci_flags=0x%x, choke=%d",
	    sc->sc_dev.dv_xname, unit->hci_flags, sc->sc_mux_choke));

	if (unit->hci_flags & BTF_XMIT)
		return;

	if (sc->sc_mux_choke) {
		struct mbuf *_m;

		/* In this case, send only Link Establishment packet */
		for (m = MBUFQ_FIRST(&sc->sc_dgq); m != NULL;
		    _m = m, m = MBUFQ_NEXT(m)) {
			hdrp = mtod(m, bcsp_hdr_t *);
			if (hdrp->ident == BCSP_CHANNEL_LE) {
				if (m == MBUFQ_FIRST(&sc->sc_dgq))
					MBUFQ_DEQUEUE(&sc->sc_dgq, m);
				else {
					if (m->m_nextpkt == NULL)
						sc->sc_dgq.mq_last =
						    &_m->m_nextpkt;
					_m->m_nextpkt = m->m_nextpkt;
					m->m_nextpkt = NULL;
				}
				goto transmit;
			}
		}
		DPRINTFN(2, ("\n"));
		return;
	}

	/*
	 * The MUX Layer always gives priority to packets from the Datagram
	 * Queue Layer over the Sequencing Layer.
	 */
	if (MBUFQ_FIRST(&sc->sc_dgq)) {
		MBUFQ_DEQUEUE(&sc->sc_dgq, m);
		goto transmit;
	}
	if (MBUFQ_FIRST(&sc->sc_seqq)) {
		MBUFQ_DEQUEUE(&sc->sc_seqq, m);
		hdrp = mtod(m, bcsp_hdr_t *);
		hdrp->flags |= BCSP_FLAGS_PROTOCOL_REL;		/* Reliable */
		goto transmit;
	}
	if (sc->sc_mux_send_ack == true) {
		m = bcsp_create_ackpkt();
		if (m != NULL)
			goto transmit;
		printf("%s: out of memory\n", sc->sc_dev.dv_xname);
		++sc->sc_unit.hci_stats.err_tx;
	}

	/* Nothing to send */
	DPRINTFN(2, ("\n"));
	return;

transmit:
	DPRINTFN(2, (", txack=%d, send_ack=%d\n",
	    bcsp_get_txack(sc), sc->sc_mux_send_ack));

	hdrp = mtod(m, bcsp_hdr_t *);
	hdrp->flags |=
	    (bcsp_get_txack(sc) << BCSP_FLAGS_ACK_SHIFT) & BCSP_FLAGS_ACK_MASK;
	if (sc->sc_mux_send_ack == true)
		sc->sc_mux_send_ack = false;

#ifdef BCSP_DEBUG
	if (bcsp_debug == 3)
		bcsp_packet_print(m);
#endif

	sc->sc_txp = m;
	unit->hci_flags |= BTF_XMIT;
	bcsp_pktintegrity_transmit(sc);
}

static void
bcsp_mux_receive(struct bcsp_softc *sc, struct mbuf *m)
{
	bcsp_hdr_t *hdrp = mtod(m, bcsp_hdr_t *);
	const u_int rxack = BCSP_FLAGS_ACK(hdrp->flags);

	DPRINTFN(2, ("%s: mux receive: flags=0x%x, ident=%d, rxack=%d\n",
	    sc->sc_dev.dv_xname, hdrp->flags, hdrp->ident, rxack));
#ifdef BCSP_DEBUG
	if (bcsp_debug == 3)
		bcsp_packet_print(m);
#endif

	bcsp_signal_rxack(sc, rxack);

	microtime(&sc->sc_mux_lastrx);

	/* if the Ack Packet received then discard */
	if (BCSP_FLAGS_SEQ(hdrp->flags) == 0 &&
	    hdrp->ident == BCSP_IDENT_ACKPKT &&
	    BCSP_GET_PLEN(hdrp) == 0) {
		m_freem(m);
		return;
	}

	if (hdrp->flags & BCSP_FLAGS_PROTOCOL_REL)
		bcsp_sequencing_receive(sc, m);
	else
		bcsp_datagramq_receive(sc, m);
}

static __inline void
bcsp_send_ack_command(struct bcsp_softc *sc)
{

	DPRINTFN(2, ("%s: mux send_ack_command\n", sc->sc_dev.dv_xname));

	sc->sc_mux_send_ack = true;
}

static __inline struct mbuf *
bcsp_create_ackpkt()
{
	struct mbuf *m;
	bcsp_hdr_t *hdrp;

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m != NULL) {
		m->m_pkthdr.len = m->m_len = sizeof(bcsp_hdr_t);
		hdrp = mtod(m, bcsp_hdr_t *);
		/*
		 * An Ack Packet has the following fields:
		 *	Ack Field:			txack (not set yet)
		 *	Seq Field:			0
		 *	Protocol Identifier Field:	0
		 *	Protocol Type Field:		Any value
		 *	Payload Length Field:		0
		 */
		memset(hdrp, 0, sizeof(bcsp_hdr_t));
	}
	return m;
}

static __inline void
bcsp_set_choke(struct bcsp_softc *sc, bool choke)
{

	DPRINTFN(2, ("%s: mux set choke=%d\n", sc->sc_dev.dv_xname, choke));

	sc->sc_mux_choke = choke;
}


/*
 * BCSP Sequencing Layer functions
 */
static void
bcsp_sequencing_receive(struct bcsp_softc *sc, struct mbuf *m)
{
	bcsp_hdr_t hdr;
	uint32_t rxseq;

	m_copydata(m, 0, sizeof(bcsp_hdr_t), &hdr);
	rxseq = BCSP_FLAGS_SEQ(hdr.flags);
	/*
	 * We remove the header of BCSP and add the 'uint8_t type' of
	 * hci_*_hdr_t to the head. 
	 */
	m_adj(m, sizeof(bcsp_hdr_t) - sizeof(uint8_t));

	DPRINTFN(1, ("%s: seq receive: rxseq=%d, expected %d\n",
	    sc->sc_dev.dv_xname, rxseq, sc->sc_seq_expected_rxseq));
#ifdef BCSP_DEBUG
	if (bcsp_debug == 2)
		bcsp_packet_print(m);
#endif

	if (rxseq != sc->sc_seq_expected_rxseq) {
		m_freem(m);

		/* send ack packet, if needly */
		bcsp_mux_transmit(sc);

		return;
	}

	switch (hdr.ident) {
	case BCSP_CHANNEL_HCI_CMDEVT:
		*(mtod(m, uint8_t *)) = HCI_EVENT_PKT;
		hci_input_event(&sc->sc_unit, m);
		sc->sc_unit.hci_stats.evt_rx++;
		break;

	case BCSP_CHANNEL_HCI_ACL:
		*(mtod(m, uint8_t *)) = HCI_ACL_DATA_PKT;
		hci_input_acl(&sc->sc_unit, m);
		sc->sc_unit.hci_stats.acl_rx++;
		break;

	case BCSP_CHANNEL_HCI_SCO:
		*(mtod(m, uint8_t *)) = HCI_SCO_DATA_PKT;
		hci_input_sco(&sc->sc_unit, m);
		sc->sc_unit.hci_stats.sco_rx++;
		break;

	case BCSP_CHANNEL_HQ:
	case BCSP_CHANNEL_DEVMGT:
	case BCSP_CHANNEL_L2CAP:
	case BCSP_CHANNEL_RFCOMM:
	case BCSP_CHANNEL_SDP:
	case BCSP_CHANNEL_DFU:
	case BCSP_CHANNEL_VM:
	default:
		printf("%s:"
		    " received reliable packet with not support channel %d\n",
		    sc->sc_dev.dv_xname, hdr.ident);
		m_freem(m);
		break;
	}

	sc->sc_seq_expected_rxseq =
	    (sc->sc_seq_expected_rxseq + 1) & BCSP_FLAGS_SEQ_MASK;
	sc->sc_seq_txack = sc->sc_seq_expected_rxseq;
	bcsp_send_ack_command(sc);
}

static bool
bcsp_tx_reliable_pkt(struct bcsp_softc *sc, struct mbuf *m, u_int protocol_id)
{
	bcsp_hdr_t *hdrp;
	struct mbuf *_m;
	u_int pldlen;
	int s;

	DPRINTFN(1, ("%s: seq transmit:"
	    "protocol_id=%d, winspace=%d, txseq=%d\n", sc->sc_dev.dv_xname,
	    protocol_id, sc->sc_seq_winspace, sc->sc_seq_txseq));

	for (pldlen = 0, _m = m; _m != NULL; _m = _m->m_next) {
		if (_m->m_len < 0)
			return false;
		pldlen += _m->m_len;
	}
	if (pldlen > 0xfff)
		return false;
	if (protocol_id == BCSP_IDENT_ACKPKT || protocol_id > 15)
		return false;

	if (sc->sc_seq_winspace == 0)
		return false;

	M_PREPEND(m, sizeof(bcsp_hdr_t), M_DONTWAIT);
	if (m == NULL) {
		printf("%s: out of memory\n", sc->sc_dev.dv_xname);
		return false;
	}
	KASSERT(m->m_len >= sizeof(bcsp_hdr_t));

	hdrp = mtod(m, bcsp_hdr_t *);
	memset(hdrp, 0, sizeof(bcsp_hdr_t));
	hdrp->flags |= sc->sc_seq_txseq;
	hdrp->ident = protocol_id;

	callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);

	s = splserial();
	MBUFQ_ENQUEUE(&sc->sc_seqq, m);
	splx(s);
	sc->sc_transmit_callback = bcsp_reliabletx_callback;

#ifdef BCSP_DEBUG
	if (bcsp_debug == 2)
		bcsp_packet_print(m);
#endif

	sc->sc_seq_txseq = (sc->sc_seq_txseq + 1) & BCSP_FLAGS_SEQ_MASK;
	sc->sc_seq_winspace--;
	_m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
	if (_m == NULL) {
		printf("%s: out of memory\n", sc->sc_dev.dv_xname);
		return false;
	}
	MBUFQ_ENQUEUE(&sc->sc_seq_retryq, _m);
	bcsp_mux_transmit(sc);

	return true;
}

#if 0
static bool
bcsp_rx_reliable_pkt(struct bcsp_softc *sc, struct mbuf *m, u_int protocol_id)
{

	return false;
}

/* XXXX:  I can't understand meaning this function... */
static __inline void
bcsp_link_failed(struct bcsp_softc *sc)
{

	return (sc->sc_seq_retries >= sc->sc_seq_retry_limit);
}
#endif

static __inline u_int
bcsp_get_txack(struct bcsp_softc *sc)
{

	return sc->sc_seq_txack;
}

static void
bcsp_signal_rxack(struct bcsp_softc *sc, uint32_t rxack)
{
	bcsp_hdr_t *hdrp;
	struct mbuf *m;
	uint32_t seqno = (rxack - 1) & BCSP_FLAGS_SEQ_MASK;
	int s;

	DPRINTFN(1, ("%s: seq signal rxack: rxack=%d\n",
	    sc->sc_dev.dv_xname, rxack));

	s = splserial();
	m = MBUFQ_FIRST(&sc->sc_seq_retryq);
	while (m != NULL) {
		hdrp = mtod(m, bcsp_hdr_t *);
		if (BCSP_FLAGS_SEQ(hdrp->flags) == seqno) {
			struct mbuf *m0;

			for (m0 = MBUFQ_FIRST(&sc->sc_seq_retryq);
			    m0 != MBUFQ_NEXT(m);
			    m0 = MBUFQ_FIRST(&sc->sc_seq_retryq)) {
				MBUFQ_DEQUEUE(&sc->sc_seq_retryq, m0);
				m_freem(m0);
				sc->sc_seq_winspace++;
			}
			break;
		}
		m = MBUFQ_NEXT(m);
	}
	splx(s);
	sc->sc_seq_retries = 0;

	if (sc->sc_seq_winspace == sc->sc_seq_winsize)
		callout_stop(&sc->sc_seq_timer);
	else
		callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
}

static void
bcsp_reliabletx_callback(struct bcsp_softc *sc, struct mbuf *m)
{

	m_freem(m);
}

static void
bcsp_timer_timeout(void *arg)
{
	struct bcsp_softc *sc = arg;
	struct mbuf *m, *_m;
	int s, i = 0;

	DPRINTFN(1, ("%s: seq timeout: retries=%d\n",
	    sc->sc_dev.dv_xname, sc->sc_seq_retries));

	s = splserial();
	for (m = MBUFQ_FIRST(&sc->sc_seq_retryq); m != NULL;
	    m = MBUFQ_NEXT(m)) {
		_m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
		if (_m == NULL) {
			printf("%s: out of memory\n", sc->sc_dev.dv_xname);
			return;
		}
		MBUFQ_ENQUEUE(&sc->sc_seqq, _m);
		i++;
	}
	splx(s);

	if (i != 0) {
		if (++sc->sc_seq_retries < sc->sc_seq_retry_limit)
			callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
		else {
			printf("%s: reached the retry limit."
			    "  restart the link-establishment\n",
			    sc->sc_dev.dv_xname);
			bcsp_start_le(&sc->sc_unit);
			return;
		}
	}
	bcsp_mux_transmit(sc);
}

static void
bcsp_sequencing_reset(struct bcsp_softc *sc)
{
	int s;

	s = splserial();
	MBUFQ_DRAIN(&sc->sc_seqq);
	MBUFQ_DRAIN(&sc->sc_seq_retryq);
	splx(s);


	sc->sc_seq_txseq = 0;
	sc->sc_seq_txack = 0;
	sc->sc_seq_winspace = sc->sc_seq_winsize;
	sc->sc_seq_retries = 0;
	callout_stop(&sc->sc_seq_timer);

	sc->sc_mux_send_ack = false;

	/* XXXX: expected_rxseq should be set by MUX Layer */
	sc->sc_seq_expected_rxseq = 0;
}


/*
 * BCSP Datagram Queue Layer functions
 */
static void
bcsp_datagramq_receive(struct bcsp_softc *sc, struct mbuf *m)
{
	bcsp_hdr_t hdr;

	DPRINTFN(1, ("%s: dgq receive\n", sc->sc_dev.dv_xname));
#ifdef BCSP_DEBUG
	if (bcsp_debug == 2)
		bcsp_packet_print(m);
#endif

	m_copydata(m, 0, sizeof(bcsp_hdr_t), &hdr);

	switch (hdr.ident) {
	case BCSP_CHANNEL_LE:
		m_adj(m, sizeof(bcsp_hdr_t));
		bcsp_input_le(&sc->sc_unit, m);
		break;

	case BCSP_CHANNEL_HCI_SCO:
		/*
		 * We remove the header of BCSP and add the 'uint8_t type' of
		 * hci_scodata_hdr_t to the head. 
		 */
		m_adj(m, sizeof(bcsp_hdr_t) - sizeof(uint8_t));
		*(mtod(m, uint8_t *)) = HCI_SCO_DATA_PKT;
		hci_input_sco(&sc->sc_unit, m);
		sc->sc_unit.hci_stats.sco_rx++;
		break;

	default:
		printf("%s:"
		    " received unreliable packet with not support channel %d\n",
		    sc->sc_dev.dv_xname, hdr.ident);
		m_freem(m);
		break;
	}
}

static bool
bcsp_tx_unreliable_pkt(struct bcsp_softc *sc, struct mbuf *m, u_int protocol_id)
{
	bcsp_hdr_t *hdrp;
	struct mbuf *_m;
	u_int pldlen;
	int s;

	DPRINTFN(1, ("%s: dgq transmit: protocol_id=%d,",
	    sc->sc_dev.dv_xname, protocol_id));

	for (pldlen = 0, _m = m; _m != NULL; _m = m->m_next) {
		if (_m->m_len < 0)
			return false;
		pldlen += _m->m_len;
	}
	DPRINTFN(1, (" pldlen=%d\n", pldlen));
	if (pldlen > 0xfff)
		return false;
	if (protocol_id == BCSP_IDENT_ACKPKT || protocol_id > 15)
		return false;

	M_PREPEND(m, sizeof(bcsp_hdr_t), M_DONTWAIT);
	if (m == NULL) {
		printf("%s: out of memory\n", sc->sc_dev.dv_xname);
		return false;
	}
	KASSERT(m->m_len >= sizeof(bcsp_hdr_t));

	hdrp = mtod(m, bcsp_hdr_t *);
	memset(hdrp, 0, sizeof(bcsp_hdr_t));
	hdrp->ident = protocol_id;

	s = splserial();
	MBUFQ_ENQUEUE(&sc->sc_dgq, m);
	splx(s);
	sc->sc_transmit_callback = bcsp_unreliabletx_callback;

#ifdef BCSP_DEBUG
	if (bcsp_debug == 2)
		bcsp_packet_print(m);
#endif

	bcsp_mux_transmit(sc);

	return true;
}

#if 0
static bool
bcsp_rx_unreliable_pkt(struct bcsp_softc *sc, struct mbuf *m, u_int protocol_id)
{

	return false;
}
#endif

static void
bcsp_unreliabletx_callback(struct bcsp_softc *sc, struct mbuf *m)
{

	if (M_GETCTX(m, void *) == NULL)
		m_freem(m);
	else
		hci_complete_sco(&sc->sc_unit, m);
}


/*
 * BlueCore Link Establishment Protocol functions
 */
static const uint8_t sync[] = BCSP_LE_SYNC;
static const uint8_t syncresp[] = BCSP_LE_SYNCRESP;
static const uint8_t conf[] = BCSP_LE_CONF;
static const uint8_t confresp[] = BCSP_LE_CONFRESP;

static int
bcsp_start_le(struct hci_unit *unit)
{
	struct bcsp_softc *sc = unit->hci_softc;

	DPRINTF(("%s: start link-establish\n", sc->sc_dev.dv_xname));

	bcsp_set_choke(sc, true);

	if (!sc->sc_le_muzzled) {
		struct mbuf *m;

		m = m_gethdr(M_WAIT, MT_DATA);
		m->m_pkthdr.len = m->m_len = 0;
		m_copyback(m, 0, sizeof(sync), sync);
		if (!bcsp_tx_unreliable_pkt(sc, m, BCSP_CHANNEL_LE)) {
			printf("%s: le-packet transmit failed\n",
			    sc->sc_dev.dv_xname);
			return EINVAL;
		}
	}
	callout_schedule(&sc->sc_le_timer, BCSP_LE_TSHY_TIMEOUT);

	sc->sc_le_state = le_state_shy;
	return 0;
}

static void
bcsp_terminate_le(struct hci_unit *unit)
{
	struct bcsp_softc *sc = unit->hci_softc;
	struct mbuf *m;

	/* terminate link-establishment */
	callout_stop(&sc->sc_le_timer);
	bcsp_set_choke(sc, true);
	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL)
		printf("%s: out of memory\n", sc->sc_dev.dv_xname);
	else {
		/* length of le packets is 4 */
		m->m_pkthdr.len = m->m_len = 0;
		m_copyback(m, 0, sizeof(sync), sync);
		if (!bcsp_tx_unreliable_pkt(sc, m, BCSP_CHANNEL_LE))
			printf("%s: link-establishment terminations failed\n",
			    sc->sc_dev.dv_xname);
	}
}

static void
bcsp_input_le(struct hci_unit *unit, struct mbuf *m)
{
	struct bcsp_softc *sc = unit->hci_softc;
	uint32_t *rcvpkt;
	int i;
	const uint8_t *rplypkt;
	static struct {
		const char *type;
		const uint8_t *datap;
	} pkt[] = {
		{ "sync",	sync },
		{ "sync-resp",	syncresp },
		{ "conf",	conf },
		{ "conf-resp",	confresp },

		{ NULL }
	};

	DPRINTFN(0, ("%s: le input: state %d, muzzled %d\n",
	    sc->sc_dev.dv_xname, sc->sc_le_state, sc->sc_le_muzzled));
#ifdef BCSP_DEBUG
	if (bcsp_debug == 1)
		bcsp_packet_print(m);
#endif

	rcvpkt = mtod(m, uint32_t *);

	/* length of le packets is 4 */
	if (m->m_len == sizeof(uint32_t))
		for (i = 0; pkt[i].type != NULL; i++)
			if (*(const uint32_t *)pkt[i].datap == *rcvpkt)
				break;
	if (m->m_len != sizeof(uint32_t) || pkt[i].type == NULL) {
		printf("%s: received unknown packet\n", sc->sc_dev.dv_xname);
		m_freem(m);
		return;
	}

	rplypkt = NULL;
	switch (sc->sc_le_state) {
	case le_state_shy:
		if (*rcvpkt == *(const uint32_t *)sync) {
			sc->sc_le_muzzled = false;
			rplypkt = syncresp;
		} else if (*rcvpkt == *(const uint32_t *)syncresp) {
			DPRINTF(("%s: state change to curious\n",
			    sc->sc_dev.dv_xname));

			rplypkt = conf;
			callout_schedule(&sc->sc_le_timer,
			    BCSP_LE_TCONF_TIMEOUT);
			sc->sc_le_state = le_state_curious;
		} else
			printf("%s: received an unknown packet at shy\n",
			    sc->sc_dev.dv_xname);
		break;

	case le_state_curious:
		if (*rcvpkt == *(const uint32_t *)sync)
			rplypkt = syncresp;
		else if (*rcvpkt == *(const uint32_t *)conf)
			rplypkt = confresp;
		else if (*rcvpkt == *(const uint32_t *)confresp) {
			DPRINTF(("%s: state change to garrulous:\n",
			    sc->sc_dev.dv_xname));

			bcsp_set_choke(sc, false);
			callout_stop(&sc->sc_le_timer);
			sc->sc_le_state = le_state_garrulous;
		} else
			printf("%s: received unknown packet at curious\n",
			    sc->sc_dev.dv_xname);
		break;

	case le_state_garrulous:
		if (*rcvpkt == *(const uint32_t *)conf)
			rplypkt = confresp;
		else if (*rcvpkt == *(const uint32_t *)sync) {
			/* XXXXX */
			printf("%s: received sync!!  peer to reset?\n",
			    sc->sc_dev.dv_xname);

			sc->sc_le_state = le_state_shy;
		} else
			printf("%s: received unknown packet at garrulous\n",
			    sc->sc_dev.dv_xname);
		break;
	}

	m_freem(m);

	if (rplypkt != NULL) {
		MGETHDR(m, M_DONTWAIT, MT_DATA);
		if (m == NULL)
			printf("%s: out of memory\n", sc->sc_dev.dv_xname);
		else {
			/* length of le packets is 4 */
			m->m_pkthdr.len = m->m_len = 0;
			m_copyback(m, 0, 4, rplypkt);
			if (!bcsp_tx_unreliable_pkt(sc, m, BCSP_CHANNEL_LE))
				printf("%s: le-packet transmit failed\n",
				    sc->sc_dev.dv_xname);
		}
	}
}

static void
bcsp_le_timeout(void *arg)
{
	struct bcsp_softc *sc = arg;
	struct mbuf *m;
	int timeout;
	const uint8_t *sndpkt = NULL;

	DPRINTFN(0, ("%s: le timeout: state %d, muzzled %d\n",
	    sc->sc_dev.dv_xname, sc->sc_le_state, sc->sc_le_muzzled));

	switch (sc->sc_le_state) {
	case le_state_shy:
		if (!sc->sc_le_muzzled)
			sndpkt = sync;
		timeout = BCSP_LE_TSHY_TIMEOUT;
		break;

	case le_state_curious:
		sndpkt = conf;
		timeout = BCSP_LE_TCONF_TIMEOUT;
		break;

	default:
		printf("%s: timeout happen at unknown state %d\n",
		    sc->sc_dev.dv_xname, sc->sc_le_state);
		return;
	}

	if (sndpkt != NULL) {
		MGETHDR(m, M_DONTWAIT, MT_DATA);
		if (m == NULL)
			printf("%s: out of memory\n", sc->sc_dev.dv_xname);
		else {
			/* length of le packets is 4 */
			m->m_pkthdr.len = m->m_len = 0;
			m_copyback(m, 0, 4, sndpkt);
			if (!bcsp_tx_unreliable_pkt(sc, m, BCSP_CHANNEL_LE))
				printf("%s: le-packet transmit failed\n",
				    sc->sc_dev.dv_xname);
		}
	}

	callout_schedule(&sc->sc_le_timer, timeout);
}


/*
 * BlueCore Serial Protocol functions.
 */
static int
bcsp_enable(struct hci_unit *unit)
{

	if (unit->hci_flags & BTF_RUNNING)
		return 0;

	unit->hci_flags |= BTF_RUNNING;
	unit->hci_flags &= ~BTF_XMIT;

	return 0;
}

static void
bcsp_disable(struct hci_unit *unit)
{
	struct bcsp_softc *sc = unit->hci_softc;

	if ((unit->hci_flags & BTF_RUNNING) == 0)
		return;

	if (sc->sc_rxp) {
		m_freem(sc->sc_rxp);
		sc->sc_rxp = NULL;
	}

	if (sc->sc_txp) {
		m_freem(sc->sc_txp);
		sc->sc_txp = NULL;
	}

	unit->hci_flags &= ~BTF_RUNNING;
}

static void
bcsp_start(struct hci_unit *unit)
{
	struct bcsp_softc *sc = unit->hci_softc;
	struct mbuf *m;

	if (MBUFQ_FIRST(&unit->hci_acltxq)) {
		MBUFQ_DEQUEUE(&unit->hci_acltxq, m);
		unit->hci_stats.acl_tx++;
		M_SETCTX(m, NULL);
		m_adj(m, sizeof(uint8_t));
		bcsp_tx_reliable_pkt(sc, m, BCSP_CHANNEL_HCI_ACL);
	}

	if (MBUFQ_FIRST(&unit->hci_cmdq)) {
		MBUFQ_DEQUEUE(&unit->hci_cmdq, m);
		unit->hci_stats.cmd_tx++;
		M_SETCTX(m, NULL);
		m_adj(m, sizeof(uint8_t));
		bcsp_tx_reliable_pkt(sc, m, BCSP_CHANNEL_HCI_CMDEVT);
	}

	if (MBUFQ_FIRST(&unit->hci_scotxq)) {
		MBUFQ_DEQUEUE(&unit->hci_scotxq, m);
		unit->hci_stats.sco_tx++;
		/* XXXX: We can transmit with reliable */
		m_adj(m, sizeof(uint8_t));
		bcsp_tx_unreliable_pkt(sc, m, BCSP_CHANNEL_HCI_SCO);
	}

	return;
}


#ifdef BCSP_DEBUG
static void
bcsp_packet_print(struct mbuf *m)
{
	int i;
	uint8_t *p;

	for ( ; m != NULL; m = m->m_next) {
		p = mtod(m, uint8_t *);
		for (i = 0; i < m->m_len; i++) {
			if (i % 16 == 0)
				printf(" ");
			printf(" %02x", *(p + i));
			if (i % 16 == 15)
				printf("\n");
		}
		printf("\n");
	}
}
#endif

----Next_Part(Sun_Sep_23_04_54_36_2007_094)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="bcsp.h"

/*	$NetBSD$	*/
/*
 * Copyright (c) 2007 KIYOHARA Takashi
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _DEV_BLUETOOTH_BCSP_H_
#define _DEV_BLUETOOTH_BCSP_H_

/*
 * BlueCore Serial Protocol definitions
 */

/*
 * Reference to bcore-sp-012p.
 */
/* BCSP packet header */
typedef struct {
	uint8_t flags;
#if BYTE_ORDER == BIG_ENDIAN
	uint8_t plen1 :4;		/* Payload Length (bits 0-3) */
	uint8_t ident :4;		/* Protocol Identifier */
#else
	uint8_t ident :4;		/* Protocol Identifier */
	uint8_t plen1 :4;		/* Payload Length (bits 0-3) */
#endif
	uint8_t plen2;			/* Payload Length (bits 4-11) */
	uint8_t csum;			/* Checksum */
	u_char payload[0];
} __attribute__ ((__packed__)) bcsp_hdr_t;

#define BCSP_FLAGS_SEQ_SHIFT	0
#define BCSP_FLAGS_SEQ_MASK	0x07
#define BCSP_FLAGS_SEQ(n) \
	(((n) & BCSP_FLAGS_SEQ_MASK) >> BCSP_FLAGS_SEQ_SHIFT)
#define BCSP_FLAGS_ACK_SHIFT	3
#define BCSP_FLAGS_ACK_MASK	0x38
#define BCSP_FLAGS_ACK(n) \
	(((n) & BCSP_FLAGS_ACK_MASK) >> BCSP_FLAGS_ACK_SHIFT)
#define BCSP_FLAGS_CRC_PRESENT	0x40
#define BCSP_FLAGS_PROTOCOL_TYPE 0x80
#define BCSP_FLAGS_PROTOCOL_REL	0x80

#define BCSP_SET_PLEN(hdrp, n)				\
	do {						\
		(hdrp)->plen1 = ((n) & 0x00f);		\
		(hdrp)->plen2 = ((n) >> 4);		\
	} while (0)
#define BCSP_GET_PLEN(hdrp)	((hdrp)->plen1 | ((hdrp)->plen2 << 4))

#define BCSP_GET_CSUM(hdrp)						\
	(0xff - (uint8_t)((hdrp)->flags + ((hdrp)->plen1 << 4) +	\
	(hdrp)->ident + (hdrp)->plen2))
#define BCSP_SET_CSUM(hdrp)	((hdrp)->csum = BCSP_GET_CSUM(hdrp))


#define BCSP_IDENT_ACKPKT	0	/* Used by MUX Layer */
/* Other Protocol Identifier values described to bcore-sp-007P */


/* definitions of SLIP Layer */
#define BCSP_SLIP_PKTSTART	0xc0
#define BCSP_SLIP_PKTEND	BCSP_SLIP_PKTSTART
#define BCSP_SLIP_ESCAPE	0xdb
#define BCSP_SLIP_ESCAPE_PKTEND	0xdc
#define BCSP_SLIP_ESCAPE_ESCAPE	0xdd


/* definitions of Sequencing Layer */
#define BCSP_SEQ_TX_TIMEOUT	(hz / 4)	/* 250 msec */
#define BCSP_SEQ_TX_WINSIZE	4
#define BCSP_SEQ_TX_RETRY_LIMIT	20


/*
 * Reference to bcore-sp-007p.
 *   Channel Allocation
 */
#define BCSP_CHANNEL_LE		1	/* defined in [BCSPLE] */
#define BCSP_CHANNEL_BCCMD	2	/* defined in [BCCMD] */
#define BCSP_CHANNEL_HQ		3	/* defined in [HQ] */
#define BCSP_CHANNEL_DEVMGT	4	/* defined by BlueStack */
#define BCSP_CHANNEL_HCI_CMDEVT	5	/* HCI Command and Event */
#define BCSP_CHANNEL_HCI_ACL	6	/* HCI ACL data */
#define BCSP_CHANNEL_HCI_SCO	7	/* HCI SCO data */
#define BCSP_CHANNEL_L2CAP	8	/* defined by BlueStack */
#define BCSP_CHANNEL_RFCOMM	9	/* defined by BlueStack */
#define BCSP_CHANNEL_SDP	10	/* defined by BlueStack */

#define BCSP_CHANNEL_DFU	12	/* defined in [DFUPROT] */
#define BCSP_CHANNEL_VM		13	/* Virtual Machine */


/*
 * Reference to bcore-sp-008p ??
 *   Link Establishment Protocol
 */
typedef enum {
	le_state_shy,
	le_state_curious,
	le_state_garrulous
} bcsp_le_state_t;

#define BCSP_LE_SYNC		{ 0xda, 0xdc, 0xed, 0xed }
#define BCSP_LE_SYNCRESP	{ 0xac, 0xaf, 0xef, 0xee }
#define BCSP_LE_CONF		{ 0xad, 0xef, 0xac, 0xed }
#define BCSP_LE_CONFRESP	{ 0xde, 0xad, 0xd0, 0xd0 }

#define BCSP_LE_TSHY_TIMEOUT	hz	/* XXXX: 1sec ? */
#define BCSP_LE_TCONF_TIMEOUT	hz	/* XXXX: 1sec ? */

#endif	/* !_DEV_BLUETOOTH_BCSP_H_ */

----Next_Part(Sun_Sep_23_04_54_36_2007_094)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="bcsp.4"

.\" $NetBSD$
.\"
.\" Copyright (c) 2007 KIYOHARA Takashi
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
.\" DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd September 20, 2007
.Dt BCSP 4
.Os
.Sh NAME
.Nm bcsp
.Nd BlueCore Serial Protocol driver
.Sh SYNOPSIS
.Cd pseudo-device bcsp
.Sh DESCRIPTION
The
.Nm
driver provides a
.Xr tty 4
line discipline to send and receive BlueCore Serial Protocol packets over
a serial line, as described in the
.Qo
BlueCore Serial Protocol (BCSP)
.Qc
.Pp
Moreover,
The
.Nm
supports BCSP Link Establishment Protocol. It described in the
.Qo
BCSP Link Establishment Protocol
.Qc
.Sh SEE ALSO
.Xr bluetooth 4 ,
.Xr btuart 4
.Xr btuartd 8
.Sh HISTORY
The
.Nm
device appeared in
.Nx 4.0 .
.Sh AUTHORS
.An KIYOHARA Takashi Aq kiyohara@kk.iij4u.or.jp

----Next_Part(Sun_Sep_23_04_54_36_2007_094)----

----Next_Part(Mon_Sep_24_03_42_44_2007_020)----