Subject: Re: Bluetooth module on com(4)
To: None <plunky@rya-online.net>
From: KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp>
List: tech-kern
Date: 01/09/2007 14:11:31
----Next_Part(Tue_Jan__9_14_11_31_2007_760)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi! Iain,


From: KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp>
Date: Tue, 05 Dec 2006 02:45:33 +0900 (JST)

> > It should be possible to do similar but attach a pseudo device instance
> > when the line discipline is opened, and the data does not need to pass
> > through userland but can go directly through the line discipline to the
> > bluetooth stack (the btuartd is just a place holder). If the line
> > discipline is closed, the pseudo device is detached and all connections
> > through it are killed automatically.
> 
> Sure.  I will write this in several days. ;-)

ppp(4) was able to be done with btuart on my gumstix.  My LSI vendor
is ericsson.  Besides, I think that the initialization of CSR is also
possible. However, I do not have the device of CSR. 

I referred to the following URL. 

  http://wiki.netbsd.se/index.php/Bluetooth

However, SCO audio did not work. Is this the same reason as bt3c(4)?

I am referring to hciattach(8) of bluez.  The data sheet of ericsson
and CSR was seen.  However, the rest was not able to be found. 

I will coordinate btuartd.c.

Thanks,
--
kiyohara


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

Index: sys/dev/bluetooth/files.bluetooth
===================================================================
RCS file: /cvsroot/src/sys/dev/bluetooth/files.bluetooth,v
retrieving revision 1.10
diff -u -r1.10 files.bluetooth
--- sys/dev/bluetooth/files.bluetooth	10 Sep 2006 15:45:56 -0000	1.10
+++ sys/dev/bluetooth/files.bluetooth	6 Jan 2007 09:14:09 -0000
@@ -31,3 +31,7 @@
 device btsco: bluetooth, audiobus, auconv, mulaw, aurateconv
 attach btsco at bthub
 file dev/bluetooth/btsco.c		btsco
+
+# Bluetooth HCI UART (H4)
+defpseudo btuart: btbus, bluetooth
+file dev/bluetooth/btuart.c		btuart
Index: sys/dev/ic/com.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/com.c,v
retrieving revision 1.255
diff -u -r1.255 com.c
--- sys/dev/ic/com.c	12 Oct 2006 01:31:00 -0000	1.255
+++ sys/dev/ic/com.c	6 Jan 2007 09:14:10 -0000
@@ -271,12 +271,6 @@
 const bus_size_t com_std_map[16] = COM_REG_16550;
 #endif /* COM_REGMAP */
 
-#define	COMUNIT_MASK	0x7ffff
-#define	COMDIALOUT_MASK	0x80000
-
-#define	COMUNIT(x)	(minor(x) & COMUNIT_MASK)
-#define	COMDIALOUT(x)	(minor(x) & COMDIALOUT_MASK)
-
 #define	COM_ISALIVE(sc)	((sc)->enabled != 0 && \
 			 device_is_active(&(sc)->sc_dev))
 
Index: sys/dev/ic/comvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/comvar.h,v
retrieving revision 1.54
diff -u -r1.54 comvar.h
--- sys/dev/ic/comvar.h	13 Jul 2006 22:56:02 -0000	1.54
+++ sys/dev/ic/comvar.h	6 Jan 2007 09:14:10 -0000
@@ -224,6 +224,12 @@
 	struct simplelock	sc_lock;
 };
 
+#define	COMUNIT_MASK	0x7ffff
+#define	COMDIALOUT_MASK	0x80000
+
+#define	COMUNIT(x)	(minor(x) & COMUNIT_MASK)
+#define	COMDIALOUT(x)	(minor(x) & COMDIALOUT_MASK)
+
 int comprobe1(bus_space_tag_t, bus_space_handle_t);
 int comintr(void *);
 void com_attach_subr(struct com_softc *);
Index: sys/kern/tty_conf.c
===================================================================
RCS file: /cvsroot/src/sys/kern/tty_conf.c,v
retrieving revision 1.52
diff -u -r1.52 tty_conf.c
--- sys/kern/tty_conf.c	1 Nov 2006 10:17:59 -0000	1.52
+++ sys/kern/tty_conf.c	6 Jan 2007 09:14:14 -0000
@@ -276,6 +276,7 @@
 		{ "ppp",		PPPDISC },
 		{ "strip",		STRIPDISC },
 		{ "hdlc",		HDLCDISC },
+		{ "bth4",		BTH4DISC },
 		{ NULL,			0 }
 	};
 	struct linesw *ldisc;
Index: sys/netbt/hci.h
===================================================================
RCS file: /cvsroot/src/sys/netbt/hci.h,v
retrieving revision 1.6
diff -u -r1.6 hci.h
--- sys/netbt/hci.h	1 Oct 2006 10:13:54 -0000	1.6
+++ sys/netbt/hci.h	6 Jan 2007 09:14:16 -0000
@@ -1589,8 +1589,12 @@
 
 /* Ericsson specific FC */
 #define HCI_CMD_ERICSSON_WRITE_PCM_SETTINGS		0xFC07
+#define HCI_CMD_ERICSSON_SET_UART_BAUD_RATE		0xFC09
 #define HCI_CMD_ERICSSON_SET_SCO_DATA_PATH		0xFC1D
 
+/* Cambridge Silicon Radio specific FC */
+#define HCI_CMD_CSR_EXTN				0xFC00
+
 
 /**************************************************************************
  **************************************************************************
Index: sys/sys/ttycom.h
===================================================================
RCS file: /cvsroot/src/sys/sys/ttycom.h,v
retrieving revision 1.18
diff -u -r1.18 ttycom.h
--- sys/sys/ttycom.h	11 Dec 2005 12:25:21 -0000	1.18
+++ sys/sys/ttycom.h	6 Jan 2007 09:14:16 -0000
@@ -160,5 +160,6 @@
 #define	PPPDISC		5		/* ppp discipline */
 #define	STRIPDISC	6		/* metricom wireless IP discipline */
 #define	HDLCDISC	9		/* HDLC discipline */
+#define	BTH4DISC	10		/* Bluetooth HCI UART (H4) discipline */
 
 #endif /* !_SYS_TTYCOM_H_ */
--- sys/dev/bluetooth/btuart.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ sys/dev/bluetooth/btuart.c	2007-01-06 18:07:39.000000000 +0900
@@ -0,0 +1,968 @@
+/*	$NetBSD$	*/
+/*
+ * Copyright (c) 2006 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/types.h>
+#include <sys/param.h>
+
+#include <sys/conf.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/systm.h>
+#include <sys/tty.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <netbt/bluetooth.h>
+#include <netbt/hci.h>
+
+#include <dev/bluetooth/btuartvar.h>
+#include <dev/ic/comvar.h>
+
+#include "ioconf.h"
+
+#define BTUART_DEBUG
+#ifdef BTUART_DEBUG
+int btuart_debug = 1;
+#define IFDBG		if (btuart_debug)
+#else
+#define IFDBG		if (0)
+#endif
+
+struct btuart_softc;
+struct bth4hci {
+	int type;
+	int init_speed;
+#define FLOW_CTL	1
+	int flags;
+	int (*init)(struct btuart_softc *);
+};
+
+struct btuart_softc {
+	struct device sc_dev;
+
+	struct tty *sc_tp;
+	struct hci_unit sc_unit;		/* Bluetooth HCI Unit */
+
+	struct bth4hci sc_bth4hci;
+	int sc_speed;
+
+	int sc_state;				/* receive state */
+#define BTUART_RECV_PKT_TYPE	0			/* packet type */
+#define BTUART_RECV_ACL_HDR	1			/* acl header */
+#define BTUART_RECV_SCO_HDR	2			/* sco header */
+#define BTUART_RECV_EVENT_HDR	3			/* event header */
+#define BTUART_RECV_ACL_DATA	4			/* acl packet data */
+#define BTUART_RECV_SCO_DATA	5			/* sco packet data */
+#define BTUART_RECV_EVENT_DATA	6			/* event packet data */
+	int sc_want;				/* how much we want */
+	struct mbuf *sc_rxp;			/* incoming packet */
+	struct mbuf *sc_txp;			/* outgoing packet */
+
+	void (*sc_input_acl)(struct hci_unit *, struct mbuf *);
+	void (*sc_input_sco)(struct hci_unit *, struct mbuf *);
+	void (*sc_input_event)(struct hci_unit *, struct mbuf *);
+};
+
+void btuartattach(int);
+static struct btuart_softc * btuart_alloc(size_t);
+static void btuart_dealloc(struct btuart_softc *);
+
+static int init_ericsson(struct btuart_softc *);
+static int init_digi(struct btuart_softc *);
+static int init_texas(struct btuart_softc *);
+static int init_csr(struct btuart_softc *);
+static int init_swave(struct btuart_softc *);
+static int init_st(struct btuart_softc *);
+static int init_stlc2500(struct btuart_softc *);
+static int init_bcm2035(struct btuart_softc *);
+static int bth4init(struct btuart_softc *);
+static void bth4init_input(struct hci_unit *, struct mbuf *);
+
+static int bth4open(dev_t, struct tty *);
+static int bth4close(struct tty *, int);
+static int bth4ioctl(struct tty *, u_long, caddr_t, int, struct lwp *);
+static int bth4input(int, struct tty *);
+static int bth4start(struct tty *);
+
+static int bth4_enable(struct hci_unit *);
+static void bth4_disable(struct hci_unit *);
+static void bth4_start(struct hci_unit *);
+
+static struct linesw bth4_disc = {
+	.l_name = "bth4",
+	.l_open = bth4open,
+	.l_close = bth4close,
+	.l_read = ttyerrio,
+	.l_write = ttyerrio,
+	.l_ioctl = bth4ioctl,
+	.l_rint = bth4input,
+	.l_start = bth4start,
+	.l_modem = ttymodem,
+	.l_poll = ttyerrpoll
+};
+
+static struct bth4hci bth4hci[] = {
+	{ BTUART_HCITYPE_ANY,		     0, FLOW_CTL, NULL },
+	{ BTUART_HCITYPE_ERICSSON,	 57600, FLOW_CTL, init_ericsson },
+	{ BTUART_HCITYPE_DIGI,		  9600, FLOW_CTL, init_digi },
+	{ BTUART_HCITYPE_TEXAS,		115200, FLOW_CTL, init_texas },
+	/* CSR Casira serial adapter or BrainBoxes serial dongle (BL642) */
+	{ BTUART_HCITYPE_CSR,		115200, FLOW_CTL, init_csr },
+	/* Silicon Wave kits */
+	{ BTUART_HCITYPE_SWAVE,		115200, FLOW_CTL, init_swave },
+	/* ST Microelectronics minikits based on STLC2410/STLC2415 */
+	{ BTUART_HCITYPE_ST,		 57600, FLOW_CTL, init_st },
+	/* ST Microelectronics minikits based on STLC2500 */
+	{ BTUART_HCITYPE_STLC2500,	115200, FLOW_CTL, init_stlc2500 },
+	/* AmbiCom BT2000C Bluetooth PC/CF Card */
+	{ BTUART_HCITYPE_BT2000C,	 57600, FLOW_CTL, init_csr },
+	/* Broadcom BCM2035 */
+	{ BTUART_HCITYPE_BCM2035,	115200,        0, init_bcm2035 },
+
+	{ -1 }
+};
+static struct speedtbl {
+	int s;
+	int speed;
+} speedtbl[] = {
+	{      0, B0 },
+	{     50, B50 },
+	{     75, B75 },
+	{    110, B110 },
+	{    134, B134 },
+	{    150, B150 },
+	{    200, B200 },
+	{    300, B300 },
+	{    600, B600 },
+	{   1200, B1200 },
+	{   1800, B1800 },
+	{   2400, B2400 },
+	{   4800, B4800 },
+	{   9600, B9600 },
+	{  19200, B19200 },
+	{  38400, B38400 },
+	{   7200, B7200 },
+	{  14400, B14400 },
+	{  28800, B28800 },
+	{  57600, B57600 },
+	{  76800, B76800 },
+	{ 115200, B115200 },
+	{ 230400, B230400 },
+	{ 460800, B460800 },
+	{ 921600, B921600 },
+	{     -1, B57600 },
+};
+
+
+/* ARGSUSED */
+void
+btuartattach(int num __unused)
+{
+
+	ttyldisc_attach(&bth4_disc);
+}
+
+static struct btuart_softc *
+btuart_alloc(size_t size)
+{
+	struct cfdriver *cd = &btuart_cd;
+	struct device *dev;
+	int unit;
+
+	for (unit = 0; unit < cd->cd_ndevs; unit++)
+		if (cd->cd_devs[unit] == NULL)
+			break;
+	dev = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
+	memset(dev, 0, size);
+	dev->dv_class = cd->cd_class;
+	dev->dv_cfdriver = cd;
+	dev->dv_unit = unit;
+	snprintf(dev->dv_xname, sizeof dev->dv_xname, "btuart%d", unit);
+	dev->dv_flags = DVF_ACTIVE;		/* always initially active */
+
+	config_makeroom(unit, cd);
+	cd->cd_devs[unit] = dev;
+
+	printf("%s", dev->dv_xname);
+
+	return ((struct btuart_softc *)dev);
+}
+
+static void
+btuart_dealloc(struct btuart_softc *sc)
+{
+	struct cfdriver *cd = &btuart_cd;
+	struct device *dev = &sc->sc_dev;
+	int unit;
+
+	for (unit = 0; unit < cd->cd_ndevs; unit++) {
+		if (cd->cd_devs[unit] == dev) {
+			cd->cd_devs[unit] = NULL;
+			free(dev, M_DEVBUF);
+			return;
+		}
+	}
+	panic("btuart_dealloc: device not found");
+}
+
+
+/*
+ * LSI initialize functions.
+ */
+static int
+init_ericsson(struct btuart_softc *sc)
+{
+	struct mbuf *m;
+	struct hci_unit *unit = &sc->sc_unit;
+	hci_cmd_hdr_t *p;
+	int i, error = 0;
+	struct {
+		int speed;
+		uint8_t param;
+	} baudratetbl[] = {
+		{ B460800, 0x00 },
+		{ B230400, 0x01 },
+		{ B115200, 0x02 },
+		{  B57600, 0x03 },
+		{  B28800, 0x04 },
+		{  B14400, 0x05 },
+		{   B7200, 0x06 },
+#if defined(B3600)
+		{   B3600, 0x07 },
+#endif
+		{   B1800, 0x08 },
+#if defined(B900)
+		{    B900, 0x09 },
+#endif
+#if defined(B153600)
+		{ B153600, 0x10 },
+#endif
+		{  B76800, 0x11 },
+		{  B38400, 0x12 },
+		{  B19200, 0x13 },
+		{   B9600, 0x14 },
+		{   B4800, 0x15 },
+		{   B2400, 0x16 },
+		{   B1200, 0x17 },
+		{    B600, 0x18 },
+		{    B300, 0x19 },
+		{ B921600, 0x20 },
+		{ -1 }
+	};
+
+	m = m_gethdr(M_DONTWAIT, MT_DATA);
+	if (m == NULL)
+		return ENOMEM;
+
+	p = mtod(m, hci_cmd_hdr_t *);
+	p->type = HCI_CMD_PKT;
+	p->opcode = htole16(HCI_CMD_ERICSSON_SET_UART_BAUD_RATE);
+	p->length = 1;
+	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
+
+	for (i = 0; baudratetbl[i].speed != sc->sc_speed; i++)
+		if (baudratetbl[i].speed == -1)
+			return EINVAL;
+	m_copyback(m, sizeof(hci_cmd_hdr_t), p->length, &baudratetbl[i].param);
+
+	MBUFQ_ENQUEUE(&unit->hci_cmdq, m);
+	bth4_start(unit);
+
+#if 0
+	m = NULL;
+	while (1 /* CONSTCOND */) {
+		hci_event_hdr_t *e;
+
+		if ((error =
+		    tsleep(&unit->hci_eventq, PCATCH, "bth4init", 0)) != 0)
+			break;
+
+		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
+		unit->hci_eventqlen--;
+		KASSERT(m != NULL);
+
+		e = mtod(m, hci_event_hdr_t *);
+		if (e->event == HCI_EVENT_VENDOR)
+			break;
+		m_freem(m);
+	}
+	if (m != NULL)
+		m_freem(m);
+
+	return error;
+#else
+	/*
+	 * XXXX: We cannot correctly receive this response perhaps.
+	 * Wait until the transmission of the data of 5 bytes is completed.
+	 * And it is assumed that init_speed is a baud rate value.
+	 */
+	delay(1000000 * 10/*bit*/ * 5/*byte*/ / sc->sc_bth4hci.init_speed);
+	return error;
+#endif
+}
+
+static int
+init_digi(struct btuart_softc *sc)
+{
+
+	/* not yet */
+	return EINVAL;
+}
+
+static int
+init_texas(struct btuart_softc *sc)
+{
+
+	/* not yet */
+	return EINVAL;
+}
+
+static int
+init_csr(struct btuart_softc *sc)
+{
+#ifdef nottest
+	struct mbuf *m;
+	struct hci_unit *unit = &sc->sc_unit;
+	hci_cmd_hdr_t *p;
+	hci_event_hdr_t *e;
+	int error;
+	struct {
+		uint8_t last :1;
+		uint8_t first :1;
+#define CSR_BCCMD_CHANID_BCCMD		2
+#define CSR_BCCMD_CHANID_HQ		3
+#define CSR_BCCMD_CHANID_DEVMGRLIB	4
+#define CSR_BCCMD_CHANID_L2CAPLIB	8
+#define CSR_BCCMD_CHANID_RFCOMMLIB	9
+#define CSR_BCCMD_CHANID_SDPLIB		10
+#define CSR_BCCMD_CHANID_DFU		12
+#define CSR_BCCMD_CHANID_VM		13
+#define CSR_BCCMD_CHANID_LMDEBUG	20
+		uint8_t chanid :6;
+
+		struct {
+#define CSR_BCCMD_MESSAGE_TYPE_GETREQ	0x0000
+#define CSR_BCCMD_MESSAGE_TYPE_GETRESP	0x0001
+#define CSR_BCCMD_MESSAGE_TYPE_SETREQ	0x0002
+			uint16_t type;
+			uint16_t length;
+			uint16_t seqno;
+#define CSR_BCCMD_MESSAGE_VARID_CONFIG_UART		0x6802
+#define CSR_BCCMD_MESSAGE_VARID_CONFIG_UART_STOPB		0x2000
+#define CSR_BCCMD_MESSAGE_VARID_CONFIG_UART_PARENB		0x4000
+#define CSR_BCCMD_MESSAGE_VARID_CONFIG_UART_PARODD		0x8000
+			uint16_t varid;
+#define CSR_BCCMD_MESSAGE_STATUS_OK			0x0000
+#define CSR_BCCMD_MESSAGE_STATUS_NO_SUCH_VARID		0x0001
+#define CSR_BCCMD_MESSAGE_STATUS_TOO_BIG		0x0002
+#define CSR_BCCMD_MESSAGE_STATUS_NO_VALUE		0x0003
+#define CSR_BCCMD_MESSAGE_STATUS_BAD_REQ		0x0004
+#define CSR_BCCMD_MESSAGE_STATUS_NO_ACCESS		0x0005
+#define CSR_BCCMD_MESSAGE_STATUS_READ_ONLY		0x0006
+#define CSR_BCCMD_MESSAGE_STATUS_WRITE_ONLY		0x0007
+#define CSR_BCCMD_MESSAGE_STATUS_ERROR			0x0008
+#define CSR_BCCMD_MESSAGE_STATUS_PERMISION_DENIED	0x0009
+			uint16_t status;
+			uint16_t payload[4];
+		} message;
+	} bccmd;
+
+	m = m_gethdr(M_DONTWAIT, MT_DATA);
+	if (m == NULL)
+		return ENOMEM;
+
+	p = mtod(m, hci_cmd_hdr_t *);
+	p->type = HCI_CMD_PKT;
+	p->opcode =htole16(HCI_CMD_CSR_EXTN);
+	p->length = sizeof (bccmd);
+	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
+
+	bccmd.last = 1;
+	bccmd.first = 1;
+	bccmd.chanid = CSR_BCCMD_CHANID_BCCMD;
+	bccmd.message.type = htole16(CSR_BCCMD_MESSAGE_TYPE_SETREQ);
+	bccmd.message.length = htole16(sizeof (bccmd.message) >> 1);
+	bccmd.message.seqno = htole16(0);
+	bccmd.message.varid = htole16(CSR_BCCMD_MESSAGE_VARID_CONFIG_UART);
+	bccmd.message.status = htole16(CSR_BCCMD_MESSAGE_STATUS_OK);
+	bzero(bccmd.message.payload, sizeof (bccmd.message.payload));
+
+	/*
+	 * Value = (baud rate / 244.140625) | no parity | 1 stop bit.
+	 * And it is assumed that sc_speed is a baud rate value.
+	 */
+	bccmd.message.payload[0] = htole16((sc->sc_speed * 64 + 7812) / 15625);
+
+	m_copyback(m, sizeof(hci_cmd_hdr_t), p->length, &bccmd);
+	MBUFQ_ENQUEUE(&unit->hci_cmdq, m);
+	bth4_start(unit);
+
+	m = NULL;
+	while (1 /* CONSTCOND */) {
+		if ((error =
+		    tsleep(&unit->hci_eventq, PCATCH, "bth4init", 0)) != 0)
+			break;
+
+		MBUFQ_DEQUEUE(&unit->hci_eventq, m);
+		unit->hci_eventqlen--;
+		KASSERT(m != NULL);
+
+		e = mtod(m, hci_event_hdr_t *);
+		if (e->event == HCI_EVENT_VENDOR)
+			break;
+		m_freem(m);
+	}
+	if (m != NULL)
+		m_freem(m);
+
+	return error;
+#else
+
+	/* not yet */
+	return EINVAL;
+#endif
+}
+
+static int
+init_swave(struct btuart_softc *sc)
+{
+
+	/* not yet */
+	return EINVAL;
+}
+
+static int
+init_st(struct btuart_softc *sc)
+{
+
+	/* not yet */
+	return EINVAL;
+}
+
+static int
+init_stlc2500(struct btuart_softc *sc)
+{
+
+	/* not yet */
+	return EINVAL;
+}
+
+static int
+init_bcm2035(struct btuart_softc *sc)
+{
+
+	/* not yet */
+	return EINVAL;
+}
+
+static int
+bth4init(struct btuart_softc *sc)
+{
+	struct tty *tp = sc->sc_tp;
+	struct termios t;
+	int error = 0, s;
+
+	sc->sc_speed = tp->t_ospeed;
+	t.c_cflag = tp->t_cflag;
+	t.c_ispeed = 0;
+	t.c_ospeed = tp->t_ospeed;
+	if ((tp->t_cflag & CRTSCTS) && !(sc->sc_bth4hci.flags & FLOW_CTL))
+		t.c_cflag &= ~CRTSCTS;
+	if (sc->sc_bth4hci.init_speed != 0 &&
+	    tp->t_ospeed != sc->sc_bth4hci.init_speed)
+		t.c_ospeed = sc->sc_bth4hci.init_speed;
+	if (t.c_ospeed != tp->t_ospeed || t.c_cflag != tp->t_cflag)
+		error = (*tp->t_param)(tp, &t);
+
+	if (error == 0 && sc->sc_bth4hci.init != NULL)
+		error = (*sc->sc_bth4hci.init)(sc);
+
+	s = splhigh();
+	sc->sc_input_acl = hci_input_acl;
+	sc->sc_input_sco = hci_input_sco;
+	sc->sc_input_event = hci_input_event;
+	splx(s);
+
+	if (sc->sc_bth4hci.init_speed != 0 &&
+	    sc->sc_bth4hci.init_speed != sc->sc_speed) {
+		t.c_ospeed = sc->sc_speed;
+		t.c_cflag = tp->t_cflag;
+		error = (*tp->t_param)(tp, &t);
+	}
+
+	return error;
+}
+
+static void
+bth4init_input(struct hci_unit *unit, struct mbuf *m)
+{
+	uint8_t *rptr =  mtod(m, uint8_t *);
+
+	IFDBG {
+		int i;
+
+		printf("%s:", __FUNCTION__);
+		for (i = 0; i < m->m_len; i++)
+			printf(" %02x", *(rptr + i));
+		printf("\n");
+	}
+
+	switch (*rptr) {
+	case HCI_ACL_DATA_PKT:
+		if (unit->hci_aclrxqlen <= hci_aclrxq_max) {
+			unit->hci_aclrxqlen++;
+			MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
+			m = NULL;
+			wakeup(&unit->hci_aclrxq);
+		}
+		break;
+	case HCI_SCO_DATA_PKT:
+		if (unit->hci_scorxqlen <= hci_scorxq_max) {
+			unit->hci_scorxqlen++;
+			MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
+			m = NULL;
+			wakeup(&unit->hci_scorxq);
+		}
+		break;
+	case HCI_EVENT_PKT:
+		if (unit->hci_eventqlen <= hci_eventq_max) {
+			unit->hci_eventqlen++;
+			MBUFQ_ENQUEUE(&unit->hci_eventq, m);
+			m = NULL;
+			wakeup(&unit->hci_eventq);
+		}
+		break;
+	}
+	if (m != NULL)
+		m_freem(m);
+}
+
+
+/*
+ * Line discipline functions.
+ */
+/* ARGSUSED */
+static int
+bth4open(dev_t device __unused, struct tty *tp)
+{
+	struct btuart_softc *sc;
+	struct lwp *l = curlwp;		/* XXX */
+	int error, i, s;
+
+	if ((error = kauth_authorize_device_tty(l->l_cred,
+	    KAUTH_DEVICE_TTY_OPEN, tp)) != 0)
+		return error;
+
+	s = spltty();
+
+	if (tp->t_linesw == &bth4_disc) {
+		sc = (struct btuart_softc *)tp->t_sc;
+		if (sc != NULL) {
+			splx(s);
+			return EBUSY;
+		}
+	}
+
+	KASSERT(tp->t_oproc != NULL);
+
+	tp->t_sc = sc = btuart_alloc(sizeof (struct btuart_softc));
+	sc->sc_tp = tp;
+	sc->sc_input_acl = bth4init_input;
+	sc->sc_input_sco = bth4init_input;
+	sc->sc_input_event = bth4init_input;
+	printf(": attached at tty%02d\n", COMUNIT(tp->t_dev));
+
+	ttyflush(tp, FREAD | FWRITE);
+
+	/* Copy default type */
+	for (i = 0; bth4hci[i].type != BTUART_HCITYPE_ANY; i++);
+	memcpy(&sc->sc_bth4hci, &bth4hci[i], sizeof (struct bth4hci));
+
+	/* Attach Bluetooth unit */
+	sc->sc_unit.hci_softc = sc;
+	sc->sc_unit.hci_devname = sc->sc_dev.dv_xname;
+	sc->sc_unit.hci_enable = bth4_enable;
+	sc->sc_unit.hci_disable = bth4_disable;
+	sc->sc_unit.hci_start_cmd = bth4_start;
+	sc->sc_unit.hci_start_acl = bth4_start;
+	sc->sc_unit.hci_start_sco = bth4_start;
+	sc->sc_unit.hci_ipl = IPL_TTY;
+	hci_attach(&sc->sc_unit);
+
+	splx(s);
+
+	return 0;
+}
+
+/* ARGSUSED */
+static int
+bth4close(struct tty *tp, int flag __unused)
+{
+	struct btuart_softc *sc = (struct btuart_softc *)tp->t_sc;
+	int s;
+
+	sc = tp->t_sc;
+
+	s = spltty();
+	ttyflush(tp, FREAD | FWRITE);
+	ttyldisc_release(tp->t_linesw);
+	tp->t_linesw = ttyldisc_default();
+	if (sc != NULL) {
+		tp->t_sc = NULL;
+		printf("%s detached from tty%02d\n",
+		    sc->sc_dev.dv_xname, COMUNIT(tp->t_dev));
+
+		hci_detach(&sc->sc_unit);
+		if (sc->sc_tp == tp)
+			btuart_dealloc(sc);
+	}
+	splx(s);
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+bth4ioctl(struct tty *tp, u_long cmd, caddr_t data,
+    int flag __unused, struct lwp *l __unused)
+{
+	struct btuart_softc *sc = (struct btuart_softc *)tp->t_sc;
+	int error, i;
+
+	if (sc == NULL || tp != sc->sc_tp)
+		return (EPASSTHROUGH);
+
+	error = 0;
+	switch (cmd) {
+	case BTUART_HCITYPE:
+		for (i = 0; bth4hci[i].type != -1; i++)
+			if (bth4hci[i].type == *(uint32_t *)data)
+				break;
+		if (bth4hci[i].type != -1)
+			memcpy(&sc->sc_bth4hci, &bth4hci[i],
+			    sizeof (struct bth4hci));
+		else
+			error = EINVAL;
+		break;
+
+	case BTUART_INITSPEED:
+		for (i = 0; speedtbl[i].s != -1; i++)
+			if (speedtbl[i].s == *(uint32_t *)data)
+				break;
+		if (speedtbl[i].s != -1)
+			sc->sc_bth4hci.init_speed = speedtbl[i].speed;
+		else
+			error = EINVAL;
+		break;
+
+	case BTUART_START:
+		error = bth4init(sc);
+		break;
+
+	default:
+		error = EPASSTHROUGH;
+		break;
+	}
+
+	return (error);
+}
+
+static int
+bth4input(int c, struct tty *tp)
+{
+	struct btuart_softc *sc = (struct btuart_softc *)tp->t_sc;
+	struct mbuf *m = sc->sc_rxp;
+	int space = 0;
+
+	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;
+
+		space = M_TRAILINGSPACE(m);
+	}
+
+	if (space == 0) {
+		if (m == NULL) {
+			/* 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;
+			space = MHLEN;
+
+			sc->sc_state = BTUART_RECV_PKT_TYPE;
+			sc->sc_want = 1;
+		} else {
+			/* 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;
+			space = MLEN;
+
+			if (sc->sc_want > MINCLSIZE) {
+				MCLGET(m, M_DONTWAIT);
+				if (m->m_flags & M_EXT)
+					space = MCLBYTES;
+			}
+		}
+	}
+
+	mtod(m, uint8_t *)[m->m_len++] = c;
+	sc->sc_rxp->m_pkthdr.len++;
+	sc->sc_unit.hci_stats.byte_rx++;
+
+	sc->sc_want--;
+	if (sc->sc_want > 0)
+		return 0;	/* want more */
+
+	switch (sc->sc_state) {
+	case BTUART_RECV_PKT_TYPE:	/* Got packet type */
+
+		switch (c) {
+		case HCI_ACL_DATA_PKT:
+			sc->sc_state = BTUART_RECV_ACL_HDR;
+			sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
+			break;
+
+		case HCI_SCO_DATA_PKT:
+			sc->sc_state = BTUART_RECV_SCO_HDR;
+			sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
+			break;
+
+		case HCI_EVENT_PKT:
+			sc->sc_state = BTUART_RECV_EVENT_HDR;
+			sc->sc_want = sizeof(hci_event_hdr_t) - 1;
+			break;
+
+		default:
+			printf("%s: Unknown packet type=%#x!\n",
+			    sc->sc_dev.dv_xname, c);
+			sc->sc_unit.hci_stats.err_rx++;
+			m_freem(sc->sc_rxp);
+			sc->sc_rxp = NULL;
+			return 0;	/* (lost sync) */
+		}
+
+		break;
+
+	/*
+	 * we assume (correctly of course :) that the packet headers all fit
+	 * into a single pkthdr mbuf
+	 */
+	case BTUART_RECV_ACL_HDR:	/* Got ACL Header */
+		sc->sc_state = BTUART_RECV_ACL_DATA;
+		sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
+		sc->sc_want = le16toh(sc->sc_want);
+		break;
+
+	case BTUART_RECV_SCO_HDR:	/* Got SCO Header */
+		sc->sc_state = BTUART_RECV_SCO_DATA;
+		sc->sc_want =  mtod(m, hci_scodata_hdr_t *)->length;
+		break;
+
+	case BTUART_RECV_EVENT_HDR:	/* Got Event Header */
+		sc->sc_state = BTUART_RECV_EVENT_DATA;
+		sc->sc_want =  mtod(m, hci_event_hdr_t *)->length;
+		break;
+
+	case BTUART_RECV_ACL_DATA:	/* ACL Packet Complete */
+		(*sc->sc_input_acl)(&sc->sc_unit, sc->sc_rxp);
+		sc->sc_unit.hci_stats.acl_rx++;
+		sc->sc_rxp = m = NULL;
+		break;
+
+	case BTUART_RECV_SCO_DATA:	/* SCO Packet Complete */
+		(*sc->sc_input_sco)(&sc->sc_unit, sc->sc_rxp);
+		sc->sc_unit.hci_stats.sco_rx++;
+		sc->sc_rxp = m = NULL;
+		break;
+
+	case BTUART_RECV_EVENT_DATA:	/* Event Packet Complete */
+		sc->sc_unit.hci_stats.evt_rx++;
+		(*sc->sc_input_event)(&sc->sc_unit, sc->sc_rxp);
+		sc->sc_rxp = m = NULL;
+		break;
+
+	default:
+		panic("%s: invalid state %d!\n",
+		    sc->sc_dev.dv_xname, sc->sc_state);
+	}
+
+	return 0;
+}
+
+static int
+bth4start(struct tty *tp)
+{
+	struct btuart_softc *sc = (struct btuart_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;
+		bth4_start(&sc->sc_unit);
+		return 0;
+	}
+
+	count = 0;
+	rlen = 0;
+	rptr = mtod(m, uint8_t *);
+
+	for(;;) {
+		if (rlen >= m->m_len) {
+			m = m->m_next;
+			if (m == NULL) {
+				m = sc->sc_txp;
+				sc->sc_txp = NULL;
+
+				if (M_GETCTX(m, void *) == NULL)
+					m_freem(m);
+				else
+					hci_complete_sco(&sc->sc_unit, m);
+
+				break;
+			}
+
+			rlen = 0;
+			rptr = mtod(m, uint8_t *);
+			continue;
+		}
+
+		if (putc(*rptr++, &tp->t_outq) < 0) {
+			m_adj(m, rlen);
+			break;
+		}
+		rlen++;
+		count++;
+	}
+
+	sc->sc_unit.hci_stats.byte_tx += count;
+
+	if (tp->t_outq.c_cc != 0)
+		(*tp->t_oproc)(tp);
+
+	return 0;
+}
+
+
+/*
+ * HCI UART (H4) functions.
+ */
+static int
+bth4_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
+bth4_disable(struct hci_unit *unit)
+{
+	struct btuart_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
+bth4_start(struct hci_unit *unit)
+{
+	struct btuart_softc *sc = unit->hci_softc;
+	struct mbuf *m;
+
+	KASSERT((unit->hci_flags & BTF_XMIT) == 0);
+	KASSERT(sc->sc_txp == NULL);
+
+	if (MBUFQ_FIRST(&unit->hci_cmdq)) {
+		MBUFQ_DEQUEUE(&unit->hci_cmdq, m);
+		unit->hci_stats.cmd_tx++;
+		M_SETCTX(m, NULL);
+		goto start;
+	}
+
+	if (MBUFQ_FIRST(&unit->hci_scotxq)) {
+		MBUFQ_DEQUEUE(&unit->hci_scotxq, m);
+		unit->hci_stats.sco_tx++;
+		goto start;
+	}
+
+	if (MBUFQ_FIRST(&unit->hci_acltxq)) {
+		MBUFQ_DEQUEUE(&unit->hci_acltxq, m);
+		unit->hci_stats.acl_tx++;
+		M_SETCTX(m, NULL);
+		goto start;
+	}
+
+	/* Nothing to send */
+	return;
+
+start:
+	sc->sc_txp = m;
+	unit->hci_flags |= BTF_XMIT;
+	bth4start(sc->sc_tp);
+}
--- sys/dev/bluetooth/btuartvar.h.orig	1970-01-01 09:00:00.000000000 +0900
+++ sys/dev/bluetooth/btuartvar.h	2006-12-15 19:33:44.000000000 +0900
@@ -0,0 +1,42 @@
+/*	$NetBSD$	*/
+/*
+ * Copyright (c) 2006 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.
+ *
+ */
+
+#define BTUART_HCITYPE		_IOW ('H', 1, uint32_t)
+#define BTUART_HCITYPE_ANY		0
+#define BTUART_HCITYPE_ERICSSON		1
+#define BTUART_HCITYPE_DIGI		2
+#define BTUART_HCITYPE_TEXAS		3
+#define BTUART_HCITYPE_CSR		4
+#define BTUART_HCITYPE_SWAVE		5
+#define BTUART_HCITYPE_ST		6
+#define BTUART_HCITYPE_STLC2500		7
+#define BTUART_HCITYPE_BT2000C		8
+#define BTUART_HCITYPE_BCM2035		9
+
+#define BTUART_INITSPEED	_IOW ('H', 2, uint32_t)
+#define BTUART_START		_IO  ('H', 3)

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

#include <sys/ioctl.h>

#include <bluetooth.h>
#include <err.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include <netbt/hci.h>

#if 1
#define BTUART_HCITYPE		_IOW('H', 1, uint32_t)
#define BTUART_HCITYPE_ANY		0
#define BTUART_HCITYPE_ERICSSON		1
#define BTUART_HCITYPE_DIGI		2
#define BTUART_HCITYPE_TEXAS		3
#define BTUART_HCITYPE_CSR		4
#define BTUART_HCITYPE_BBOXES		5
#define BTUART_HCITYPE_SWAVE		6
#define BTUART_HCITYPE_ST		7
#define BTUART_HCITYPE_STLC2500		8
#define BTUART_HCITYPE_BT2000C		9
#define BTUART_HCITYPE_BCM2035		10

#define BTUART_INITSPEED	_IOW('H', 2, uint32_t)
#define BTUART_START		_IO('H', 3)
#endif

static void usage(void);
static int btuartd(int, char *, int, int, int);


static struct hcitypetbl {
	char *hciname;
	int hcitype;
} hcitypetbl[] = {
	{ "ericsson",		BTUART_HCITYPE_ERICSSON },
	{ "digi",		BTUART_HCITYPE_DIGI },
	{ "texas",		BTUART_HCITYPE_TEXAS },
	{ "csr",		BTUART_HCITYPE_CSR },
	{ "bboxes",		BTUART_HCITYPE_BBOXES },
	{ "swave",		BTUART_HCITYPE_SWAVE },
	{ "st",			BTUART_HCITYPE_ST },
	{ "stlc2500",		BTUART_HCITYPE_STLC2500 },
	{ "bt2000c",		BTUART_HCITYPE_BT2000C },
	{ "bcm2035",		BTUART_HCITYPE_BCM2035 },
	{ NULL,			BTUART_HCITYPE_ANY },
};
static struct speedtbl {
	int s;
	int speed;
} speedtbl[] = {
	{      0, B0 },
	{     50, B50 },
	{     75, B75 },
	{    110, B110 },
	{    134, B134 },
	{    150, B150 },
	{    200, B200 },
	{    300, B300 },
	{    600, B600 },
	{   1200, B1200 },
	{   1800, B1800 },
	{   2400, B2400 },
	{   4800, B4800 },
	{   9600, B9600 },
	{  19200, B19200 },
	{  38400, B38400 },
	{   7200, B7200 },
	{  14400, B14400 },
	{  28800, B28800 },
	{  57600, B57600 },
	{  76800, B76800 },
	{ 115200, B115200 },
	{ 230400, B230400 },
	{ 460800, B460800 },
	{ 921600, B921600 },
	{     -1, B57600 },
};


static void
usage()
{

	printf("usage: %s [-f] [-i init_speed] "
	    "type comdev speed\n", getprogname());
	printf("    type  : \n");
	printf("    comdev: com device. e.g. /dev/dty03\n");
	printf("    speed : baud rate. e.g. 921600\n");
	exit(EXIT_SUCCESS);
}

static int
btuartd(int type, char *comdev, int speed, int flow, int init_speed)
{
	struct termios t;
	int comfd, disc;

	if ((comfd = open(comdev, O_RDWR | O_NOCTTY)) == -1)
		err(EXIT_FAILURE, "open failed: ");

	tcflush(comfd, TCIOFLUSH);
	if (tcgetattr(comfd, &t) == -1)
		err(EXIT_FAILURE, "tcgetattr failed: ");
	cfmakeraw(&t);
	t.c_cflag |= CLOCAL;
	if (flow)
		t.c_cflag |= CRTSCTS;

	tcflush(comfd, TCIOFLUSH);
	if (cfsetspeed(&t, speed) == -1)
		err(EXIT_FAILURE, "cfsetspeed failed: ");
	if (tcsetattr(comfd, TCSANOW, &t) == -1)
		err(EXIT_FAILURE, "tcsetattr failed: ");

	disc = BTH4DISC;
	if (ioctl(comfd, TIOCSETD, &disc) < 0)
		err(EXIT_FAILURE, "ioctl TIOCSETD failed: ");

	if (init_speed != -1)
		if (ioctl(comfd, BTUART_INITSPEED, &init_speed) < 0)
			err(EXIT_FAILURE, "ioctl BTUART_INITSPEED failed: ");
	if (ioctl(comfd, BTUART_HCITYPE, &type) < 0)
		err(EXIT_FAILURE, "ioctl BTUART_HCITYPE failed: ");
	if (ioctl(comfd, BTUART_START) < 0)
		err(EXIT_FAILURE, "ioctl BTUART_START failed: ");
	while (1);

	disc = TTYDISC;
	if (ioctl(comfd, TIOCSETD, &disc) < 0)
		err(EXIT_FAILURE, "ioctl TIOCSETD failed: ");

	if (close(comfd) == -1)
		err(EXIT_FAILURE, "close failed: ");

	return 0;
}

int
main(int argc, char *argv[])
{
	extern char *optarg;
	extern int optind;
	int type, speed, init_speed = -1, flow = 0, ch, i;
	char *comdev;

	while ((ch = getopt(argc, argv, "fi:")) != -1) {
		switch (ch) {
		case 'f':
			flow = 1;
			break;

		case 'i':
			for (i = 0; speedtbl[i].speed != -1; i++)
				if (speedtbl[i].s == atoi(optarg))
					break;
			init_speed = atoi(optarg);
			break;

		case '?':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if (argc != 3)
		usage();

	for (i = 0; hcitypetbl[i].hciname != NULL; i++)
		if (!strncmp(hcitypetbl[i].hciname, argv[0], strlen(argv[0])))
			break;
	type = hcitypetbl[i].hcitype;
	comdev = argv[1];
	for (i = 0; speedtbl[i].speed != -1; i++)
		if (speedtbl[i].s == atoi(argv[2]))
			break;
	speed = speedtbl[i].speed;

	if (btuartd(type, comdev, speed, flow, init_speed) != 0)
		exit(EXIT_FAILURE);
	exit(EXIT_SUCCESS);
}

----Next_Part(Tue_Jan__9_14_11_31_2007_760)----