diff --git a/Makefile.am b/Makefile.am index 935a422c66e3ce44fe17ccdcc7a88b2d4fa35e48..e9e304498052ce3314fc01aa02bddc59615a55c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,10 +2,12 @@ bin_PROGRAMS = gbridge gbridge_CFLAGS = -Wall -Werror -I${GBDIR} gbridge_CFLAGS += `pkg-config --cflags libnl-3.0 libnl-genl-3.0` +gbridge_CFLAGS += `pkg-config --cflags bluez` gbridge_SOURCES = main.c \ netlink.c \ debug.c \ greybus.c \ svc.c \ - controller.c \ No newline at end of file + controller.c \ + bluetooth.c \ No newline at end of file diff --git a/bluetooth.c b/bluetooth.c new file mode 100644 index 0000000000000000000000000000000000000000..1c1f22682b4a719ba91d55774a2eefb8e8780b19 --- /dev/null +++ b/bluetooth.c @@ -0,0 +1,256 @@ +/* + * GBridge (Greybus Bridge) + * Copyright (c) 2016 Alexandre Bailon + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <bluetooth/rfcomm.h> + +#include <debug.h> +#include <gbridge.h> +#include <controller.h> + +#define BDADDR_SIZE 19 +#define BDNAME_SIZE 248 + +struct bluetooth_device { + char name[BDNAME_SIZE]; + char addr[BDADDR_SIZE]; + struct btd_device *device; + int sock; +}; + +struct bluetooth_controller { + int dev_id; + int sock; +}; + +static int bluetooth_is_connected(struct controller *ctrl, bdaddr_t *bdaddr) +{ + char addr[BDADDR_SIZE]; + struct interface *intf; + struct bluetooth_device *bd; + + ba2str(bdaddr, addr); + TAILQ_FOREACH(intf, &ctrl->interfaces, node) { + bd = intf->priv; + if (strcmp(addr, bd->addr) == 0) { + return 1; + } + } + + return 0; +} + +static int bluetooth_connect(struct controller *ctrl, bdaddr_t *bdaddr) +{ + int ret; + struct bluetooth_device *bd; + struct interface *intf; + struct sockaddr_rc addr; + struct bluetooth_controller *bt_ctrl = ctrl->priv; + + bd = malloc(sizeof(*bd)); + if (!bd) + return -ENOMEM; + + ba2str(bdaddr, bd->addr); + memset(bd->name, 0, sizeof(bd->name)); + ret = hci_read_remote_name(bt_ctrl->sock, bdaddr, + sizeof(bd->name), bd->name, + IREQ_CACHE_FLUSH); + if (ret < 0) + goto err_free_bd; + + pr_info("Connecting a new Greybus device\n"); + + bd->sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (bd->sock < 0) { + ret = bd->sock; + goto err_free_bd; + } + + addr.rc_family = AF_BLUETOOTH; + addr.rc_channel = (uint8_t) 1; + str2ba(bd->addr, &addr.rc_bdaddr); + + ret = connect(bd->sock, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) + goto err_close_sock; + + pr_info("Greybus device connected\n"); + + /* FIXME: use real IDs */ + intf = interface_create(ctrl, 1, 1, 0x1234, bd); + if (!intf) + goto err_close_sock; + + ret = interface_hotplug(intf); + if (ret < 0) + goto err_intf_destroy; + + return 0; + + err_intf_destroy: + interface_destroy(intf); + err_close_sock: + close(bd->sock); + err_free_bd: + free(bd); + + return ret; +} + +static void bluetooth_disconnect(struct controller *ctrl, + struct bluetooth_device *bd) +{ + close(bd->sock); + free(bd); +} + +static void bluetooth_interface_destroy(struct interface *intf) +{ + bluetooth_disconnect(intf->ctrl, intf->priv); +} + +static int bluetooth_scan(struct controller *ctrl) +{ + int ret; + inquiry_info *ii = NULL; + int max_rsp, num_rsp; + int len, flags; + int i; + char name[BDNAME_SIZE] = { 0 }; + struct bluetooth_controller *bt_ctrl = ctrl->priv; + + len = 8; + max_rsp = 255; + flags = IREQ_CACHE_FLUSH; + + ii = malloc(max_rsp * sizeof(inquiry_info)); + if (!ii) + return -ENOMEM; + + while (1) { + num_rsp = hci_inquiry(bt_ctrl->dev_id, + len, max_rsp, NULL, &ii, flags); + if (num_rsp < 0) { + perror("hci_inquiry"); + free(ii); + return errno; + } + + for (i = 0; i < num_rsp; i++) { + memset(name, 0, sizeof(name)); + ret = + hci_read_remote_name(bt_ctrl->sock, + &(ii + i)->bdaddr, + sizeof(name), name, 0); + if (ret < 0) + strcpy(name, "[unknown]"); + + if (strstr(name, "GREYBUS")) { + if (!bluetooth_is_connected + (ctrl, &(ii + i)->bdaddr)) { + bluetooth_connect(ctrl, + &(ii + i)->bdaddr); + } + } + } + } + + free(ii); + + return 0; +} + +static int bluetooth_write(struct connection *conn, void *data, size_t len) +{ + struct interface *intf = conn->intf; + struct bluetooth_device *bd = intf->priv; + + cport_pack(data, conn->cport2_id); + return write(bd->sock, data, len); +} + +static int bluetooth_read(struct interface *intf, + uint16_t *cport_id, void *data, size_t len) +{ + int ret; + struct bluetooth_device *bd = intf->priv; + + ret = read_gb_msg(bd->sock, data, len); + if (ret > 0) + *cport_id = cport_unpack(data); + return ret; +} + +static int bluetooth_init(struct controller *ctrl) +{ + int ret; + struct bluetooth_controller *bt_ctrl; + + bt_ctrl = malloc(sizeof(*bt_ctrl)); + if (!bt_ctrl) + return -ENOMEM; + ctrl->priv = bt_ctrl; + + bt_ctrl->dev_id = hci_get_route(NULL); + if (bt_ctrl->dev_id < 0) { + perror("Failed to get device id"); + ret = errno; + goto err_free_bt_ctrl; + } + + bt_ctrl->sock = hci_open_dev(bt_ctrl->dev_id); + if (bt_ctrl->sock < 0) { + perror("Failed to open socket"); + ret = errno; + goto err_free_bt_ctrl; + } + + return 0; + +err_free_bt_ctrl: + free(bt_ctrl); + + return ret; +} + +static void bluetooth_exit(struct controller *ctrl) +{ + struct bluetooth_controller *bt_ctrl = ctrl->priv; + + free(ctrl->priv); + close(bt_ctrl->sock); +} + +struct controller bluetooth_controller = { + .name = "bluetooth", + .init = bluetooth_init, + .exit = bluetooth_exit, + .event_loop = bluetooth_scan, + .write = bluetooth_write, + .intf_read = bluetooth_read, + .interface_destroy = bluetooth_interface_destroy, +}; diff --git a/configure.ac b/configure.ac index 8875569daf27b0a5470c2ca0961abf9c07f7f08a..60d901e53a7d268ece7484742320a405a30e1206 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,7 @@ AC_PROG_INSTALL AC_CHECK_LIB([nl-3], [nl_socket_alloc]) AC_CHECK_LIB([nl-genl-3], [genl_register_family]) AC_CHECK_LIB([pthread], [pthread_create]) +AC_CHECK_LIB([bluetooth], [hci_inquiry]) AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/controller.c b/controller.c index 120184af62295ea56e128cfd2aa2b285c1b01fe9..1454fcacee87cbdc59fd621150ade5a8d5c4c1c4 100644 --- a/controller.c +++ b/controller.c @@ -293,9 +293,14 @@ connection_destroy(uint8_t intf1_id, uint16_t cport1_id, return 0; } +static void register_controller(struct controller *controller) +{ + TAILQ_INSERT_TAIL(&controllers, controller, node); +} + static void register_controllers(void) { - /* TODO Register controllers */ + register_controller(&bluetooth_controller); } static void *controller_loop(void *data) diff --git a/netlink.c b/netlink.c index 51ff4c3ca5870d463c27642473776d4e1273c54e..8091765f7b80c7e0d66851744f44069bff719b4a 100644 --- a/netlink.c +++ b/netlink.c @@ -62,7 +62,9 @@ parse_gb_nl_msg(struct nl_cache_ops *unused, struct genl_cmd *cmd, hdr->type, ret); } } else { - ret = controller_write(hd_cport_id, hdr, gb_operation_msg_size(hdr)); + ret = + controller_write(hd_cport_id, hdr, + gb_operation_msg_size(hdr)); } return 0;