diff options
author | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2007-03-19 14:58:44 +0000 |
---|---|---|
committer | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2007-03-19 14:58:44 +0000 |
commit | f2c6a6f2debcccfb51d239834c3cf91a2c3a6c40 (patch) | |
tree | 2a83d19fc07684f6713dd901f46f04858a78bc3d /input/device.c | |
parent | 0ac929228aa1eb823f37776e2bbb84855417c66e (diff) |
Moving input functions to the right files
Diffstat (limited to 'input/device.c')
-rw-r--r-- | input/device.c | 1011 |
1 files changed, 49 insertions, 962 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); } |