summaryrefslogtreecommitdiffstats
path: root/input
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@openbossa.org>2007-03-19 14:58:44 +0000
committerClaudio Takahasi <claudio.takahasi@openbossa.org>2007-03-19 14:58:44 +0000
commitf2c6a6f2debcccfb51d239834c3cf91a2c3a6c40 (patch)
tree2a83d19fc07684f6713dd901f46f04858a78bc3d /input
parent0ac929228aa1eb823f37776e2bbb84855417c66e (diff)
Moving input functions to the right files
Diffstat (limited to 'input')
-rw-r--r--input/device.c1011
-rw-r--r--input/device.h9
-rw-r--r--input/error.c64
-rw-r--r--input/error.h22
-rw-r--r--input/main.c5
-rw-r--r--input/manager.c854
-rw-r--r--input/manager.h4
-rw-r--r--input/storage.c31
-rw-r--r--input/storage.h3
9 files changed, 1029 insertions, 974 deletions
diff --git a/input/device.c b/input/device.c
index fb1e5e5d..8488b406 100644
--- a/input/device.c
+++ b/input/device.c
@@ -34,12 +34,8 @@
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
#include <bluetooth/hidp.h>
#include <glib.h>
@@ -52,12 +48,11 @@
#include "uinput.h"
#include "storage.h"
+#include "error.h"
+#include "manager.h"
#include "device.h"
-#define INPUT_PATH "/org/bluez/input"
-#define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager"
#define INPUT_DEVICE_INTERFACE "org.bluez.input.Device"
-#define INPUT_ERROR_INTERFACE "org.bluez.Error"
#define L2CAP_PSM_HIDP_CTRL 0x11
#define L2CAP_PSM_HIDP_INTR 0x13
@@ -66,12 +61,6 @@
#define UPDOWN_ENABLED 1
-static DBusConnection *connection = NULL;
-
-const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb";
-const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb";
-const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb";
-
struct fake_input {
GIOChannel *io;
int rfcomm; /* RFCOMM socket */
@@ -95,35 +84,22 @@ struct input_device {
struct pending_connect *pending_connect;
};
-struct input_manager {
- bdaddr_t src; /* Local adapter BT address */
- GSList *paths; /* Input registered paths */
-};
-
-struct pending_req {
- char *adapter_path; /* Local adapter D-Bus path */
- bdaddr_t src; /* Local adapter BT address */
- bdaddr_t dst; /* Peer BT address */
- DBusConnection *conn;
- DBusMessage *msg;
- sdp_record_t *pnp_rec;
- sdp_record_t *hid_rec;
-};
-
-static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint32_t cls)
+static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst)
{
struct input_device *idev;
+ uint32_t cls;
idev = g_new0(struct input_device, 1);
bacpy(&idev->src, src);
bacpy(&idev->dst, dst);
+ read_device_name(src, dst, &idev->name);
+ read_device_class(src, dst, &cls);
+
idev->major = (cls >> 8) & 0x1f;
idev->minor = (cls >> 2) & 0x3f;
- read_device_name(src, dst, &idev->name);
-
/* FIXME: hidp could be alloc dynamically */
snprintf(idev->hidp.name, 128, "%s", idev->name);
@@ -157,178 +133,6 @@ static void input_device_free(struct input_device *idev)
g_free(idev);
}
-static struct pending_req *pending_req_new(DBusConnection *conn,
- DBusMessage *msg, const char *adapter_path,
- bdaddr_t *src, bdaddr_t *dst)
-{
- struct pending_req *pr;
- pr = g_try_new0(struct pending_req, 1);
- if (!pr)
- return NULL;
-
- pr->adapter_path = g_strdup(adapter_path);
- bacpy(&pr->src, src);
- bacpy(&pr->dst, dst);
- pr->conn = dbus_connection_ref(conn);
- pr->msg = dbus_message_ref(msg);
-
- return pr;
-}
-
-static void pending_req_free(struct pending_req *pr)
-{
- if (!pr)
- return;
- if (pr->adapter_path)
- g_free(pr->adapter_path);
- if (pr->conn)
- dbus_connection_unref(pr->conn);
- if (pr->msg)
- dbus_message_unref(pr->msg);
- if (pr->pnp_rec)
- sdp_record_free(pr->pnp_rec);
- if (pr->hid_rec)
- sdp_record_free(pr->hid_rec);
- g_free(pr);
-}
-
-/*
- * Common D-Bus BlueZ input error functions
- */
-static DBusHandlerResult err_unknown_device(DBusConnection *conn, DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE ".UnknownDevice",
- "Invalid device"));
-}
-
-static DBusHandlerResult err_unknown_method(DBusConnection *conn, DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE ".UnknownMethod",
- "Unknown input method"));
-}
-
-static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg,
- const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE ".Failed", str));
-}
-
-static DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE ".NotSupported",
- "The service is not supported by the remote device"));
-}
-
-static DBusHandlerResult err_connection_failed(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE".ConnectionAttemptFailed",
- str));
-}
-
-static DBusHandlerResult err_already_exists(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE ".AlreadyExists", str));
-}
-
-static DBusHandlerResult err_does_not_exist(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- INPUT_ERROR_INTERFACE ".DoesNotExist", str));
-}
-
-static DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg,
- const char *name, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg, name, str));
-
-}
-
-static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
-{
- sdp_data_t *pdlist, *pdlist2;
- uint8_t attr_val;
-
- pdlist = sdp_data_get(rec, 0x0101);
- pdlist2 = sdp_data_get(rec, 0x0102);
- if (pdlist) {
- if (pdlist2) {
- if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
- strncpy(req->name, pdlist2->val.str, 127);
- strcat(req->name, " ");
- }
- strncat(req->name, pdlist->val.str, 127 - strlen(req->name));
- } else
- strncpy(req->name, pdlist->val.str, 127);
- } else {
- pdlist2 = sdp_data_get(rec, 0x0100);
- if (pdlist2)
- strncpy(req->name, pdlist2->val.str, 127);
- }
-
- pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
- req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
-
- pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
- req->subclass = pdlist ? pdlist->val.uint8 : 0;
-
- pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
- req->country = pdlist ? pdlist->val.uint8 : 0;
-
- pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
- attr_val = pdlist ? pdlist->val.uint8 : 0;
- if (attr_val)
- req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
-
- pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
- attr_val = pdlist ? pdlist->val.uint8 : 0;
- if (attr_val)
- req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
-
- pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
- if (pdlist) {
- pdlist = pdlist->val.dataseq;
- pdlist = pdlist->val.dataseq;
- pdlist = pdlist->next;
-
- req->rd_data = g_try_malloc0(pdlist->unitSize);
- if (req->rd_data) {
- memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize);
- req->rd_size = pdlist->unitSize;
- }
- }
-}
-
-static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req)
-{
- sdp_data_t *pdlist;
-
- pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
- req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;
-
- pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
- req->product = pdlist ? pdlist->val.uint16 : 0x0000;
-
- pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
- req->version = pdlist ? pdlist->val.uint16 : 0x0000;
-}
-
static int uinput_create(char *name)
{
struct uinput_dev dev;
@@ -615,7 +419,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,
reply = dbus_message_new_method_return(idev->pending_connect->msg);
if (reply) {
- dbus_connection_send(connection, reply, NULL);
+ dbus_connection_send(idev->pending_connect->conn, reply, NULL);
dbus_message_unref(reply);
}
@@ -1199,12 +1003,16 @@ static DBusHandlerResult device_message(DBusConnection *conn,
if (strcmp(member, "SetTimeout") == 0)
return device_set_timeout(conn, msg, data);
- return err_unknown_method(conn, msg);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void device_unregister(DBusConnection *conn, void *data)
{
- input_device_free(data);
+ struct input_device *idev = data;
+
+ /* Disconnect if applied */
+ disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG));
+ input_device_free(idev);
}
/* Virtual table to handle device object path hierarchy */
@@ -1214,819 +1022,98 @@ static const DBusObjectPathVTable device_table = {
};
/*
- * Input Manager methods
+ * Input registration functions
*/
-static void input_manager_free(struct input_manager *mgr)
+int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *hid, const char **path)
{
- if (!mgr)
- return;
+ DBusMessage *msg;
+ struct input_device *idev;
- if (mgr->paths) {
- g_slist_foreach(mgr->paths, (GFunc) free, NULL);
- g_slist_free(mgr->paths);
- }
+ idev = input_device_new(src, dst);
+ *path = create_input_path(idev->major, idev->minor);
- g_free(mgr);
-}
+ memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req));
-static int register_input_device(DBusConnection *conn,
- struct input_device *idev, const char *path)
-{
- DBusMessage *msg;
- struct input_manager *mgr;
+ /* FIXME: rd_data is a pointer - hacking */
if (!dbus_connection_register_object_path(conn,
- path, &device_table, idev)) {
+ *path, &device_table, idev)) {
error("Input device path registration failed");
return -1;
}
- dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr);
- mgr->paths = g_slist_append(mgr->paths, g_strdup(path));
-
msg = dbus_message_new_signal(INPUT_PATH,
INPUT_MANAGER_INTERFACE, "DeviceCreated");
if (!msg)
return -1;
dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &*path,
DBUS_TYPE_INVALID);
send_message_and_unref(conn, msg);
- info("Created input device: %s", path);
+ info("Created input device: %s", *path);
return 0;
}
-static int unregister_input_device(DBusConnection *conn, const char *path)
+int fake_input_register(DBusConnection *conn, bdaddr_t *src,
+ bdaddr_t *dst, uint8_t ch, const char **path)
{
DBusMessage *msg;
+ struct input_device *idev;
- if (!dbus_connection_unregister_object_path(conn, path)) {
- error("Input device path unregister failed");
+ idev = input_device_new(src, dst);
+ *path = create_input_path(idev->major, idev->minor);
+
+ idev->fake = g_new0(struct fake_input, 1);
+ idev->fake->ch = ch;
+
+ if (!dbus_connection_register_object_path(conn,
+ *path, &device_table, idev)) {
+ error("Fake input device path registration failed");
return -1;
}
+ /* FIXME: dupplicated code */
msg = dbus_message_new_signal(INPUT_PATH,
- INPUT_MANAGER_INTERFACE, "DeviceRemoved");
+ INPUT_MANAGER_INTERFACE, "DeviceCreated");
if (!msg)
return -1;
dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &*path,
DBUS_TYPE_INVALID);
send_message_and_unref(conn, msg);
- return 0;
-}
-
-static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr)
-{
- struct input_device *idev;
+ info("Created input device: %s", *path);
- if (!dbus_connection_get_object_path_data(connection, path,
- (void *) &idev))
- return -1;
-
- if (!idev)
- return -1;
+ return 0;
- return bacmp(&idev->dst, bdaddr);
}
-static int get_record(struct pending_req *pr, uint32_t handle,
- DBusPendingCallNotifyFunction cb)
+int input_device_unregister(DBusConnection *conn, const char *path)
{
DBusMessage *msg;
- DBusPendingCall *pending;
- char addr[18];
- const char *paddr = addr;
-
- msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
- "org.bluez.Adapter", "GetRemoteServiceRecord");
- if (!msg)
- return -1;
- ba2str(&pr->dst, addr);
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &paddr,
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_INVALID);
-
- if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
- error("Can't send D-Bus message.");
+ if (!dbus_connection_unregister_object_path(conn, path)) {
+ error("Input device path unregister failed");
return -1;
}
- dbus_pending_call_set_notify(pending, cb, pr, NULL);
- dbus_message_unref(msg);
-
- return 0;
-}
-
-static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls)
-{
- char filename[PATH_MAX + 1], *str;
- char addr[18];
-
- ba2str(src, addr);
- create_name(filename, PATH_MAX, STORAGEDIR, addr, "classes");
-
- ba2str(dst, addr);
- str = textfile_get(filename, addr);
- if (!str)
- return -ENOENT;
-
- if (sscanf(str, "%x", cls) != 1) {
- g_free(str);
- return -ENOENT;
- }
-
- g_free(str);
-
- return 0;
-}
-
-static int get_handles(struct pending_req *pr, const char *uuid,
- DBusPendingCallNotifyFunction cb)
-{
- DBusMessage *msg;
- DBusPendingCall *pending;
- char addr[18];
- const char *paddr = addr;
-
- msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
- "org.bluez.Adapter", "GetRemoteServiceHandles");
+ msg = dbus_message_new_signal(INPUT_PATH,
+ INPUT_MANAGER_INTERFACE, "DeviceRemoved");
if (!msg)
return -1;
- ba2str(&pr->dst, addr);
dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &paddr,
- DBUS_TYPE_STRING, &uuid,
- DBUS_TYPE_INVALID);
-
- if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
- error("Can't send D-Bus message.");
- return -1;
- }
-
- dbus_pending_call_set_notify(pending, cb, pr, NULL);
- dbus_message_unref(msg);
-
- return 0;
-}
-
-static void hid_record_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusMessage *pr_reply;
- struct pending_req *pr = data;
- struct input_device *idev;
- DBusError derr;
- uint8_t *rec_bin;
- const char *path;
- int len, scanned;
- uint32_t cls;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- err_generic(pr->conn, pr->msg, derr.name, derr.message);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (!dbus_message_get_args(reply, &derr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
- DBUS_TYPE_INVALID)) {
- err_not_supported(pr->conn, pr->msg);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (len == 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Invalid HID service record length");
- goto fail;
- }
-
- pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned);
- if (!pr->hid_rec) {
- err_not_supported(pr->conn, pr->msg);
- goto fail;
- }
-
- if (get_class(&pr->src, &pr->dst, &cls) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Device class not available");
- goto fail;
- }
-
- idev = input_device_new(&pr->src, &pr->dst, cls);
-
- extract_hid_record(pr->hid_rec, &idev->hidp);
- if (pr->pnp_rec)
- extract_pnp_record(pr->pnp_rec, &idev->hidp);
-
- path = create_input_path(idev->major, idev->minor);
-
- if (register_input_device(pr->conn, idev, path) < 0) {
- err_failed(pr->conn, pr->msg, "D-Bus path registration failed");
- input_device_free(idev);
- goto fail;
- }
-
- pr_reply = dbus_message_new_method_return(pr->msg);
- dbus_message_append_args(pr_reply,
DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
- send_message_and_unref(pr->conn, pr_reply);
-
- store_device_info(&pr->src, &pr->dst, &idev->hidp);
-fail:
- dbus_error_free(&derr);
- pending_req_free(pr);
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-}
-
-static void hid_handle_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- struct pending_req *pr = data;
- uint32_t *phandle;
- DBusError derr;
- int len;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- err_generic(pr->conn, pr->msg, derr.name, derr.message);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (!dbus_message_get_args(reply, &derr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
- DBUS_TYPE_INVALID)) {
- err_not_supported(pr->conn, pr->msg);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (len == 0) {
- err_not_supported(pr->conn, pr->msg);
- error("HID record handle not found");
- goto fail;
- }
-
- if (get_record(pr, *phandle, hid_record_reply) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("HID service attribute request failed");
- goto fail;
- } else {
- /* Wait record reply */
- goto done;
- }
-fail:
- dbus_error_free(&derr);
- pending_req_free(pr);
-done:
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-}
-
-static void pnp_record_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- struct pending_req *pr = data;
- DBusError derr;
- uint8_t *rec_bin;
- int len, scanned;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- err_generic(pr->conn, pr->msg, derr.name, derr.message);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (!dbus_message_get_args(reply, &derr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
- DBUS_TYPE_INVALID)) {
- err_not_supported(pr->conn, pr->msg);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
- if (len == 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Invalid PnP service record length");
- goto fail;
- }
-
- pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned);
- if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("HID service search request failed");
- goto fail;
- } else {
- /* Wait handle reply */
- goto done;
- }
-
-fail:
- dbus_error_free(&derr);
- pending_req_free(pr);
-done:
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-}
-
-static void pnp_handle_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- struct pending_req *pr = data;
- DBusError derr;
- uint32_t *phandle;
- int len;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- err_generic(pr->conn, pr->msg, derr.name, derr.message);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (!dbus_message_get_args(reply, &derr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
- DBUS_TYPE_INVALID)) {
- err_not_supported(pr->conn, pr->msg);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (len == 0) {
- /* PnP is optional: Ignore it and request the HID handle */
- if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("HID service search request failed");
- goto fail;
- }
- } else {
- /* Request PnP record */
- if (get_record(pr, *phandle, pnp_record_reply) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("PnP service attribute request failed");
- goto fail;
- }
- }
-
- /* Wait HID handle reply or PnP record reply */
- goto done;
-
-fail:
- dbus_error_free(&derr);
- pending_req_free(pr);
-done:
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-}
-
-static void headset_record_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusMessage *pr_reply;
- DBusError derr;
- struct pending_req *pr = data;
- struct input_device *idev;
- uint8_t *rec_bin;
- sdp_record_t *rec;
- sdp_list_t *protos;
- const char *path;
- int len, scanned;
- uint32_t cls;
- uint8_t ch;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- err_generic(pr->conn, pr->msg, derr.name, derr.message);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (!dbus_message_get_args(reply, &derr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
- DBUS_TYPE_INVALID)) {
- err_not_supported(pr->conn, pr->msg);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (len == 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Invalid headset service record length");
- goto fail;
- }
-
- rec = sdp_extract_pdu(rec_bin, &scanned);
- if (!rec) {
- err_not_supported(pr->conn, pr->msg);
- goto fail;
- }
-
- if (sdp_get_access_protos(rec, &protos) < 0) {
- err_not_supported(pr->conn, pr->msg);
- goto fail;
- }
-
- ch = sdp_get_proto_port(protos, RFCOMM_UUID);
- sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, NULL);
- sdp_list_free(protos, NULL);
- sdp_record_free(rec);
-
- if (ch <= 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Invalid RFCOMM channel");
- goto fail;
- }
-
- if (get_class(&pr->src, &pr->dst, &cls) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Device class not available");
- goto fail;
- }
-
- idev = input_device_new(&pr->src, &pr->dst, cls);
-
- idev->fake = g_new0(struct fake_input, 1);
- idev->fake->ch = ch;
-
- /* FIXME: Store the fake input data */
-
- path = create_input_path(idev->major, idev->minor);
- if (register_input_device(pr->conn, idev, path) < 0) {
- error("D-Bus path registration failed:%s", path);
- err_failed(pr->conn, pr->msg, "Path registration failed");
- input_device_free(idev);
- goto fail;
- }
-
- pr_reply = dbus_message_new_method_return(pr->msg);
- dbus_message_append_args(pr_reply,
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- send_message_and_unref(pr->conn, pr_reply);
-fail:
- dbus_error_free(&derr);
- pending_req_free(pr);
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-}
-
-static void headset_handle_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- struct pending_req *pr = data;
- DBusError derr;
- uint32_t *phandle;
- int len;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- err_generic(pr->conn, pr->msg, derr.name, derr.message);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (!dbus_message_get_args(reply, &derr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
- DBUS_TYPE_INVALID)) {
- err_not_supported(pr->conn, pr->msg);
- error("%s: %s", derr.name, derr.message);
- goto fail;
- }
-
- if (len == 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Headset record handle not found");
- goto fail;
- }
-
- if (get_record(pr, *phandle, headset_record_reply) < 0) {
- err_not_supported(pr->conn, pr->msg);
- error("Headset service attribute request failed");
- goto fail;
- } else {
- /* Wait record reply */
- goto done;
- }
-fail:
- dbus_error_free(&derr);
- pending_req_free(pr);
-done:
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-}
-
-static DBusHandlerResult manager_create_device(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct input_manager *mgr = data;
- struct pending_req *pr;
- DBusError derr;
- char adapter[18], adapter_path[32];
- const char *addr;
- GSList *l;
- bdaddr_t dst;
- uint32_t cls = 0;
- int dev_id;
-
- dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
- DBUS_TYPE_STRING, &addr,
- DBUS_TYPE_INVALID)) {
- err_generic(conn, msg, derr.name, derr.message);
- dbus_error_free(&derr);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- str2ba(addr, &dst);
- l = g_slist_find_custom(mgr->paths, &dst,
- (GCompareFunc) path_bdaddr_cmp);
- if (l)
- return err_already_exists(conn, msg, "Input Already exists");
-
- ba2str(&mgr->src, adapter);
- dev_id = hci_devid(adapter);
- snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id);
-
- if (get_class(&mgr->src, &dst, &cls) < 0) {
- error("Device class not available");
- return err_not_supported(conn, msg);
- }
-
- pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst);
- if (!pr)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- switch (cls & 0x1f00) {
- case 0x0500: /* Peripheral */
- if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) {
- pending_req_free(pr);
- return err_not_supported(conn, msg);
- }
- break;
- case 0x0400: /* Fake input */
- if (get_handles(pr, headset_uuid,
- headset_handle_reply) < 0) {
- pending_req_free(pr);
- return err_not_supported(conn, msg);
- }
- break;
- default:
- pending_req_free(pr);
- return err_not_supported(conn, msg);
- }
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult manager_remove_device(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct input_manager *mgr = data;
- struct input_device *idev;
- DBusMessage *reply;
- DBusError derr;
- GSList *l;
- const char *path;
-
- dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID)) {
- err_generic(conn, msg, derr.name, derr.message);
- dbus_error_free(&derr);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- l = g_slist_find_custom(mgr->paths, path, (GCompareFunc) strcmp);
- if (!l)
- return err_does_not_exist(conn, msg, "Input doesn't exist");
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- /* Try disconnect */
- if (dbus_connection_get_object_path_data(conn, path, (void *) &idev) && idev)
- disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG));
-
- del_stored_device_info(&mgr->src, &idev->dst);
-
- if (unregister_input_device(conn, path) < 0) {
- dbus_message_unref(reply);
- return err_failed(conn, msg, "D-Bus path unregistration failed");
- }
-
- g_free(l->data);
- mgr->paths = g_slist_remove(mgr->paths, l->data);
-
- return send_message_and_unref(conn, reply);
-}
-
-static DBusHandlerResult manager_list_devices(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct input_manager *mgr = data;
- DBusMessageIter iter, iter_array;
- DBusMessage *reply;
- GSList *paths;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &iter_array);
-
- for (paths = mgr->paths; paths != NULL; paths = paths->next) {
- const char *ppath = paths->data;
- dbus_message_iter_append_basic(&iter_array,
- DBUS_TYPE_STRING, &ppath);
- }
-
- dbus_message_iter_close_container(&iter, &iter_array);
-
- return send_message_and_unref(conn, reply);
-}
-
-static DBusHandlerResult manager_message(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *path, *iface, *member;
-
- path = dbus_message_get_path(msg);
- iface = dbus_message_get_interface(msg);
- member = dbus_message_get_member(msg);
-
- /* Catching fallback paths */
- if (strcmp(INPUT_PATH, path) != 0)
- return err_unknown_device(conn, msg);
-
- /* Accept messages from the input manager interface only */
- if (strcmp(INPUT_MANAGER_INTERFACE, iface))
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (strcmp(member, "ListDevices") == 0)
- return manager_list_devices(conn, msg, data);
-
- if (strcmp(member, "CreateDevice") == 0)
- return manager_create_device(conn, msg, data);
-
- if (strcmp(member, "RemoveDevice") == 0)
- return manager_remove_device(conn, msg, data);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static void manager_unregister(DBusConnection *conn, void *data)
-{
- struct input_manager *mgr = data;
-
- info("Unregistered manager path");
-
- input_manager_free(mgr);
-}
-
-/* Virtual table to handle manager object path hierarchy */
-static const DBusObjectPathVTable manager_table = {
- .message_function = manager_message,
- .unregister_function = manager_unregister,
-};
-
-static void stored_input(char *key, char *value, void *data)
-{
- bdaddr_t *src = data;
- struct input_device *idev;
- const char *path;
- bdaddr_t dst;
- uint32_t cls;
-
- str2ba(key, &dst);
-
- if (get_class(src, &dst, &cls) < 0)
- return;
-
- idev = input_device_new(src, &dst, cls);
-
- if (parse_stored_device_info(value, &idev->hidp) < 0) {
- input_device_free(idev);
- return;
- }
-
- path = create_input_path(idev->major, idev->minor);
- if (register_input_device(connection, idev, path) < 0)
- input_device_free(idev);
-}
-
-static int register_stored_inputs(bdaddr_t *src)
-{
- char filename[PATH_MAX + 1];
- char addr[18];
-
- ba2str(src, addr);
- create_name(filename, PATH_MAX, STORAGEDIR, addr, "input");
- textfile_foreach(filename, stored_input, src);
-
- return 0;
-}
-
-int input_dbus_init(void)
-{
- struct input_manager *mgr;
- bdaddr_t src;
- int dev_id;
-
- connection = init_dbus(NULL, NULL, NULL);
- if (!connection)
- return -1;
-
- dbus_connection_set_exit_on_disconnect(connection, TRUE);
-
- mgr = g_new0(struct input_manager, 1);
-
- /* Fallback to catch invalid device path */
- if (!dbus_connection_register_fallback(connection, INPUT_PATH,
- &manager_table, mgr)) {
- error("D-Bus failed to register %s path", INPUT_PATH);
- goto fail;
- }
-
- info("Registered input manager path:%s", INPUT_PATH);
-
- /* Set the default adapter */
- bacpy(&src, BDADDR_ANY);
- dev_id = hci_get_route(&src);
- if (dev_id < 0) {
- error("Bluetooth device not available");
- goto fail;
- }
-
- if (hci_devba(dev_id, &src) < 0) {
- error("Can't get local adapter device info");
- goto fail;
- }
-
- bacpy(&mgr->src, &src);
- /* Register well known HID devices */
- register_stored_inputs(&src);
+ send_message_and_unref(conn, msg);
return 0;
-
-fail:
- input_manager_free(mgr);
-
- return -1;
-}
-
-void input_dbus_exit(void)
-{
- dbus_connection_unregister_object_path(connection, INPUT_PATH);
-
- dbus_connection_unref(connection);
-}
-
-void internal_service(const char *identifier)
-{
- DBusMessage *msg, *reply;
- const char *name = "Input Service Debug", *desc = "";
-
- info("Registering service");
-
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
- "org.bluez.Database", "RegisterService");
- if (!msg) {
- error("Can't create service register method");
- return;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &identifier,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID);
-
- reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, NULL);
- if (!reply) {
- error("Can't register service");
- return;
- }
-
- dbus_message_unref(msg);
- dbus_message_unref(reply);
-
- dbus_connection_flush(connection);
}
diff --git a/input/device.h b/input/device.h
index 957756fd..b51056e2 100644
--- a/input/device.h
+++ b/input/device.h
@@ -21,7 +21,8 @@
*
*/
-int input_dbus_init(void);
-void input_dbus_exit(void);
-
-void internal_service(const char *identifier);
+int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *hidp, const char **path);
+int fake_input_register(DBusConnection *conn, bdaddr_t *src,
+ bdaddr_t *dst, uint8_t ch, const char **path);
+int input_device_unregister(DBusConnection *conn, const char *path);
diff --git a/input/error.c b/input/error.c
index 55c459da..658bdeff 100644
--- a/input/error.c
+++ b/input/error.c
@@ -25,4 +25,68 @@
#include <config.h>
#endif
+#include <stdlib.h>
+#include <dbus.h>
+
#include "error.h"
+
+#define INPUT_ERROR_INTERFACE "org.bluez.input.Error"
+
+DBusHandlerResult err_unknown_device(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ INPUT_ERROR_INTERFACE ".UnknownDevice",
+ "Invalid device"));
+}
+
+DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg,
+ const char *name, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg, name, str));
+
+}
+
+DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg,
+ const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ INPUT_ERROR_INTERFACE ".Failed", str));
+}
+
+DBusHandlerResult err_connection_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ INPUT_ERROR_INTERFACE".ConnectionAttemptFailed",
+ str));
+}
+
+DBusHandlerResult err_already_exists(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ INPUT_ERROR_INTERFACE ".AlreadyExists", str));
+}
+
+DBusHandlerResult err_does_not_exist(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ INPUT_ERROR_INTERFACE ".DoesNotExist", str));
+}
+
+DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ INPUT_ERROR_INTERFACE ".NotSupported",
+ "The service is not supported by the remote device"));
+}
+
diff --git a/input/error.h b/input/error.h
index e87dd676..9f767d1a 100644
--- a/input/error.h
+++ b/input/error.h
@@ -20,3 +20,25 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+
+DBusHandlerResult err_unknown_device(DBusConnection *conn,
+ DBusMessage *msg);
+
+DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg,
+ const char *name, const char *str);
+
+DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg,
+ const char *str);
+
+DBusHandlerResult err_connection_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+
+DBusHandlerResult err_already_exists(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+
+DBusHandlerResult err_does_not_exist(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+
+DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg);
+
+
diff --git a/input/main.c b/input/main.c
index 688c8a58..2a6b3b59 100644
--- a/input/main.c
+++ b/input/main.c
@@ -41,7 +41,6 @@
#include "manager.h"
#include "server.h"
-#include "device.h"
static GMainLoop *main_loop;
@@ -71,7 +70,7 @@ int main(int argc, char *argv[])
/* Create event loop */
main_loop = g_main_loop_new(NULL, FALSE);
- if (input_dbus_init() < 0) {
+ if (input_init() < 0) {
error("Unable to get on D-Bus");
exit(1);
}
@@ -85,7 +84,7 @@ int main(int argc, char *argv[])
server_stop();
- input_dbus_exit();
+ input_exit();
g_main_loop_unref(main_loop);
diff --git a/input/manager.c b/input/manager.c
index ab45339f..143471bc 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -25,13 +25,867 @@
#include <config.h>
#endif
+#include <stdlib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/hidp.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "dbus.h"
+#include "logging.h"
+#include "textfile.h"
+
+#include "error.h"
+#include "storage.h"
+#include "device.h"
#include "manager.h"
+const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb";
+const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb";
+const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb";
+
+struct pending_req {
+ char *adapter_path; /* Local adapter D-Bus path */
+ bdaddr_t src; /* Local adapter BT address */
+ bdaddr_t dst; /* Peer BT address */
+ DBusConnection *conn;
+ DBusMessage *msg;
+ sdp_record_t *pnp_rec;
+ sdp_record_t *hid_rec;
+};
+
+struct input_manager {
+ bdaddr_t src; /* Local adapter BT address */
+ GSList *paths; /* Input registered paths */
+};
+
+static DBusConnection *connection = NULL;
+
+static struct pending_req *pending_req_new(DBusConnection *conn,
+ DBusMessage *msg, const char *adapter_path,
+ bdaddr_t *src, bdaddr_t *dst)
+{
+ struct pending_req *pr;
+ pr = g_try_new0(struct pending_req, 1);
+ if (!pr)
+ return NULL;
+
+ pr->adapter_path = g_strdup(adapter_path);
+ bacpy(&pr->src, src);
+ bacpy(&pr->dst, dst);
+ pr->conn = dbus_connection_ref(conn);
+ pr->msg = dbus_message_ref(msg);
+
+ return pr;
+}
+
+static void pending_req_free(struct pending_req *pr)
+{
+ if (!pr)
+ return;
+ if (pr->adapter_path)
+ g_free(pr->adapter_path);
+ if (pr->conn)
+ dbus_connection_unref(pr->conn);
+ if (pr->msg)
+ dbus_message_unref(pr->msg);
+ if (pr->pnp_rec)
+ sdp_record_free(pr->pnp_rec);
+ if (pr->hid_rec)
+ sdp_record_free(pr->hid_rec);
+ g_free(pr);
+}
+
+#if 0
+static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr)
+{
+ struct input_device *idev;
+
+ if (!dbus_connection_get_object_path_data(connection, path,
+ (void *) &idev))
+ return -1;
+
+ if (!idev)
+ return -1;
+
+ return bacmp(&idev->dst, bdaddr);
+}
+#endif
+static int get_record(struct pending_req *pr, uint32_t handle,
+ DBusPendingCallNotifyFunction cb)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+ char addr[18];
+ const char *paddr = addr;
+
+ msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
+ "org.bluez.Adapter", "GetRemoteServiceRecord");
+ if (!msg)
+ return -1;
+
+ ba2str(&pr->dst, addr);
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ return -1;
+ }
+
+ dbus_pending_call_set_notify(pending, cb, pr, NULL);
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int get_handles(struct pending_req *pr, const char *uuid,
+ DBusPendingCallNotifyFunction cb)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+ char addr[18];
+ const char *paddr = addr;
+
+ msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
+ "org.bluez.Adapter", "GetRemoteServiceHandles");
+ if (!msg)
+ return -1;
+
+ ba2str(&pr->dst, addr);
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ return -1;
+ }
+
+ dbus_pending_call_set_notify(pending, cb, pr, NULL);
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
+{
+ sdp_data_t *pdlist, *pdlist2;
+ uint8_t attr_val;
+
+ pdlist = sdp_data_get(rec, 0x0101);
+ pdlist2 = sdp_data_get(rec, 0x0102);
+ if (pdlist) {
+ if (pdlist2) {
+ if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
+ strncpy(req->name, pdlist2->val.str, 127);
+ strcat(req->name, " ");
+ }
+ strncat(req->name, pdlist->val.str, 127 - strlen(req->name));
+ } else
+ strncpy(req->name, pdlist->val.str, 127);
+ } else {
+ pdlist2 = sdp_data_get(rec, 0x0100);
+ if (pdlist2)
+ strncpy(req->name, pdlist2->val.str, 127);
+ }
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
+ req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
+ req->subclass = pdlist ? pdlist->val.uint8 : 0;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
+ req->country = pdlist ? pdlist->val.uint8 : 0;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
+ attr_val = pdlist ? pdlist->val.uint8 : 0;
+ if (attr_val)
+ req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
+ attr_val = pdlist ? pdlist->val.uint8 : 0;
+ if (attr_val)
+ req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
+ if (pdlist) {
+ pdlist = pdlist->val.dataseq;
+ pdlist = pdlist->val.dataseq;
+ pdlist = pdlist->next;
+
+ req->rd_data = g_try_malloc0(pdlist->unitSize);
+ if (req->rd_data) {
+ memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize);
+ req->rd_size = pdlist->unitSize;
+ }
+ }
+}
+
+static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req)
+{
+ sdp_data_t *pdlist;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
+ req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
+ req->product = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
+ req->version = pdlist ? pdlist->val.uint16 : 0x0000;
+}
+
+static void hid_record_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusMessage *pr_reply;
+ struct input_manager *mgr;
+ struct pending_req *pr = data;
+ struct hidp_connadd_req hidp;
+ DBusError derr;
+ uint8_t *rec_bin;
+ const char *path;
+ int len, scanned;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ err_generic(pr->conn, pr->msg, derr.name, derr.message);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Invalid HID service record length");
+ goto fail;
+ }
+
+ pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned);
+ if (!pr->hid_rec) {
+ err_not_supported(pr->conn, pr->msg);
+ goto fail;
+ }
+
+ memset(&hidp, 0, sizeof(struct hidp_connadd_req));
+ extract_hid_record(pr->hid_rec, &hidp);
+ if (pr->pnp_rec)
+ extract_pnp_record(pr->pnp_rec, &hidp);
+
+ store_device_info(&pr->src, &pr->dst, &hidp);
+
+ if (input_device_register(pr->conn, &pr->src,
+ &pr->dst, &hidp, &path) < 0) {
+ err_failed(pr->conn, pr->msg, "D-Bus path registration failed");
+ goto fail;
+ }
+
+ dbus_connection_get_object_path_data(pr->conn, INPUT_PATH, (void *) &mgr);
+ mgr->paths = g_slist_append(mgr->paths, g_strdup(path));
+
+ pr_reply = dbus_message_new_method_return(pr->msg);
+ dbus_message_append_args(pr_reply,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(pr->conn, pr_reply);
+fail:
+ dbus_error_free(&derr);
+ pending_req_free(pr);
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void hid_handle_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ struct pending_req *pr = data;
+ uint32_t *phandle;
+ DBusError derr;
+ int len;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ err_generic(pr->conn, pr->msg, derr.name, derr.message);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("HID record handle not found");
+ goto fail;
+ }
+
+ if (get_record(pr, *phandle, hid_record_reply) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("HID service attribute request failed");
+ goto fail;
+ } else {
+ /* Wait record reply */
+ goto done;
+ }
+fail:
+ dbus_error_free(&derr);
+ pending_req_free(pr);
+done:
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void pnp_record_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ struct pending_req *pr = data;
+ DBusError derr;
+ uint8_t *rec_bin;
+ int len, scanned;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ err_generic(pr->conn, pr->msg, derr.name, derr.message);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Invalid PnP service record length");
+ goto fail;
+ }
+
+ pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned);
+ if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("HID service search request failed");
+ goto fail;
+ } else {
+ /* Wait handle reply */
+ goto done;
+ }
+
+fail:
+ dbus_error_free(&derr);
+ pending_req_free(pr);
+done:
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void pnp_handle_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ struct pending_req *pr = data;
+ DBusError derr;
+ uint32_t *phandle;
+ int len;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ err_generic(pr->conn, pr->msg, derr.name, derr.message);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ /* PnP is optional: Ignore it and request the HID handle */
+ if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("HID service search request failed");
+ goto fail;
+ }
+ } else {
+ /* Request PnP record */
+ if (get_record(pr, *phandle, pnp_record_reply) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("PnP service attribute request failed");
+ goto fail;
+ }
+ }
+
+ /* Wait HID handle reply or PnP record reply */
+ goto done;
+
+fail:
+ dbus_error_free(&derr);
+ pending_req_free(pr);
+done:
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void headset_record_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusMessage *pr_reply;
+ DBusError derr;
+ struct input_manager *mgr;
+ struct pending_req *pr = data;
+ uint8_t *rec_bin;
+ sdp_record_t *rec;
+ sdp_list_t *protos;
+ const char *path;
+ int len, scanned;
+ uint8_t ch;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ err_generic(pr->conn, pr->msg, derr.name, derr.message);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Invalid headset service record length");
+ goto fail;
+ }
+
+ rec = sdp_extract_pdu(rec_bin, &scanned);
+ if (!rec) {
+ err_not_supported(pr->conn, pr->msg);
+ goto fail;
+ }
+
+ if (sdp_get_access_protos(rec, &protos) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ goto fail;
+ }
+
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+ sdp_record_free(rec);
+
+ if (ch <= 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Invalid RFCOMM channel");
+ goto fail;
+ }
+
+ /* FIXME: Store the fake input data */
+
+ if (fake_input_register(pr->conn, &pr->src, &pr->dst, ch, &path) < 0) {
+ error("D-Bus path registration failed:%s", path);
+ err_failed(pr->conn, pr->msg, "Path registration failed");
+ goto fail;
+ }
+
+ dbus_connection_get_object_path_data(pr->conn, INPUT_PATH, (void *) &mgr);
+ mgr->paths = g_slist_append(mgr->paths, g_strdup(path));
+
+ pr_reply = dbus_message_new_method_return(pr->msg);
+ dbus_message_append_args(pr_reply,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(pr->conn, pr_reply);
+fail:
+ dbus_error_free(&derr);
+ pending_req_free(pr);
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void headset_handle_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ struct pending_req *pr = data;
+ DBusError derr;
+ uint32_t *phandle;
+ int len;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ err_generic(pr->conn, pr->msg, derr.name, derr.message);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len,
+ DBUS_TYPE_INVALID)) {
+ err_not_supported(pr->conn, pr->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Headset record handle not found");
+ goto fail;
+ }
+
+ if (get_record(pr, *phandle, headset_record_reply) < 0) {
+ err_not_supported(pr->conn, pr->msg);
+ error("Headset service attribute request failed");
+ goto fail;
+ } else {
+ /* Wait record reply */
+ goto done;
+ }
+fail:
+ dbus_error_free(&derr);
+ pending_req_free(pr);
+done:
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static DBusHandlerResult manager_create_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct input_manager *mgr = data;
+ struct pending_req *pr;
+ DBusError derr;
+ char adapter[18], adapter_path[32];
+ const char *addr;
+ bdaddr_t dst;
+ uint32_t cls = 0;
+ int dev_id;
+
+ dbus_error_init(&derr);
+ if (!dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID)) {
+ err_generic(conn, msg, derr.name, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ str2ba(addr, &dst);
+#if 0
+ /* FIXME */
+ l = g_slist_find_custom(mgr->paths, &dst,
+ (GCompareFunc) path_bdaddr_cmp);
+ if (l)
+ return err_already_exists(conn, msg, "Input Already exists");
+#endif
+ /* FIXME: Move the following code to pending_req_new() */
+ ba2str(&mgr->src, adapter);
+ dev_id = hci_devid(adapter);
+ snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id);
+
+ if (read_device_class(&mgr->src, &dst, &cls) < 0) {
+ error("Device class not available");
+ return err_not_supported(conn, msg);
+ }
+
+ pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst);
+ if (!pr)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ switch (cls & 0x1f00) {
+ case 0x0500: /* Peripheral */
+ if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) {
+ pending_req_free(pr);
+ return err_not_supported(conn, msg);
+ }
+ break;
+ case 0x0400: /* Fake input */
+ if (get_handles(pr, headset_uuid,
+ headset_handle_reply) < 0) {
+ pending_req_free(pr);
+ return err_not_supported(conn, msg);
+ }
+ break;
+ default:
+ pending_req_free(pr);
+ return err_not_supported(conn, msg);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult manager_remove_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct input_manager *mgr = data;
+ DBusMessage *reply;
+ DBusError derr;
+ GSList *l;
+ const char *path;
+
+ dbus_error_init(&derr);
+ if (!dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID)) {
+ err_generic(conn, msg, derr.name, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ l = g_slist_find_custom(mgr->paths, path, (GCompareFunc) strcmp);
+ if (!l)
+ return err_does_not_exist(conn, msg, "Input doesn't exist");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ g_free(l->data);
+ mgr->paths = g_slist_remove(mgr->paths, l->data);
+
+ /* FIXME: how retrieve the destination address */
+ //del_stored_device_info(&mgr->src, &idev->dst);
+
+ if (input_device_unregister(conn, path) < 0) {
+ dbus_message_unref(reply);
+ return err_failed(conn, msg, "D-Bus path unregistration failed");
+ }
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult manager_list_devices(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct input_manager *mgr = data;
+ DBusMessageIter iter, iter_array;
+ DBusMessage *reply;
+ GSList *paths;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &iter_array);
+
+ for (paths = mgr->paths; paths != NULL; paths = paths->next) {
+ const char *ppath = paths->data;
+ dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING, &ppath);
+ }
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ return send_message_and_unref(conn, reply);
+}
+static DBusHandlerResult manager_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path, *iface, *member;
+
+ path = dbus_message_get_path(msg);
+ iface = dbus_message_get_interface(msg);
+ member = dbus_message_get_member(msg);
+
+ /* Catching fallback paths */
+ if (strcmp(INPUT_PATH, path) != 0)
+ return err_unknown_device(conn, msg);
+
+ /* Accept messages from the input manager interface only */
+ if (strcmp(INPUT_MANAGER_INTERFACE, iface))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (strcmp(member, "ListDevices") == 0)
+ return manager_list_devices(conn, msg, data);
+
+ if (strcmp(member, "CreateDevice") == 0)
+ return manager_create_device(conn, msg, data);
+
+ if (strcmp(member, "RemoveDevice") == 0)
+ return manager_remove_device(conn, msg, data);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void input_manager_free(struct input_manager *mgr)
+{
+ if (!mgr)
+ return;
+
+ if (mgr->paths) {
+ g_slist_foreach(mgr->paths, (GFunc) free, NULL);
+ g_slist_free(mgr->paths);
+ }
+
+ g_free(mgr);
+}
+
+static void manager_unregister(DBusConnection *conn, void *data)
+{
+ struct input_manager *mgr = data;
+
+ info("Unregistered manager path");
+
+ input_manager_free(mgr);
+}
+
+/* Virtual table to handle manager object path hierarchy */
+static const DBusObjectPathVTable manager_table = {
+ .message_function = manager_message,
+ .unregister_function = manager_unregister,
+};
+
+/*
+ * Stored inputs registration functions
+ */
+
+static void stored_input(char *key, char *value, void *data)
+{
+ struct input_manager *mgr = data;
+ const char *path;
+ struct hidp_connadd_req hidp;
+ bdaddr_t dst;
+
+ str2ba(key, &dst);
+
+ memset(&hidp, 0, sizeof(struct hidp_connadd_req));
+ if (parse_stored_device_info(value, &hidp) < 0) {
+ return;
+ }
+
+ if (input_device_register(connection, &mgr->src, &dst, &hidp, &path) < 0)
+ return;
+
+ mgr->paths = g_slist_append(mgr->paths, g_strdup(path));
+}
+
+static int register_stored_inputs(struct input_manager *mgr)
+{
+ char filename[PATH_MAX + 1];
+ char addr[18];
+
+ ba2str(&mgr->src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "input");
+ textfile_foreach(filename, stored_input, mgr);
+
+ return 0;
+}
+
int input_init(void)
{
+ struct input_manager *mgr;
+ bdaddr_t src;
+ int dev_id;
+
+ connection = init_dbus(NULL, NULL, NULL);
+ if (!connection)
+ return -1;
+
+ dbus_connection_set_exit_on_disconnect(connection, TRUE);
+
+ mgr = g_new0(struct input_manager, 1);
+
+ /* Fallback to catch invalid device path */
+ if (!dbus_connection_register_fallback(connection, INPUT_PATH,
+ &manager_table, mgr)) {
+ error("D-Bus failed to register %s path", INPUT_PATH);
+ goto fail;
+ }
+
+ info("Registered input manager path:%s", INPUT_PATH);
+
+ /* Set the default adapter */
+ bacpy(&src, BDADDR_ANY);
+ dev_id = hci_get_route(&src);
+ if (dev_id < 0) {
+ error("Bluetooth device not available");
+ goto fail;
+ }
+
+ if (hci_devba(dev_id, &src) < 0) {
+ error("Can't get local adapter device info");
+ goto fail;
+ }
+
+ bacpy(&mgr->src, &src);
+ /* Register well known HID devices */
+ register_stored_inputs(mgr);
+
return 0;
+
+fail:
+ input_manager_free(mgr);
+
+ return -1;
}
void input_exit(void)
{
+ dbus_connection_unregister_object_path(connection, INPUT_PATH);
+
+ dbus_connection_unref(connection);
+}
+
+void internal_service(const char *identifier)
+{
+ DBusMessage *msg, *reply;
+ const char *name = "Input Service Debug", *desc = "";
+
+ info("Registering service");
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Database", "RegisterService");
+ if (!msg) {
+ error("Can't create service register method");
+ return;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &identifier,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID);
+
+ reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, NULL);
+ if (!reply) {
+ error("Can't register service");
+ return;
+ }
+
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+
+ dbus_connection_flush(connection);
}
diff --git a/input/manager.h b/input/manager.h
index 98e6d2d8..9eee22aa 100644
--- a/input/manager.h
+++ b/input/manager.h
@@ -21,5 +21,9 @@
*
*/
+#define INPUT_PATH "/org/bluez/input"
+#define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager"
+
int input_init(void);
void input_exit(void);
+void internal_service(const char *identifier);
diff --git a/input/storage.c b/input/storage.c
index fd8d4bcb..3793a275 100644
--- a/input/storage.c
+++ b/input/storage.c
@@ -44,8 +44,8 @@
#include <glib.h>
-#include "textfile.h"
#include "logging.h"
+#include "textfile.h"
#include "storage.h"
@@ -171,14 +171,14 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req
return err;
}
-int read_device_name(bdaddr_t *local, bdaddr_t *peer, char **name)
+int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name)
{
char filename[PATH_MAX + 1], addr[18], *str;
int len;
- create_filename(filename, PATH_MAX, local, "names");
+ create_filename(filename, PATH_MAX, src, "names");
- ba2str(peer, addr);
+ ba2str(dst, addr);
str = textfile_get(filename, addr);
if (!str)
return -ENOENT;
@@ -202,6 +202,29 @@ int read_device_name(bdaddr_t *local, bdaddr_t *peer, char **name)
return 0;
}
+int read_device_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls)
+{
+ char filename[PATH_MAX + 1], *str;
+ char addr[18];
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "classes");
+
+ ba2str(dst, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ if (sscanf(str, "%x", cls) != 1) {
+ g_free(str);
+ return -ENOENT;
+ }
+
+ g_free(str);
+
+ return 0;
+}
+
int encrypt_link(bdaddr_t *src, bdaddr_t *dst)
{
char filename[PATH_MAX + 1];
diff --git a/input/storage.h b/input/storage.h
index 60df915d..81ad2599 100644
--- a/input/storage.h
+++ b/input/storage.h
@@ -32,6 +32,7 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst,
int parse_stored_device_info(const char *str,
struct hidp_connadd_req *req);
-int read_device_name(bdaddr_t *local, bdaddr_t *peer, char **name);
+int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name);
+int read_device_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls);
int encrypt_link(bdaddr_t *src, bdaddr_t *dst);