1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <errno.h> 29 30 #include <bluetooth/bluetooth.h> 31 #include <bluetooth/hci.h> 32 #include <bluetooth/sdp.h> 33 #include <bluetooth/sdp_lib.h> 34 35 #include <gdbus.h> 36 37 #include "log.h" 38 #include "../src/adapter.h" 39 #include "../src/device.h" 40 41 #include "device.h" 42 #include "server.h" 43 #include "manager.h" 44 45 static int idle_timeout = 0; 46 47 static DBusConnection *connection = NULL; 48 static GSList *adapters = NULL; 49 50 static void input_remove(struct btd_device *device, const char *uuid) 51 { 52 const gchar *path = device_get_path(device); 53 54 DBG("path %s", path); 55 56 input_device_unregister(path, uuid); 57 } 58 59 static int hid_device_probe(struct btd_device *device, GSList *uuids) 60 { 61 struct btd_adapter *adapter = device_get_adapter(device); 62 const gchar *path = device_get_path(device); 63 const sdp_record_t *rec = btd_device_get_record(device, uuids->data); 64 bdaddr_t src, dst; 65 66 DBG("path %s", path); 67 68 if (!rec) 69 return -1; 70 71 adapter_get_address(adapter, &src); 72 device_get_address(device, &dst); 73 74 return input_device_register(connection, device, path, &src, &dst, 75 HID_UUID, rec->handle, idle_timeout * 60); 76 } 77 78 static void hid_device_remove(struct btd_device *device) 79 { 80 input_remove(device, HID_UUID); 81 } 82 83 static int headset_probe(struct btd_device *device, GSList *uuids) 84 { 85 struct btd_adapter *adapter = device_get_adapter(device); 86 const gchar *path = device_get_path(device); 87 const sdp_record_t *record; 88 sdp_list_t *protos; 89 uint8_t ch; 90 bdaddr_t src, dst; 91 92 DBG("path %s", path); 93 94 if (!g_slist_find_custom(uuids, HSP_HS_UUID, 95 (GCompareFunc) strcasecmp)) 96 return -EINVAL; 97 98 record = btd_device_get_record(device, uuids->data); 99 100 if (!record || sdp_get_access_protos(record, &protos) < 0) { 101 error("Invalid record"); 102 return -EINVAL; 103 } 104 105 ch = sdp_get_proto_port(protos, RFCOMM_UUID); 106 sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); 107 sdp_list_free(protos, NULL); 108 109 if (ch <= 0) { 110 error("Invalid RFCOMM channel"); 111 return -EINVAL; 112 } 113 114 adapter_get_address(adapter, &src); 115 device_get_address(device, &dst); 116 117 return fake_input_register(connection, device, path, &src, &dst, 118 HSP_HS_UUID, ch); 119 } 120 121 static void headset_remove(struct btd_device *device) 122 { 123 input_remove(device, HSP_HS_UUID); 124 } 125 126 static int hid_server_probe(struct btd_adapter *adapter) 127 { 128 bdaddr_t src; 129 int ret; 130 131 adapter_get_address(adapter, &src); 132 133 ret = server_start(&src); 134 if (ret < 0) 135 return ret; 136 137 adapters = g_slist_append(adapters, btd_adapter_ref(adapter)); 138 139 return 0; 140 } 141 142 static void hid_server_remove(struct btd_adapter *adapter) 143 { 144 bdaddr_t src; 145 146 adapter_get_address(adapter, &src); 147 148 server_stop(&src); 149 150 adapters = g_slist_remove(adapters, adapter); 151 btd_adapter_unref(adapter); 152 } 153 154 static struct btd_device_driver input_hid_driver = { 155 .name = "input-hid", 156 .uuids = BTD_UUIDS(HID_UUID), 157 .probe = hid_device_probe, 158 .remove = hid_device_remove, 159 }; 160 161 static struct btd_device_driver input_headset_driver = { 162 .name = "input-headset", 163 .uuids = BTD_UUIDS(HSP_HS_UUID), 164 .probe = headset_probe, 165 .remove = headset_remove, 166 }; 167 168 static struct btd_adapter_driver input_server_driver = { 169 .name = "input-server", 170 .probe = hid_server_probe, 171 .remove = hid_server_remove, 172 }; 173 174 int input_manager_init(DBusConnection *conn, GKeyFile *config) 175 { 176 GError *err = NULL; 177 178 if (config) { 179 idle_timeout = g_key_file_get_integer(config, "General", 180 "IdleTimeout", &err); 181 if (err) { 182 DBG("input.conf: %s", err->message); 183 g_error_free(err); 184 } 185 } 186 187 connection = dbus_connection_ref(conn); 188 189 btd_register_adapter_driver(&input_server_driver); 190 191 btd_register_device_driver(&input_hid_driver); 192 btd_register_device_driver(&input_headset_driver); 193 194 return 0; 195 } 196 197 void input_manager_exit(void) 198 { 199 btd_unregister_device_driver(&input_hid_driver); 200 btd_unregister_device_driver(&input_headset_driver); 201 202 btd_unregister_adapter_driver(&input_server_driver); 203 204 dbus_connection_unref(connection); 205 206 connection = NULL; 207 } 208