Home | History | Annotate | Download | only in input
      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