From owner-svn-src-all@FreeBSD.ORG Wed Mar 18 21:43:16 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BC9FB106566B; Wed, 18 Mar 2009 21:43:16 +0000 (UTC) (envelope-from emax@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A9A058FC13; Wed, 18 Mar 2009 21:43:16 +0000 (UTC) (envelope-from emax@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n2ILhGGn038405; Wed, 18 Mar 2009 21:43:16 GMT (envelope-from emax@svn.freebsd.org) Received: (from emax@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n2ILhGwW038397; Wed, 18 Mar 2009 21:43:16 GMT (envelope-from emax@svn.freebsd.org) Message-Id: <200903182143.n2ILhGwW038397@svn.freebsd.org> From: Maksim Yevmenkin Date: Wed, 18 Mar 2009 21:43:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r189989 - stable/7/lib/libbluetooth X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 18 Mar 2009 21:43:17 -0000 Author: emax Date: Wed Mar 18 21:43:16 2009 New Revision: 189989 URL: http://svn.freebsd.org/changeset/base/189989 Log: MFC r189462 MFC is ahead of schedule due to request. Add Bluetooth compatibility shims. Inspired by Linux BlueZ and NetBSD. Discussed with: Iain Hibbert plunky -at- rya-online -dot- net of NetBSD Requested by: Bruce Simpson bms -at- incunabulum -dot- net Tested by: Bruce Simpson bms -at- incunabulum -dot- net Added: stable/7/lib/libbluetooth/dev.c - copied unchanged from r189462, head/lib/libbluetooth/dev.c stable/7/lib/libbluetooth/hci.c - copied unchanged from r189462, head/lib/libbluetooth/hci.c Modified: stable/7/lib/libbluetooth/ (props changed) stable/7/lib/libbluetooth/Makefile stable/7/lib/libbluetooth/bluetooth.3 stable/7/lib/libbluetooth/bluetooth.c stable/7/lib/libbluetooth/bluetooth.h Modified: stable/7/lib/libbluetooth/Makefile ============================================================================== --- stable/7/lib/libbluetooth/Makefile Wed Mar 18 21:33:53 2009 (r189988) +++ stable/7/lib/libbluetooth/Makefile Wed Mar 18 21:43:16 2009 (r189989) @@ -9,7 +9,7 @@ CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../.. SHLIB_MAJOR= 3 -SRCS= bluetooth.c +SRCS= bluetooth.c dev.c hci.c INCS= bluetooth.h MLINKS+= bluetooth.3 bt_gethostbyname.3 @@ -27,6 +27,12 @@ MLINKS+= bluetooth.3 bt_endprotoent.3 MLINKS+= bluetooth.3 bt_ntoa.3 MLINKS+= bluetooth.3 bt_aton.3 +MLINKS+= bluetooth.3 bt_devaddr.3 +MLINKS+= bluetooth.3 bt_devname.3 + +MLINKS+= bluetooth.3 bt_devinfo.3 +MLINKS+= bluetooth.3 bt_devenum.3 + MLINKS+= bluetooth.3 bdaddr_same.3 MLINKS+= bluetooth.3 bdaddr_any.3 MLINKS+= bluetooth.3 bdaddr_copy.3 Modified: stable/7/lib/libbluetooth/bluetooth.3 ============================================================================== --- stable/7/lib/libbluetooth/bluetooth.3 Wed Mar 18 21:33:53 2009 (r189988) +++ stable/7/lib/libbluetooth/bluetooth.3 Wed Mar 18 21:43:16 2009 (r189989) @@ -1,4 +1,4 @@ -.\" Copyright (c) 2003 Maksim Yevmenkin +.\" Copyright (c) 2003-2009 Maksim Yevmenkin .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ .\" $Id: bluetooth.3,v 1.5 2003/05/20 23:04:30 max Exp $ .\" $FreeBSD$ .\" -.Dd August 13, 2008 +.Dd February 13, 2009 .Dt BLUETOOTH 3 .Os .Sh NAME @@ -74,6 +74,16 @@ .Ft const char * .Fn bt_ntoa "const bdaddr_t *ba" "char *str" .Ft int +.Fn bt_devaddr "const char *devname" "bdaddr_t *addr" +.Ft int +.Fn bt_devname "char *devname" "const bdaddr_t *addr" +.Ft int +.Fn (bt_devenum_cb_t) "int s" "struct bt_devinfo const *di" "void *arg" +.Ft int +.Fn bt_devinfo "struct bt_devinfo *di" +.Ft int +.Fn bt_devenum "bt_devenum_cb_t *cb" "void *arg" +.Ft int .Fn bdaddr_same "const bdaddr_t *a" "const bdaddr_t *b" .Ft int .Fn bdaddr_any "const bdaddr_t *a" @@ -197,6 +207,110 @@ It is up to the caller to ensure that pr If no buffer was provided then internal static buffer will be used. .Pp The +.Fn bt_devaddr +function interprets the specified +.Fa devname +string as the address or device name of a Bluetooth device on the local system, +and places the device address in the provided +.Fa bdaddr , +if any. +The function returns 1 if the string was successfully interpreted, +or 0 if the string did not match any local device. +The +.Fn bt_devname +function takes a Bluetooth device address and copies the local device +name associated with that address into the buffer provided, +if any. +Caller must ensure that provided buffer is at least +.Dv HCI_DEVNAME_SIZE +characters in size. +The function returns 1 when the device was found, +otherwise 0. +.Pp +The +.Fn bt_devinfo +function populates prodivded +.Vt bt_devinfo +structure with the information about given Bluetooth device. +The caller is expected to pass Bluetooth device name in the +.Fa devname +field of the passed +.Vt bt_devinfo +structure. +The function returns 0 when successful, +otherwise -1. +The +.Vt bt_devinfo +structure is defined as follows +.Bd -literal -offset indent +struct bt_devinfo +{ + char devname[HCI_DEVNAME_SIZE]; + + uint32_t state; + + bdaddr_t bdaddr; + uint16_t _reserved0; + + uint8_t features[HCI_DEVFEATURES_SIZE]; + + /* buffer info */ + uint16_t _reserved1; + uint16_t cmd_free; + uint16_t sco_size; + uint16_t sco_pkts; + uint16_t sco_free; + uint16_t acl_size; + uint16_t acl_pkts; + uint16_t acl_free; + + /* stats */ + uint32_t cmd_sent; + uint32_t evnt_recv; + uint32_t acl_recv; + uint32_t acl_sent; + uint32_t sco_recv; + uint32_t sco_sent; + uint32_t bytes_recv; + uint32_t bytes_sent; + + /* misc/specific */ + uint16_t link_policy_info; + uint16_t packet_type_info; + uint16_t role_switch_info; + uint16_t debug; + + uint8_t _padding[20]; +}; +.Ed +.Pp +The +.Fn bt_devenum +function enumerates Bluetooth devices present in the system. +For every device found, +the function will call provided +.Fa cb +callback function which should be of +.Vt bt_devenum_cb_t +type. +The callback function is passed a +.Dv HCI +socket +.Fa s , +fully populated +.Vt bt_devinfo +structure +.Fa di +and +.Fa arg +argument provided to the +.Fn bt_devenum . +The callback function can stop enumeration by returning a value +that is greater than zero. +The function returns number of successfully enumerated devices, +or -1 if an error occurred. +.Pp +The .Fn bdaddr_same , .Fn bdaddr_any and @@ -287,7 +401,8 @@ on EOF or error. .Xr getprotobynumber 3 , .Xr herror 3 , .Xr inet_aton 3 , -.Xr inet_ntoa 3 +.Xr inet_ntoa 3 , +.Xr ng_hci 4 .Sh CAVEAT The .Fn bt_gethostent @@ -312,6 +427,20 @@ The function opens and/or rewinds the .Pa /etc/bluetooth/protocols file. +.Pp +The +.Fn bt_devenum +function enumerates up to +.Dv HCI_DEVMAX +Bluetooth devices. +During enumeration the +.Fn bt_devenum +function uses the same +.Dv HCI +socket. +The function guarantees that the socket, +passed to the callback function, +will be bound and connected to the Bluetooth device being enumerated. .Sh AUTHORS .An Maksim Yevmenkin Aq m_evmenkin@yahoo.com .Sh BUGS Modified: stable/7/lib/libbluetooth/bluetooth.c ============================================================================== --- stable/7/lib/libbluetooth/bluetooth.c Wed Mar 18 21:33:53 2009 (r189988) +++ stable/7/lib/libbluetooth/bluetooth.c Wed Mar 18 21:43:16 2009 (r189989) @@ -1,7 +1,9 @@ /* * bluetooth.c - * - * Copyright (c) 2001-2003 Maksim Yevmenkin + */ + +/*- + * Copyright (c) 2001-2009 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without Modified: stable/7/lib/libbluetooth/bluetooth.h ============================================================================== --- stable/7/lib/libbluetooth/bluetooth.h Wed Mar 18 21:33:53 2009 (r189988) +++ stable/7/lib/libbluetooth/bluetooth.h Wed Mar 18 21:43:16 2009 (r189989) @@ -1,7 +1,9 @@ /* * bluetooth.h - * - * Copyright (c) 2001-2003 Maksim Yevmenkin + */ + +/*- + * Copyright (c) 2001-2009 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,9 +37,12 @@ #include #include #include +#include #include #include +#include #include +#include #include #include #include @@ -72,6 +77,63 @@ void bt_endprotoent (v char const * bt_ntoa (bdaddr_t const *ba, char *str); int bt_aton (char const *str, bdaddr_t *ba); +/* bt_devXXXX() functions (inspired by NetBSD) */ +int bt_devaddr (char const *devname, bdaddr_t *addr); +int bt_devname (char *devname, bdaddr_t const *addr); + +/* + * Bluetooth HCI functions + */ + +#define HCI_DEVMAX 32 /* arbitrary */ +#define HCI_DEVNAME_SIZE NG_NODESIZ +#define HCI_DEVFEATURES_SIZE NG_HCI_FEATURES_SIZE + +struct bt_devinfo +{ + char devname[HCI_DEVNAME_SIZE]; + + uint32_t state; /* device/implementation specific */ + + bdaddr_t bdaddr; + uint16_t _reserved0; + + uint8_t features[HCI_DEVFEATURES_SIZE]; + + /* buffer info */ + uint16_t _reserved1; + uint16_t cmd_free; + uint16_t sco_size; + uint16_t sco_pkts; + uint16_t sco_free; + uint16_t acl_size; + uint16_t acl_pkts; + uint16_t acl_free; + + /* stats */ + uint32_t cmd_sent; + uint32_t evnt_recv; + uint32_t acl_recv; + uint32_t acl_sent; + uint32_t sco_recv; + uint32_t sco_sent; + uint32_t bytes_recv; + uint32_t bytes_sent; + + /* misc/specific */ + uint16_t link_policy_info; + uint16_t packet_type_info; + uint16_t role_switch_info; + uint16_t debug; + + uint8_t _padding[20]; /* leave space for future additions */ +}; + +typedef int (bt_devenum_cb_t)(int, struct bt_devinfo const *, void *); + +int bt_devinfo (struct bt_devinfo *di); +int bt_devenum (bt_devenum_cb_t *cb, void *arg); + /* * bdaddr utility functions (from NetBSD) */ Copied: stable/7/lib/libbluetooth/dev.c (from r189462, head/lib/libbluetooth/dev.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/7/lib/libbluetooth/dev.c Wed Mar 18 21:43:16 2009 (r189989, copy of r189462, head/lib/libbluetooth/dev.c) @@ -0,0 +1,95 @@ +/* + * dev.c + */ + +/*- + * Copyright (c) 2009 Maksim Yevmenkin + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include +#include +#include + +struct bt_devaddr_match_arg +{ + char devname[HCI_DEVNAME_SIZE]; + bdaddr_t const *bdaddr; +}; + +static bt_devenum_cb_t bt_devaddr_match; + +int +bt_devaddr(char const *devname, bdaddr_t *addr) +{ + struct bt_devinfo di; + + strlcpy(di.devname, devname, sizeof(di.devname)); + + if (bt_devinfo(&di) < 0) + return (0); + + if (addr != NULL) + bdaddr_copy(addr, &di.bdaddr); + + return (1); +} + +int +bt_devname(char *devname, bdaddr_t const *addr) +{ + struct bt_devaddr_match_arg arg; + + memset(&arg, 0, sizeof(arg)); + arg.bdaddr = addr; + + if (bt_devenum(&bt_devaddr_match, &arg) < 0) + return (0); + + if (arg.devname[0] == '\0') { + errno = ENXIO; + return (0); + } + + if (devname != NULL) + strlcpy(devname, arg.devname, HCI_DEVNAME_SIZE); + + return (1); +} + +static int +bt_devaddr_match(int s, struct bt_devinfo const *di, void *arg) +{ + struct bt_devaddr_match_arg *m = (struct bt_devaddr_match_arg *)arg; + + if (!bdaddr_same(&di->bdaddr, m->bdaddr)) + return (0); + + strlcpy(m->devname, di->devname, sizeof(m->devname)); + + return (1); +} + Copied: stable/7/lib/libbluetooth/hci.c (from r189462, head/lib/libbluetooth/hci.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/7/lib/libbluetooth/hci.c Wed Mar 18 21:43:16 2009 (r189989, copy of r189462, head/lib/libbluetooth/hci.c) @@ -0,0 +1,246 @@ +/* + * hci.c + */ + +/*- + * Copyright (c) 2009 Maksim Yevmenkin + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include + +static char * bt_dev2node (char const *devname, char *nodename, int nnlen); + +int +bt_devinfo(struct bt_devinfo *di) +{ + union { + struct ng_btsocket_hci_raw_node_state r0; + struct ng_btsocket_hci_raw_node_bdaddr r1; + struct ng_btsocket_hci_raw_node_features r2; + struct ng_btsocket_hci_raw_node_buffer r3; + struct ng_btsocket_hci_raw_node_stat r4; + struct ng_btsocket_hci_raw_node_link_policy_mask r5; + struct ng_btsocket_hci_raw_node_packet_mask r6; + struct ng_btsocket_hci_raw_node_role_switch r7; + struct ng_btsocket_hci_raw_node_debug r8; + } rp; + struct sockaddr_hci ha; + int s, rval; + + if (di == NULL) { + errno = EINVAL; + return (-1); + } + + memset(&ha, 0, sizeof(ha)); + ha.hci_len = sizeof(ha); + ha.hci_family = AF_BLUETOOTH; + + if (bt_aton(di->devname, &rp.r1.bdaddr)) { + if (!bt_devname(ha.hci_node, &rp.r1.bdaddr)) + return (-1); + } else if (bt_dev2node(di->devname, ha.hci_node, + sizeof(ha.hci_node)) == NULL) { + errno = ENXIO; + return (-1); + } + + s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); + if (s < 0) + return (-1); + + rval = -1; + + if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || + connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) + goto bad; + strlcpy(di->devname, ha.hci_node, sizeof(di->devname)); + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &rp.r0, sizeof(rp.r0)) < 0) + goto bad; + di->state = rp.r0.state; + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &rp.r1, sizeof(rp.r1)) < 0) + goto bad; + bdaddr_copy(&di->bdaddr, &rp.r1.bdaddr); + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &rp.r2, sizeof(rp.r2)) < 0) + goto bad; + memcpy(di->features, rp.r2.features, sizeof(di->features)); + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &rp.r3, sizeof(rp.r3)) < 0) + goto bad; + di->cmd_free = rp.r3.buffer.cmd_free; + di->sco_size = rp.r3.buffer.sco_size; + di->sco_pkts = rp.r3.buffer.sco_pkts; + di->sco_free = rp.r3.buffer.sco_free; + di->acl_size = rp.r3.buffer.acl_size; + di->acl_pkts = rp.r3.buffer.acl_pkts; + di->acl_free = rp.r3.buffer.acl_free; + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &rp.r4, sizeof(rp.r4)) < 0) + goto bad; + di->cmd_sent = rp.r4.stat.cmd_sent; + di->evnt_recv = rp.r4.stat.evnt_recv; + di->acl_recv = rp.r4.stat.acl_recv; + di->acl_sent = rp.r4.stat.acl_sent; + di->sco_recv = rp.r4.stat.sco_recv; + di->sco_sent = rp.r4.stat.sco_sent; + di->bytes_recv = rp.r4.stat.bytes_recv; + di->bytes_sent = rp.r4.stat.bytes_sent; + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, + &rp.r5, sizeof(rp.r5)) < 0) + goto bad; + di->link_policy_info = rp.r5.policy_mask; + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, + &rp.r6, sizeof(rp.r6)) < 0) + goto bad; + di->packet_type_info = rp.r6.packet_mask; + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, + &rp.r7, sizeof(rp.r7)) < 0) + goto bad; + di->role_switch_info = rp.r7.role_switch; + + if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &rp.r8, sizeof(rp.r8)) < 0) + goto bad; + di->debug = rp.r8.debug; + + rval = 0; +bad: + close(s); + + return (rval); +} + +int +bt_devenum(bt_devenum_cb_t cb, void *arg) +{ + struct ng_btsocket_hci_raw_node_list_names rp; + struct bt_devinfo di; + struct sockaddr_hci ha; + int s, i, count; + + rp.num_names = HCI_DEVMAX; + rp.names = (struct nodeinfo *) calloc(rp.num_names, + sizeof(struct nodeinfo)); + if (rp.names == NULL) { + errno = ENOMEM; + return (-1); + } + + memset(&ha, 0, sizeof(ha)); + ha.hci_len = sizeof(ha); + ha.hci_family = AF_BLUETOOTH; + ha.hci_node[0] = 'x'; + + s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); + if (s < 0) { + free(rp.names); + + return (-1); + } + + if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || + connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || + ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &rp, sizeof(rp)) < 0) { + close(s); + free(rp.names); + + return (-1); + } + + for (count = 0, i = 0; i < rp.num_names; i ++) { + strlcpy(di.devname, rp.names[i].name, sizeof(di.devname)); + if (bt_devinfo(&di) < 0) + continue; + + count ++; + + if (cb == NULL) + continue; + + strlcpy(ha.hci_node, rp.names[i].name, sizeof(ha.hci_node)); + if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || + connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) + continue; + + if ((*cb)(s, &di, arg) > 0) + break; + } + + close (s); + free(rp.names); + + return (count); +} + +static char * +bt_dev2node(char const *devname, char *nodename, int nnlen) +{ + static char const * bt_dev_prefix[] = { + "btccc", /* 3Com Bluetooth PC-CARD */ + "h4", /* UART/serial Bluetooth devices */ + "ubt", /* Bluetooth USB devices */ + NULL /* should be last */ + }; + + static char _nodename[HCI_DEVNAME_SIZE]; + char const **p; + char *ep; + int plen, unit; + + if (nodename == NULL) { + nodename = _nodename; + nnlen = HCI_DEVNAME_SIZE; + } + + for (p = bt_dev_prefix; *p != NULL; p ++) { + plen = strlen(*p); + if (strncmp(devname, *p, plen) != 0) + continue; + + unit = strtoul(devname + plen, &ep, 10); + if (*ep != '\0' && + strcmp(ep, "hci") != 0 && + strcmp(ep, "l2cap") != 0) + return (NULL); /* can't make sense of device name */ + + snprintf(nodename, nnlen, "%s%uhci", *p, unit); + + return (nodename); + } + + return (NULL); +} +