From c761480865c6b65e370e2bba750c86c226a7fc3f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 27 Oct 2006 14:46:36 +0000 Subject: Add skeletons for service implementations --- input/Makefile.am | 12 ++++++++++++ input/main.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 input/Makefile.am create mode 100644 input/main.c (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am new file mode 100644 index 00000000..c684432d --- /dev/null +++ b/input/Makefile.am @@ -0,0 +1,12 @@ + +noinst_PROGRAMS = bt.inputd + +bt_inputd_SOURCES = main.c + +bt_inputd_LDADD = @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a + +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ + +INCLUDES = -I$(top_srcdir)/common + +MAINTAINERCLEANFILES = Makefile.in diff --git a/input/main.c b/input/main.c new file mode 100644 index 00000000..c04bb251 --- /dev/null +++ b/input/main.c @@ -0,0 +1,34 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2006 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +int main(int argc, char *argv[]) +{ + return 0; +} -- cgit From 3eb0a5cd951b680c89f92bce6dddce2da2539af0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 11 Nov 2006 23:14:14 +0000 Subject: Initial service skeleton for bt.inputd --- input/Makefile.am | 2 +- input/input-service.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++ input/input-service.h | 29 +++++++++ input/main.c | 69 ++++++++++++++++++++ 4 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 input/input-service.c create mode 100644 input/input-service.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index c684432d..c23df9ba 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -1,7 +1,7 @@ noinst_PROGRAMS = bt.inputd -bt_inputd_SOURCES = main.c +bt_inputd_SOURCES = main.c input-service.h input-service.c bt_inputd_LDADD = @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a diff --git a/input/input-service.c b/input/input-service.c new file mode 100644 index 00000000..b036bf70 --- /dev/null +++ b/input/input-service.c @@ -0,0 +1,172 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2006 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "dbus.h" +#include "logging.h" + +#include + +#define INPUT_PATH "/org/bluez/input" + +static DBusConnection *connection = NULL; + +static DBusHandlerResult start_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + + info("Starting example service"); + + reply = dbus_message_new_method_return(msg); + if (!reply) { + error("Can't create reply message"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + dbus_connection_send(conn, reply, NULL); + + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult stop_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + + info("Stopping example service"); + + reply = dbus_message_new_method_return(msg); + if (!reply) { + error("Can't create reply message"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_connection_send(conn, reply, NULL); + + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult release_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) { + error("Can't create reply message"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_connection_send(conn, reply, NULL); + + dbus_message_unref(reply); + + info("Got Release method. Exiting."); + + raise(SIGTERM); + + return DBUS_HANDLER_RESULT_HANDLED; +} + + +static DBusHandlerResult input_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + if (dbus_message_is_method_call(msg, "org.bluez.ServiceAgent", "Start")) + return start_message(conn, msg, data); + + if (dbus_message_is_method_call(msg, "org.bluez.ServiceAgent", "Stop")) + return stop_message(conn, msg, data); + + if (dbus_message_is_method_call(msg, "org.bluez.ServiceAgent", "Release")) + return release_message(conn, msg, data); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +static const DBusObjectPathVTable input_table = { + .message_function = input_message, +}; + +int input_dbus_init(void) +{ + DBusError err; + DBusMessage *msg, *reply; + const char *name = "Input service"; + const char *description = "A service for input devices"; + const char *input_path = INPUT_PATH; + + connection = init_dbus(NULL, NULL); + if (!connection) + return -1; + + dbus_error_init(&err); + + if (!dbus_connection_register_object_path(connection, input_path, + &input_table, NULL)) { + error("D-Bus failed to register %s path", INPUT_PATH); + return -1; + } + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Manager", "RegisterService"); + if (!msg) { + error("Can't allocate new method call"); + return -1; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &input_path, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &description, + DBUS_TYPE_INVALID); + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, + &err); + + dbus_message_unref(msg); + + if (!reply) { + error("Can't register service agent"); + if (dbus_error_is_set(&err)) { + error("%s", err.message); + dbus_error_free(&err); + } + return -1; + } + + return 0; +} + diff --git a/input/input-service.h b/input/input-service.h new file mode 100644 index 00000000..6cc0b413 --- /dev/null +++ b/input/input-service.h @@ -0,0 +1,29 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2006 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __INPUT_SERVICE_H +#define __INPUT_SERVICE_H + +int input_dbus_init(void); + +#endif /* __INPUT_SERVICE_H */ diff --git a/input/main.c b/input/main.c index c04bb251..df3b5160 100644 --- a/input/main.c +++ b/input/main.c @@ -26,9 +26,78 @@ #endif #include +#include +#include #include +#include +#include +#include + +#include "dbus.h" +#include "logging.h" +#include "glib-ectomy.h" + +#include "input-service.h" + +static GMainLoop *main_loop; + +static void usage(void) +{ + printf("bt.inputd - Bluetooth Input daemon ver %s\n", VERSION); + printf("Usage: \n"); + printf("\tbt.inputd [-n not_daemon]\n"); +} + +static void sig_term(int sig) +{ + g_main_quit(main_loop); +} int main(int argc, char *argv[]) { + struct sigaction sa; + int opt, daemonize = 1; + + while ((opt = getopt(argc, argv, "n")) != EOF) { + switch (opt) { + case 'n': + daemonize = 0; + break; + + default: + usage(); + exit(1); + } + } + + if (daemonize && daemon(0, 0)) { + error("Can't daemonize: %s (%d)", strerror(errno), errno); + exit(1); + } + + start_logging("bt.inputd", "Bluetooth Input daemon"); + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = sig_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + enable_debug(); + + /* Create event loop */ + main_loop = g_main_new(FALSE); + + if (input_dbus_init() < 0) { + error("Unable to get on D-Bus"); + exit(1); + } + + g_main_run(main_loop); + return 0; } -- cgit From 40e3342c520a00d47d68f7791cb70cb49d698630 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 13 Nov 2006 07:58:40 +0000 Subject: Add D-Bus name setup to common function --- input/input-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index b036bf70..14bce1c3 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -127,7 +127,7 @@ int input_dbus_init(void) const char *description = "A service for input devices"; const char *input_path = INPUT_PATH; - connection = init_dbus(NULL, NULL); + connection = init_dbus(NULL, NULL, NULL); if (!connection) return -1; -- cgit From 8512236a405d345e4a9c19d47e593cbf2fec81e3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Nov 2006 11:51:55 +0000 Subject: code cleanup/fixes --- input/input-service.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 14bce1c3..15e37e44 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -34,6 +34,8 @@ #define INPUT_PATH "/org/bluez/input" +static int started = 0; + static DBusConnection *connection = NULL; static DBusHandlerResult start_message(DBusConnection *conn, @@ -41,18 +43,20 @@ static DBusHandlerResult start_message(DBusConnection *conn, { DBusMessage *reply; - info("Starting example service"); + info("Starting input service"); reply = dbus_message_new_method_return(msg); if (!reply) { error("Can't create reply message"); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return DBUS_HANDLER_RESULT_NEED_MEMORY; } dbus_connection_send(conn, reply, NULL); dbus_message_unref(reply); + started = 1; + return DBUS_HANDLER_RESULT_HANDLED; } @@ -61,7 +65,7 @@ static DBusHandlerResult stop_message(DBusConnection *conn, { DBusMessage *reply; - info("Stopping example service"); + info("Stopping input service"); reply = dbus_message_new_method_return(msg); if (!reply) { @@ -73,6 +77,8 @@ static DBusHandlerResult stop_message(DBusConnection *conn, dbus_message_unref(reply); + started = 0; + return DBUS_HANDLER_RESULT_HANDLED; } @@ -167,6 +173,8 @@ int input_dbus_init(void) return -1; } + dbus_message_unref(reply); + return 0; } -- cgit From bb83060114ca74dc711b93c44693977e7dd4f5ad Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Nov 2006 15:15:00 +0000 Subject: Preparation for the Input interface implementation --- input/input-service.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 15e37e44..a64b1c25 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -25,6 +25,7 @@ #include #endif +#include #include #include "dbus.h" @@ -104,23 +105,33 @@ static DBusHandlerResult release_message(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - static DBusHandlerResult input_message(DBusConnection *conn, DBusMessage *msg, void *data) { - if (dbus_message_is_method_call(msg, "org.bluez.ServiceAgent", "Start")) - return start_message(conn, msg, data); + const char *interface; + const char *member; + + interface = dbus_message_get_interface(msg); + member = dbus_message_get_member(msg); + + if (strcmp(interface, "org.bluez.ServiceAgent") == 0) { + if (strcmp(member, "Start") == 0) + return start_message(conn, msg, data); + if (strcmp(member, "Stop") == 0) + return stop_message(conn, msg, data); + if (strcmp(member, "Release") == 0) + return release_message(conn, msg, data); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } - if (dbus_message_is_method_call(msg, "org.bluez.ServiceAgent", "Stop")) - return stop_message(conn, msg, data); + if (strcmp(interface, "org.bluez.Input") != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (dbus_message_is_method_call(msg, "org.bluez.ServiceAgent", "Release")) - return release_message(conn, msg, data); + /* Handle Input interface methods here */ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - static const DBusObjectPathVTable input_table = { .message_function = input_message, }; -- cgit From a40937598985b3f25f6078c9407bf9b682bf6f56 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 13 Nov 2006 16:18:20 +0000 Subject: Establish well known name for input service --- input/Makefile.am | 8 ++++++++ input/bluetooth-input.conf | 21 +++++++++++++++++++++ input/input-service.c | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 input/bluetooth-input.conf (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index c23df9ba..b578645c 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -1,4 +1,10 @@ +if CONFIGFILES +dbusdir = $(sysconfdir)/dbus-1/system.d + +dbus_DATA = bluetooth-input.conf +endif + noinst_PROGRAMS = bt.inputd bt_inputd_SOURCES = main.c input-service.h input-service.c @@ -9,4 +15,6 @@ AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ INCLUDES = -I$(top_srcdir)/common +EXTRA_DIST = bluetooth-input.conf + MAINTAINERCLEANFILES = Makefile.in diff --git a/input/bluetooth-input.conf b/input/bluetooth-input.conf new file mode 100644 index 00000000..90643f74 --- /dev/null +++ b/input/bluetooth-input.conf @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/input/input-service.c b/input/input-service.c index a64b1c25..d76ef74b 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -144,7 +144,7 @@ int input_dbus_init(void) const char *description = "A service for input devices"; const char *input_path = INPUT_PATH; - connection = init_dbus(NULL, NULL, NULL); + connection = init_dbus("org.bluez.input", NULL, NULL); if (!connection) return -1; -- cgit From e95363393f55072d43a0b5d70e11c790b4feecd4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Nov 2006 17:51:56 +0000 Subject: Call Register asynchronously --- input/input-service.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index d76ef74b..accb17c9 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -136,10 +136,27 @@ static const DBusObjectPathVTable input_table = { .message_function = input_message, }; -int input_dbus_init(void) +static void register_reply(DBusPendingCall *call, void *data) { + DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError err; - DBusMessage *msg, *reply; + + dbus_error_init(&err); + if (dbus_set_error_from_message(&err, reply)) { + error("Registering failed: %s", err.message); + dbus_error_free(&err); + raise(SIGTERM); + } + else + debug("Successfully registered"); + + dbus_message_unref(reply); +} + +int input_dbus_init(void) +{ + DBusMessage *msg; + DBusPendingCall *pending; const char *name = "Input service"; const char *description = "A service for input devices"; const char *input_path = INPUT_PATH; @@ -148,8 +165,6 @@ int input_dbus_init(void) if (!connection) return -1; - dbus_error_init(&err); - if (!dbus_connection_register_object_path(connection, input_path, &input_table, NULL)) { error("D-Bus failed to register %s path", INPUT_PATH); @@ -168,23 +183,14 @@ int input_dbus_init(void) DBUS_TYPE_STRING, &description, DBUS_TYPE_INVALID); - dbus_error_init(&err); - - reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, - &err); - - dbus_message_unref(msg); - - if (!reply) { - error("Can't register service agent"); - if (dbus_error_is_set(&err)) { - error("%s", err.message); - dbus_error_free(&err); - } + if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) { + error("Sending Register method call failed"); + dbus_message_unref(msg); return -1; } - dbus_message_unref(reply); + dbus_pending_call_set_notify(pending, register_reply, NULL, NULL); + dbus_message_unref(msg); return 0; } -- cgit From c97480f11bdfdc3cbb867b8127074bcb6b047024 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 12 Jan 2007 00:37:42 +0000 Subject: Allow compilation against GLib --- input/Makefile.am | 12 ++++++++++-- input/main.c | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index b578645c..cafc03a6 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -5,13 +5,21 @@ dbusdir = $(sysconfdir)/dbus-1/system.d dbus_DATA = bluetooth-input.conf endif +if GLIB +glib_cflags = @GLIB_CFLAGS@ +glib_ldadd = @GLIB_LIBS@ +else +glib_cflags = +glib_ldadd = +endif + noinst_PROGRAMS = bt.inputd bt_inputd_SOURCES = main.c input-service.h input-service.c -bt_inputd_LDADD = @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a +bt_inputd_LDADD = $(glib_ldadd) @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a -AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ $(glib_cflags) INCLUDES = -I$(top_srcdir)/common diff --git a/input/main.c b/input/main.c index df3b5160..5523b67f 100644 --- a/input/main.c +++ b/input/main.c @@ -26,11 +26,14 @@ #endif #include +#include #include +#include #include #include #include #include + #include #include "dbus.h" -- cgit From 8a7d17430468d08c3d0660e2159cc046eebc5dfc Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 18 Jan 2007 13:42:11 +0000 Subject: Added methods skeleton --- input/input-api.txt | 93 ++++++++++++++++++ input/input-service.c | 267 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 253 insertions(+), 107 deletions(-) create mode 100644 input/input-api.txt (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt new file mode 100644 index 00000000..f321ac2b --- /dev/null +++ b/input/input-api.txt @@ -0,0 +1,93 @@ +Bluetooth input service API description +****************************************** + +Copyright (C) 2006-2007 Marcel Holtmann + +Error hierarchy +=============== + +Interface org.bluez.Error + +Errors Failed + + An unknown error occured. The error messages is + taken from the strerror(errno) function. + + UnknownDevice + + Error returned when the input device path is invalid + + UnknownMethod + + Error returned when the input device path doesn't + implement the requested method. + + +Input Manager hierarchy +================= + +Service org.bluez.input +Interface org.bluez.input.Manager +Object path /org/bluez/input + +Methods + array{string} ListDevices() + + Returns an array of available input devices path. + + void CreateDevice(string address) + + Create an input device object: HID service record is + retrieved and bonding(if applied) is created. + + void RemoveDevice(string path) + + Remove the input device object for a given path. + + +Input hierarchy +================= + +Service org.bluez.input +Interface org.bluez.input +Object path /org/bluez/input_* + +Methods string GetAddress() + + Returns the device address. + + Example: "00:11:22:33:44:55" + + string GetName() + + Returns the service name. + + string GetProductId() + + Returns the product id. + + string GetVendorId() + + Returns the vendor id. + + boolean IsConnected() + + Returns the connection status. + + void Connect() + + Connect to the input device. + + void Disconnect() + + Disconnect from the input device. + + void Unplug() + + Unplug the virtual cable device. + + void SetTimeout(uint32 timeout) + + Set the idle timeout. + + diff --git a/input/input-service.c b/input/input-service.c index accb17c9..54e745a4 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -25,173 +25,226 @@ #include #endif -#include -#include +#include +#include +#include #include "dbus.h" #include "logging.h" +#include "input-service.h" +#include "glib-ectomy.h" #include +#include +#include +#include + +#define INPUT_SERVICE "org.bluez.input" #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" -static int started = 0; static DBusConnection *connection = NULL; -static DBusHandlerResult start_message(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; +static DBusHandlerResult manager_message(DBusConnection *conn, + DBusMessage *msg, void *data); +static DBusHandlerResult device_message(DBusConnection *conn, + DBusMessage *msg, void *data); - info("Starting input service"); +static const DBusObjectPathVTable manager_table = { + .message_function = manager_message, +}; - reply = dbus_message_new_method_return(msg); - if (!reply) { - error("Can't create reply message"); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } +static const DBusObjectPathVTable device_table = { + .message_function = device_message, +}; - dbus_connection_send(conn, reply, NULL); +/* + * 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")); +} - dbus_message_unref(reply); +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")); +} - started = 1; +/* + * Input Manager methods + */ +static DBusHandlerResult manager_create_device(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - return DBUS_HANDLER_RESULT_HANDLED; +static DBusHandlerResult manager_remove_device(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -static DBusHandlerResult stop_message(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult manager_list_devices(DBusConnection *conn, + DBusMessage *msg, void *udata) { - DBusMessage *reply; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - info("Stopping input service"); +static DBusHandlerResult manager_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const char *path, *iface, *member; - reply = dbus_message_new_method_return(msg); - if (!reply) { - error("Can't create reply message"); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } + 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; - dbus_connection_send(conn, reply, NULL); + if (strcmp(member, "ListDevices") == 0) + return manager_list_devices(conn, msg, data); - dbus_message_unref(reply); + if (strcmp(member, "CreateDevice") == 0) + return manager_create_device(conn, msg, data); - started = 0; + if (strcmp(member, "RemoveDevice") == 0) + return manager_remove_device(conn, msg, data); - return DBUS_HANDLER_RESULT_HANDLED; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -static DBusHandlerResult release_message(DBusConnection *conn, - DBusMessage *msg, void *data) +/* + * Input Device methods + */ +static DBusHandlerResult device_connect(DBusConnection *conn, + DBusMessage *msg, void *udata) { - DBusMessage *reply; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - reply = dbus_message_new_method_return(msg); - if (!reply) { - error("Can't create reply message"); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } +static DBusHandlerResult device_disconnect(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - dbus_connection_send(conn, reply, NULL); +static DBusHandlerResult device_unplug(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - dbus_message_unref(reply); +static DBusHandlerResult device_is_connected(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - info("Got Release method. Exiting."); +static DBusHandlerResult device_get_address(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - raise(SIGTERM); +static DBusHandlerResult device_get_name(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - return DBUS_HANDLER_RESULT_HANDLED; +static DBusHandlerResult device_get_product_id(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -static DBusHandlerResult input_message(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult device_set_timeout(DBusConnection *conn, + DBusMessage *msg, void *udata) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +static DBusHandlerResult device_message(DBusConnection *conn, + DBusMessage *msg, void *data) { - const char *interface; - const char *member; + const char *iface, *member; - interface = dbus_message_get_interface(msg); + iface = dbus_message_get_interface(msg); member = dbus_message_get_member(msg); - if (strcmp(interface, "org.bluez.ServiceAgent") == 0) { - if (strcmp(member, "Start") == 0) - return start_message(conn, msg, data); - if (strcmp(member, "Stop") == 0) - return stop_message(conn, msg, data); - if (strcmp(member, "Release") == 0) - return release_message(conn, msg, data); + /* Accept messages from the input interface only */ + if (strcmp(INPUT_DEVICE_INTERFACE, iface)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - if (strcmp(interface, "org.bluez.Input") != 0) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (strcmp(member, "Connect") == 0) + return device_connect(conn, msg, data); - /* Handle Input interface methods here */ + if (strcmp(member, "Disconnect") == 0) + return device_disconnect(conn, msg, data); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} + if (strcmp(member, "Unplug") == 0) + return device_unplug(conn, msg, data); -static const DBusObjectPathVTable input_table = { - .message_function = input_message, -}; + if (strcmp(member, "IsConnected") == 0) + return device_is_connected(conn, msg, data); -static void register_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError err; + if (strcmp(member, "GetAddress") == 0) + return device_get_address(conn, msg, data); - dbus_error_init(&err); - if (dbus_set_error_from_message(&err, reply)) { - error("Registering failed: %s", err.message); - dbus_error_free(&err); - raise(SIGTERM); - } - else - debug("Successfully registered"); + if (strcmp(member, "GetName") == 0) + return device_get_name(conn, msg, data); + + if (strcmp(member, "GetProductId") == 0) + return device_get_product_id(conn, msg, data); + + if (strcmp(member, "GetVendorId") == 0) + return device_get_vendor_id(conn, msg, data); + + if (strcmp(member, "SetTimeout") == 0) + return device_set_timeout(conn, msg, data); - dbus_message_unref(reply); + return err_unknown_method(conn, msg); } int input_dbus_init(void) { - DBusMessage *msg; - DBusPendingCall *pending; - const char *name = "Input service"; - const char *description = "A service for input devices"; - const char *input_path = INPUT_PATH; - - connection = init_dbus("org.bluez.input", NULL, NULL); + connection = init_dbus(INPUT_SERVICE, NULL, NULL); if (!connection) return -1; - if (!dbus_connection_register_object_path(connection, input_path, - &input_table, NULL)) { + /* Fallback to catch invalid device path */ + if (!dbus_connection_register_fallback(connection, INPUT_PATH, + &manager_table, NULL)) { error("D-Bus failed to register %s path", INPUT_PATH); return -1; } - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Manager", "RegisterService"); - if (!msg) { - error("Can't allocate new method call"); - return -1; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &input_path, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &description, - DBUS_TYPE_INVALID); - - if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) { - error("Sending Register method call failed"); - dbus_message_unref(msg); - return -1; - } - - dbus_pending_call_set_notify(pending, register_reply, NULL, NULL); - dbus_message_unref(msg); + info("Registered input manager path:%s", INPUT_PATH); return 0; } - -- cgit From c6cd1ad500588247d4293b96db66d7a140ee81ec Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 18 Jan 2007 14:28:18 +0000 Subject: Added unregister code for input manager path --- input/input-service.c | 36 +++++++++++++++++++++++++++++++++++- input/input-service.h | 1 + input/main.c | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 54e745a4..23dbce8b 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -51,11 +51,15 @@ static DBusConnection *connection = NULL; static DBusHandlerResult manager_message(DBusConnection *conn, DBusMessage *msg, void *data); + +static void manager_unregister(DBusConnection *conn, void *data); + static DBusHandlerResult device_message(DBusConnection *conn, DBusMessage *msg, void *data); static const DBusObjectPathVTable manager_table = { .message_function = manager_message, + .unregister_function = manager_unregister, }; static const DBusObjectPathVTable device_table = { @@ -84,6 +88,10 @@ static DBusHandlerResult err_unknown_method(DBusConnection *conn, DBusMessage *m /* * Input Manager methods */ +struct input_manager { + GList *paths; +}; + static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *msg, void *udata) { @@ -131,6 +139,18 @@ static DBusHandlerResult manager_message(DBusConnection *conn, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } +static void manager_unregister(DBusConnection *conn, void *data) +{ + struct input_manager *mgr = data; + + info("Unregistered manager path"); + + if (mgr->paths) + g_list_foreach(mgr->paths, (GFunc) free, NULL); + + free(mgr); +} + /* * Input Device methods */ @@ -233,13 +253,19 @@ static DBusHandlerResult device_message(DBusConnection *conn, int input_dbus_init(void) { + struct input_manager *mgr; connection = init_dbus(INPUT_SERVICE, NULL, NULL); if (!connection) return -1; + dbus_connection_set_exit_on_disconnect(connection, TRUE); + + mgr = malloc(sizeof(struct input_manager)); + memset(mgr, 0, sizeof(struct input_manager)); + /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, - &manager_table, NULL)) { + &manager_table, mgr)) { error("D-Bus failed to register %s path", INPUT_PATH); return -1; } @@ -248,3 +274,11 @@ int input_dbus_init(void) return 0; } + +void input_dbus_exit(void) +{ + dbus_connection_unregister_object_path(connection, INPUT_PATH); + + dbus_connection_unref(connection); +} + diff --git a/input/input-service.h b/input/input-service.h index 6cc0b413..acda934d 100644 --- a/input/input-service.h +++ b/input/input-service.h @@ -25,5 +25,6 @@ #define __INPUT_SERVICE_H int input_dbus_init(void); +void input_dbus_exit(void); #endif /* __INPUT_SERVICE_H */ diff --git a/input/main.c b/input/main.c index 5523b67f..9386caf9 100644 --- a/input/main.c +++ b/input/main.c @@ -102,5 +102,7 @@ int main(int argc, char *argv[]) g_main_run(main_loop); + input_dbus_exit(); + return 0; } -- cgit From d1ae2b4841f2b16f647903ff48bb82f2ee35b167 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 18 Jan 2007 17:02:50 +0000 Subject: Added ListDevices --- input/input-service.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 23dbce8b..9b5dde45 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -107,7 +107,28 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, static DBusHandlerResult manager_list_devices(DBusConnection *conn, DBusMessage *msg, void *udata) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_manager *mgr = udata; + DBusMessageIter iter, iter_array; + DBusMessage *reply; + GList *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, -- cgit From b7781d4cbc0689f30402e685b91f4e1bfbd21ed2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 18 Jan 2007 17:10:29 +0000 Subject: Removed forward declaration and fixed code standard. --- input/input-service.c | 55 ++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 9b5dde45..5dbed3b4 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -49,23 +49,6 @@ static DBusConnection *connection = NULL; -static DBusHandlerResult manager_message(DBusConnection *conn, - DBusMessage *msg, void *data); - -static void manager_unregister(DBusConnection *conn, void *data); - -static DBusHandlerResult device_message(DBusConnection *conn, - DBusMessage *msg, void *data); - -static const DBusObjectPathVTable manager_table = { - .message_function = manager_message, - .unregister_function = manager_unregister, -}; - -static const DBusObjectPathVTable device_table = { - .message_function = device_message, -}; - /* * Common D-Bus BlueZ input error functions */ @@ -93,21 +76,21 @@ struct input_manager { }; static DBusHandlerResult manager_create_device(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult manager_remove_device(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult manager_list_devices(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { - struct input_manager *mgr = udata; + struct input_manager *mgr = data; DBusMessageIter iter, iter_array; DBusMessage *reply; GList *paths; @@ -172,64 +155,69 @@ static void manager_unregister(DBusConnection *conn, void *data) free(mgr); } +/* Virtual table to handle manager object path hierarchy */ +static const DBusObjectPathVTable manager_table = { + .message_function = manager_message, + .unregister_function = manager_unregister, +}; + /* * Input Device methods */ static DBusHandlerResult device_connect(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_disconnect(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_unplug(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_is_connected(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_get_address(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_get_name(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_get_product_id(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_set_timeout(DBusConnection *conn, - DBusMessage *msg, void *udata) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - static DBusHandlerResult device_message(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -272,6 +260,11 @@ static DBusHandlerResult device_message(DBusConnection *conn, return err_unknown_method(conn, msg); } +/* Virtual table to handle device object path hierarchy */ +static const DBusObjectPathVTable device_table = { + .message_function = device_message, +}; + int input_dbus_init(void) { struct input_manager *mgr; -- cgit From fd8be9d63d020165de6b5da67b0f86a5b18f1340 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 18 Jan 2007 17:30:54 +0000 Subject: fixed minor code standard issue --- input/input-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 5dbed3b4..35e5306b 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -99,7 +99,7 @@ static DBusHandlerResult manager_list_devices(DBusConnection *conn, if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; - dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_array); -- cgit From fb0189533b77a5c7d4fb38107096fb2e1b149e15 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 18 Jan 2007 21:43:08 +0000 Subject: Small clenaup to the API definitions --- input/input-api.txt | 45 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index f321ac2b..f63faa38 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -1,56 +1,41 @@ Bluetooth input service API description -****************************************** +*************************************** Copyright (C) 2006-2007 Marcel Holtmann -Error hierarchy -=============== - -Interface org.bluez.Error - -Errors Failed - - An unknown error occured. The error messages is - taken from the strerror(errno) function. - - UnknownDevice - - Error returned when the input device path is invalid - - UnknownMethod - - Error returned when the input device path doesn't - implement the requested method. - Input Manager hierarchy -================= +======================= Service org.bluez.input Interface org.bluez.input.Manager Object path /org/bluez/input -Methods - array{string} ListDevices() +Methods array{string} ListDevices() Returns an array of available input devices path. void CreateDevice(string address) - Create an input device object: HID service record is - retrieved and bonding(if applied) is created. + Create an input device object. The HID service + record will be retrieved and the pairing will + be initiated if needed. void RemoveDevice(string path) Remove the input device object for a given path. +Signals void DeviceCreated(string path) + + void DeviceRemoved(string path) -Input hierarchy -================= + +Input Device hierarchy +====================== Service org.bluez.input -Interface org.bluez.input -Object path /org/bluez/input_* +Interface org.bluez.input.Device +Object path /org/bluez/input/{keyboard*|mouse*|...} Methods string GetAddress() @@ -89,5 +74,3 @@ Methods string GetAddress() void SetTimeout(uint32 timeout) Set the idle timeout. - - -- cgit From d3d68f09fac9d13476b70d67330f5083f60fc1a7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 18 Jan 2007 21:54:03 +0000 Subject: Return the path on device creation --- input/input-api.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index f63faa38..d947d489 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -15,12 +15,15 @@ Methods array{string} ListDevices() Returns an array of available input devices path. - void CreateDevice(string address) + string CreateDevice(string address) Create an input device object. The HID service record will be retrieved and the pairing will be initiated if needed. + On success it will return the path of the + newly created device object. + void RemoveDevice(string path) Remove the input device object for a given path. -- cgit From 87113c3bda9245ad758ce75d8cec04ca303faed3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 19 Jan 2007 16:07:37 +0000 Subject: CreateDevice: initial skeleton --- input/input-service.c | 294 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 223 insertions(+), 71 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 35e5306b..4c2105c4 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -33,6 +33,7 @@ #include "logging.h" #include "input-service.h" #include "glib-ectomy.h" +#include "textfile.h" #include @@ -49,6 +50,25 @@ static DBusConnection *connection = NULL; +struct input_device { + char addr[18]; +}; + +struct input_device *input_device_new(const char *addr) +{ + struct input_device *idev; + + idev = malloc(sizeof(struct input_device)); + if (!idev) + return NULL; + + memset(idev, 0, sizeof(struct input_device)); + + memcpy(idev->addr, addr, 18); + + return idev; +} + /* * Common D-Bus BlueZ input error functions */ @@ -68,98 +88,60 @@ static DBusHandlerResult err_unknown_method(DBusConnection *conn, DBusMessage *m "Unknown input method")); } -/* - * Input Manager methods - */ -struct input_manager { - GList *paths; -}; - -static DBusHandlerResult manager_create_device(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, + const char *str) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".Failed", str)); } -static DBusHandlerResult manager_remove_device(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult err_already_exists(DBusConnection *conn, + DBusMessage *msg, const char *str) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".AlreadyExists", str)); } -static DBusHandlerResult manager_list_devices(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg, + const char *name, const char *str) { - struct input_manager *mgr = data; - DBusMessageIter iter, iter_array; - DBusMessage *reply; - GList *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, + dbus_message_new_error(msg, name, str)); - return send_message_and_unref(conn, reply); } -static DBusHandlerResult manager_message(DBusConnection *conn, - DBusMessage *msg, void *data) +static inline int create_filename(char *buf, size_t size, + bdaddr_t *bdaddr, const char *name) { - const char *path, *iface, *member; + char addr[18]; - 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); + ba2str(bdaddr, addr); - 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; + return create_name(buf, size, STORAGEDIR, addr, name); } -static void manager_unregister(DBusConnection *conn, void *data) +static int has_hid_record(const char *local, const char *peer) { - struct input_manager *mgr = data; + char filename[PATH_MAX + 1], *str; - info("Unregistered manager path"); + create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); - if (mgr->paths) - g_list_foreach(mgr->paths, (GFunc) free, NULL); + str = textfile_get(filename, peer); + if (!str) + return 0; - free(mgr); + free(str); + return 1; } -/* Virtual table to handle manager object path hierarchy */ -static const DBusObjectPathVTable manager_table = { - .message_function = manager_message, - .unregister_function = manager_unregister, -}; +static int search_request(DBusConnection *conn, + DBusMessage *msg, const char *peer) +{ + info("FIXME: service search"); + return 0; +} /* * Input Device methods @@ -260,14 +242,177 @@ static DBusHandlerResult device_message(DBusConnection *conn, return err_unknown_method(conn, msg); } +static DBusHandlerResult device_message(DBusConnection *conn, + DBusMessage *msg, void *data); /* Virtual table to handle device object path hierarchy */ static const DBusObjectPathVTable device_table = { .message_function = device_message, }; +/* + * Input Manager methods + */ +struct input_manager { + char adapter[18]; + GList *paths; +}; + +static int path_addr_cmp(const char *path, const char *addr) +{ + struct input_device *idev; + + if (!dbus_connection_get_object_path_data(connection, path, + (void *) &idev)) + return -1; + + if (!idev) + return -1; + + return strcasecmp(idev->addr, addr); +} + +static DBusHandlerResult manager_create_device(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_manager *mgr = data; + struct input_device *idev; + DBusMessage *reply; + DBusError derr; + const char *addr; + const char *keyb_path = "/org/bluez/input/keyboard0"; + GList *path; + + 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; + } + + path = g_list_find_custom(mgr->paths, addr, + (GCompareFunc) path_addr_cmp); + if (path) + return err_already_exists(conn, msg, "Input Already exists"); + + if (!has_hid_record(mgr->adapter, addr)) { + if (search_request(conn, msg, addr) < 0) + return err_failed(conn, msg, "SDP error"); + + return DBUS_HANDLER_RESULT_HANDLED; + } + + idev = input_device_new(addr); + if (!idev) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(idev); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + if (!dbus_connection_register_object_path(conn, + keyb_path, &device_table, idev)) { + error("Input device path registration failed"); + free(idev); + return err_failed(conn, msg, "Path registration failed"); + } + + mgr->paths = g_list_append(mgr->paths, strdup(keyb_path)); + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &keyb_path, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult manager_remove_device(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult manager_list_devices(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_manager *mgr = data; + DBusMessageIter iter, iter_array; + DBusMessage *reply; + GList *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"); + + if (mgr->paths) + g_list_foreach(mgr->paths, (GFunc) free, NULL); + + free(mgr); +} + +/* Virtual table to handle manager object path hierarchy */ +static const DBusObjectPathVTable manager_table = { + .message_function = manager_message, + .unregister_function = manager_unregister, +}; + int input_dbus_init(void) { struct input_manager *mgr; + bdaddr_t sba; + connection = init_dbus(INPUT_SERVICE, NULL, NULL); if (!connection) return -1; @@ -277,6 +422,13 @@ int input_dbus_init(void) mgr = malloc(sizeof(struct input_manager)); memset(mgr, 0, sizeof(struct input_manager)); + /* Get the local adapter */ + if (hci_devba(0, &sba) < 0) { + error("Can't access local adapter"); + return -1; + } + ba2str(&sba, mgr->adapter); + /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, &manager_table, mgr)) { -- cgit From 4f411bad65f2725f628ea610a49310da97c28d30 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 19 Jan 2007 17:14:41 +0000 Subject: Retrieve the default local adapter --- input/input-service.c | 85 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 11 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 4c2105c4..8ca06ecf 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -254,9 +254,21 @@ static const DBusObjectPathVTable device_table = { */ struct input_manager { char adapter[18]; + char *adapter_path; GList *paths; }; +void input_manager_free(struct input_manager *mgr) +{ + if (!mgr) + return; + if (mgr->paths) + g_list_foreach(mgr->paths, (GFunc) free, NULL); + if (mgr->adapter_path) + free(mgr->adapter_path); + free(mgr); +} + static int path_addr_cmp(const char *path, const char *addr) { struct input_device *idev; @@ -396,10 +408,7 @@ static void manager_unregister(DBusConnection *conn, void *data) info("Unregistered manager path"); - if (mgr->paths) - g_list_foreach(mgr->paths, (GFunc) free, NULL); - - free(mgr); + input_manager_free(mgr); } /* Virtual table to handle manager object path hierarchy */ @@ -411,7 +420,9 @@ static const DBusObjectPathVTable manager_table = { int input_dbus_init(void) { struct input_manager *mgr; - bdaddr_t sba; + DBusMessage *msg, *reply; + DBusError derr; + const char *adapter; connection = init_dbus(INPUT_SERVICE, NULL, NULL); if (!connection) @@ -422,23 +433,75 @@ int input_dbus_init(void) mgr = malloc(sizeof(struct input_manager)); memset(mgr, 0, sizeof(struct input_manager)); - /* Get the local adapter */ - if (hci_devba(0, &sba) < 0) { - error("Can't access local adapter"); - return -1; + /* Get the default adapter path */ + msg = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Manager", "DefaultAdapter"); + + dbus_error_init(&derr); + reply = dbus_connection_send_with_reply_and_block(connection, + msg, -1, &derr); + dbus_message_unref(msg); + + if (!reply) { + error("input init failed: %s (%s)", derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_STRING, &adapter, + DBUS_TYPE_INVALID)) { + error("input init failed: %s (%s)", derr.name, derr.message); + dbus_error_free(&derr); + goto fail; } - ba2str(&sba, mgr->adapter); + + mgr->adapter_path = strdup(adapter); + dbus_message_unref(reply); + + /* Get the adapter address */ + msg = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", "GetAddress"); + + dbus_error_init(&derr); + reply = dbus_connection_send_with_reply_and_block(connection, + msg, -1, &derr); + dbus_message_unref(msg); + + if (!reply) { + error("input init failed: %s (%s)", derr.name, derr.message); + dbus_error_free(&derr); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_STRING, &adapter, + DBUS_TYPE_INVALID)) { + error("input init failed: %s (%s)", derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + strncpy(mgr->adapter, adapter, 18); + dbus_message_unref(reply); + + info("Default adapter: %s (%s)", mgr->adapter_path, mgr->adapter); /* 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); - return -1; + goto fail; } info("Registered input manager path:%s", INPUT_PATH); return 0; +fail: + input_manager_free(mgr); + + return -1; } void input_dbus_exit(void) -- cgit From ed95fffdbb414013f3dd29f8e400b0064f152793 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 19 Jan 2007 18:31:11 +0000 Subject: Added function to search PnP handle --- input/input-service.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 108 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 8ca06ecf..cec55dc2 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -47,13 +47,45 @@ #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" #define INPUT_ERROR_INTERFACE "org.bluez.Error" - static DBusConnection *connection = NULL; struct input_device { char addr[18]; }; +struct pending_req { + char addr[18]; + DBusConnection *conn; + DBusMessage *msg; +}; + +struct pending_req *pending_req_new(DBusConnection *conn, + DBusMessage *msg, const char *addr) +{ + struct pending_req *pr; + pr = malloc(sizeof(struct pending_req)); + if (!pr) + return NULL; + + memset(pr, 0, sizeof(struct pending_req)); + memcpy(pr->addr, addr, 18); + pr->conn = dbus_connection_ref(conn); + pr->msg = dbus_message_ref(msg); + + return pr; +} + +void pending_req_free(struct pending_req *pr) +{ + if (!pr) + return; + if (pr->conn) + dbus_connection_unref(pr->conn); + if (pr->msg) + dbus_message_unref(pr->msg); + free(pr); +} + struct input_device *input_device_new(const char *addr) { struct input_device *idev; @@ -136,13 +168,6 @@ static int has_hid_record(const char *local, const char *peer) return 1; } -static int search_request(DBusConnection *conn, - DBusMessage *msg, const char *peer) -{ - info("FIXME: service search"); - return 0; -} - /* * Input Device methods */ @@ -283,6 +308,72 @@ static int path_addr_cmp(const char *path, const char *addr) return strcasecmp(idev->addr, addr); } +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); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { + + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len == 0) { + /* PnP is optional */ + info("FIXME: PnP is optional, request HID record"); + } else { + /* Request PnP record */ + info("FIXME: Request PnP Record"); + } +fail: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int get_handles(struct input_manager *mgr, struct pending_req *pr, + const char *uuid, DBusPendingCallNotifyFunction cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + const char *paddr; + + msg = dbus_message_new_method_call("org.bluez", mgr->adapter_path, + "org.bluez.Adapter", "GetRemoteServiceHandles"); + if (!msg) + return -1; + + paddr = pr->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, + (DBusFreeFunction) pending_req_free); + dbus_message_unref(msg); + + return 0; +} + static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -292,6 +383,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusError derr; const char *addr; const char *keyb_path = "/org/bluez/input/keyboard0"; + const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; GList *path; dbus_error_init(&derr); @@ -309,8 +401,15 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_already_exists(conn, msg, "Input Already exists"); if (!has_hid_record(mgr->adapter, addr)) { - if (search_request(conn, msg, addr) < 0) + struct pending_req *pr; + pr = pending_req_new(conn, msg, addr); + if (!pr) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (get_handles(mgr, pr, pnp_uuid, pnp_handle_reply) < 0) { + pending_req_free(pr); return err_failed(conn, msg, "SDP error"); + } return DBUS_HANDLER_RESULT_HANDLED; } -- cgit From e989bd9c02eeaeb469061fbf908f67fe279c03f5 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 19 Jan 2007 19:49:47 +0000 Subject: Added function to search HID handle --- input/input-service.c | 118 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 34 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index cec55dc2..9cd6b55f 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -54,13 +54,14 @@ struct input_device { }; struct pending_req { - char addr[18]; + char *adapter_path; + char peer[18]; DBusConnection *conn; DBusMessage *msg; }; -struct pending_req *pending_req_new(DBusConnection *conn, - DBusMessage *msg, const char *addr) +struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, + const char *adapter_path, const char *peer) { struct pending_req *pr; pr = malloc(sizeof(struct pending_req)); @@ -68,7 +69,8 @@ struct pending_req *pending_req_new(DBusConnection *conn, return NULL; memset(pr, 0, sizeof(struct pending_req)); - memcpy(pr->addr, addr, 18); + pr->adapter_path = strdup(adapter_path); + strncpy(pr->peer, peer, 18); pr->conn = dbus_connection_ref(conn); pr->msg = dbus_message_ref(msg); @@ -79,6 +81,8 @@ void pending_req_free(struct pending_req *pr) { if (!pr) return; + if (pr->adapter_path) + free(pr->adapter_path); if (pr->conn) dbus_connection_unref(pr->conn); if (pr->msg) @@ -308,12 +312,41 @@ static int path_addr_cmp(const char *path, const char *addr) return strcasecmp(idev->addr, addr); } -static void pnp_handle_reply(DBusPendingCall *call, void *data) +static int get_handles(struct pending_req *pr, const char *uuid, + DBusPendingCallNotifyFunction cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + const char *paddr; + + msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, + "org.bluez.Adapter", "GetRemoteServiceHandles"); + if (!msg) + return -1; + + paddr = pr->peer; + 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_handle_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; - DBusError derr; uint32_t *phandle; + DBusError derr; int len; dbus_error_init(&derr); @@ -333,45 +366,62 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) } if (len == 0) { - /* PnP is optional */ - info("FIXME: PnP is optional, request HID record"); + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; } else { - /* Request PnP record */ - info("FIXME: Request PnP Record"); + info("FIXME: request HID record"); } + + goto done; fail: + pending_req_free(pr); +done: dbus_message_unref(reply); dbus_pending_call_unref(call); } -static int get_handles(struct input_manager *mgr, struct pending_req *pr, - const char *uuid, DBusPendingCallNotifyFunction cb) +static void pnp_handle_reply(DBusPendingCall *call, void *data) { - DBusMessage *msg; - DBusPendingCall *pending; - const char *paddr; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct pending_req *pr = data; + DBusError derr; + uint32_t *phandle; + const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; + int len; - msg = dbus_message_new_method_call("org.bluez", mgr->adapter_path, - "org.bluez.Adapter", "GetRemoteServiceHandles"); - if (!msg) - return -1; + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } - paddr = pr->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; + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { + + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; } - dbus_pending_call_set_notify(pending, cb, pr, - (DBusFreeFunction) pending_req_free); - dbus_message_unref(msg); + if (len == 0) { + /* PnP is optional: Ignore it and request the HID handle */ + if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + } else { + /* Request PnP record */ + info("FIXME: Request PnP Record"); + } - return 0; + goto done; +fail: + pending_req_free(pr); +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); } static DBusHandlerResult manager_create_device(DBusConnection *conn, @@ -402,11 +452,11 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (!has_hid_record(mgr->adapter, addr)) { struct pending_req *pr; - pr = pending_req_new(conn, msg, addr); + pr = pending_req_new(conn, msg, mgr->adapter_path, addr); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_handles(mgr, pr, pnp_uuid, pnp_handle_reply) < 0) { + if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); return err_failed(conn, msg, "SDP error"); } -- cgit From 2f8c48d48529b951e514be6541f272c0ecca48a7 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 19 Jan 2007 20:58:42 +0000 Subject: Added function to request PnP service record --- input/input-service.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 9cd6b55f..19778c22 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #define INPUT_SERVICE "org.bluez.input" #define INPUT_PATH "/org/bluez/input" @@ -48,6 +50,8 @@ #define INPUT_ERROR_INTERFACE "org.bluez.Error" static DBusConnection *connection = NULL; +const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; +const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; struct input_device { char addr[18]; @@ -58,6 +62,8 @@ struct pending_req { char peer[18]; DBusConnection *conn; DBusMessage *msg; + sdp_record_t *pnp_rec; + sdp_record_t *hid_rec; }; struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, @@ -87,6 +93,10 @@ void pending_req_free(struct pending_req *pr) 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); free(pr); } @@ -312,6 +322,35 @@ static int path_addr_cmp(const char *path, const char *addr) return strcasecmp(idev->addr, addr); } +static int get_record(struct pending_req *pr, uint32_t handle, + DBusPendingCallNotifyFunction cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + const char *paddr; + + msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, + "org.bluez.Adapter", "GetRemoteServiceRecord"); + if (!msg) + return -1; + + paddr = pr->peer; + 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) { @@ -380,13 +419,52 @@ done: 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; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len != 0) { + int scanned; + pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); + if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) + error("HID record search error"); + else + goto done; + } + err_failed(pr->conn, pr->msg, "SDP error"); +fail: + 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; - const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; int len; dbus_error_init(&derr); @@ -413,7 +491,10 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) } } else { /* Request PnP record */ - info("FIXME: Request PnP Record"); + if (get_record(pr, *phandle, pnp_record_reply) < 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } } goto done; @@ -433,7 +514,6 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusError derr; const char *addr; const char *keyb_path = "/org/bluez/input/keyboard0"; - const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; GList *path; dbus_error_init(&derr); -- cgit From 4f2bc2345b99c4d0c187aae4f68f4509e50826a5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 19 Jan 2007 21:04:35 +0000 Subject: Rename daemon --- input/Makefile.am | 6 +++--- input/main.c | 10 +--------- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index cafc03a6..92652711 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -13,11 +13,11 @@ glib_cflags = glib_ldadd = endif -noinst_PROGRAMS = bt.inputd +noinst_PROGRAMS = bluetoothd_input -bt_inputd_SOURCES = main.c input-service.h input-service.c +bluetoothd_input_SOURCES = main.c input-service.h input-service.c -bt_inputd_LDADD = $(glib_ldadd) @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a +bluetoothd_input_LDADD = $(glib_ldadd) @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ $(glib_cflags) diff --git a/input/main.c b/input/main.c index 9386caf9..ad35c32e 100644 --- a/input/main.c +++ b/input/main.c @@ -44,13 +44,6 @@ static GMainLoop *main_loop; -static void usage(void) -{ - printf("bt.inputd - Bluetooth Input daemon ver %s\n", VERSION); - printf("Usage: \n"); - printf("\tbt.inputd [-n not_daemon]\n"); -} - static void sig_term(int sig) { g_main_quit(main_loop); @@ -68,7 +61,6 @@ int main(int argc, char *argv[]) break; default: - usage(); exit(1); } } @@ -78,7 +70,7 @@ int main(int argc, char *argv[]) exit(1); } - start_logging("bt.inputd", "Bluetooth Input daemon"); + start_logging("input", "Bluetooth Input daemon"); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; -- cgit From b820ab01df064df0c5e2936e78c8765a3eb6e446 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 19 Jan 2007 21:12:49 +0000 Subject: Added function to request the HID record --- input/input-service.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 19778c22..70d2a3f3 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -380,6 +380,42 @@ static int get_handles(struct pending_req *pr, const char *uuid, return 0; } +static void hid_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); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len == 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + + pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); + /* FIXME: parse SDP records */ +fail: + 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); @@ -404,14 +440,13 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) goto fail; } - if (len == 0) { - err_failed(pr->conn, pr->msg, "SDP error"); - goto fail; - } else { - info("FIXME: request HID record"); + if (len != 0) { + if (get_record(pr, *phandle, hid_record_reply) < 0) + error("HID record search error"); + else + goto done; } - - goto done; + err_failed(pr->conn, pr->msg, "SDP error"); fail: pending_req_free(pr); done: @@ -458,7 +493,6 @@ done: dbus_pending_call_unref(call); } - static void pnp_handle_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); -- cgit From 23875e5b1b633dcfddfe7cbc560d25e306bc9e41 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 19 Jan 2007 21:40:33 +0000 Subject: Rename service and install it --- input/Makefile.am | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 92652711..71beb94e 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -5,6 +5,8 @@ dbusdir = $(sysconfdir)/dbus-1/system.d dbus_DATA = bluetooth-input.conf endif +servicedir = $(libdir)/bluetooth + if GLIB glib_cflags = @GLIB_CFLAGS@ glib_ldadd = @GLIB_LIBS@ @@ -13,11 +15,13 @@ glib_cflags = glib_ldadd = endif -noinst_PROGRAMS = bluetoothd_input +service_PROGRAMS = bluetoothd-service-input -bluetoothd_input_SOURCES = main.c input-service.h input-service.c +bluetoothd_service_input_SOURCES = \ + main.c input-service.h input-service.c -bluetoothd_input_LDADD = $(glib_ldadd) @DBUS_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a +LDADD = $(top_builddir)/common/libhelper.a $(glib_ldadd) \ + @DBUS_LIBS@ @BLUEZ_LIBS@ AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ $(glib_cflags) -- cgit From e36b830e0b772a0ccba8275e634b624217b37577 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 19 Jan 2007 22:11:39 +0000 Subject: Don't become a daemon --- input/main.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index ad35c32e..df1eee9e 100644 --- a/input/main.c +++ b/input/main.c @@ -32,7 +32,6 @@ #include #include #include -#include #include @@ -52,23 +51,6 @@ static void sig_term(int sig) int main(int argc, char *argv[]) { struct sigaction sa; - int opt, daemonize = 1; - - while ((opt = getopt(argc, argv, "n")) != EOF) { - switch (opt) { - case 'n': - daemonize = 0; - break; - - default: - exit(1); - } - } - - if (daemonize && daemon(0, 0)) { - error("Can't daemonize: %s (%d)", strerror(errno), errno); - exit(1); - } start_logging("input", "Bluetooth Input daemon"); -- cgit From 884cfe825db1a0e8c98aa6a604fd4588a1de1340 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 20 Jan 2007 02:36:57 +0000 Subject: Don't install services that are in experimental state --- input/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 71beb94e..e9efa972 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -15,7 +15,7 @@ glib_cflags = glib_ldadd = endif -service_PROGRAMS = bluetoothd-service-input +noinst_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = \ main.c input-service.h input-service.c -- cgit From 8cc5595d9091b484b9a4abe314c0f3ec055e0581 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 20 Jan 2007 05:26:15 +0000 Subject: Make it possible to support an embedded GLib --- input/Makefile.am | 14 +++----------- input/input-service.c | 29 +++++++++++++++-------------- input/main.c | 9 +++++---- 3 files changed, 23 insertions(+), 29 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index e9efa972..6565d8c1 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -7,23 +7,15 @@ endif servicedir = $(libdir)/bluetooth -if GLIB -glib_cflags = @GLIB_CFLAGS@ -glib_ldadd = @GLIB_LIBS@ -else -glib_cflags = -glib_ldadd = -endif - noinst_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = \ main.c input-service.h input-service.c -LDADD = $(top_builddir)/common/libhelper.a $(glib_ldadd) \ - @DBUS_LIBS@ @BLUEZ_LIBS@ +LDADD = $(top_builddir)/common/libhelper.a \ + @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ -AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ $(glib_cflags) +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ INCLUDES = -I$(top_srcdir)/common diff --git a/input/input-service.c b/input/input-service.c index 70d2a3f3..5b9f5204 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -29,20 +29,21 @@ #include #include -#include "dbus.h" -#include "logging.h" -#include "input-service.h" -#include "glib-ectomy.h" -#include "textfile.h" - -#include - #include #include #include #include #include +#include + +#include + +#include "dbus.h" +#include "logging.h" +#include "textfile.h" +#include "input-service.h" + #define INPUT_SERVICE "org.bluez.input" #define INPUT_PATH "/org/bluez/input" #define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" @@ -294,7 +295,7 @@ static const DBusObjectPathVTable device_table = { struct input_manager { char adapter[18]; char *adapter_path; - GList *paths; + GSList *paths; }; void input_manager_free(struct input_manager *mgr) @@ -302,7 +303,7 @@ void input_manager_free(struct input_manager *mgr) if (!mgr) return; if (mgr->paths) - g_list_foreach(mgr->paths, (GFunc) free, NULL); + g_slist_foreach(mgr->paths, (GFunc) free, NULL); if (mgr->adapter_path) free(mgr->adapter_path); free(mgr); @@ -548,7 +549,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusError derr; const char *addr; const char *keyb_path = "/org/bluez/input/keyboard0"; - GList *path; + GSList *path; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -559,7 +560,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - path = g_list_find_custom(mgr->paths, addr, + path = g_slist_find_custom(mgr->paths, addr, (GCompareFunc) path_addr_cmp); if (path) return err_already_exists(conn, msg, "Input Already exists"); @@ -595,7 +596,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_failed(conn, msg, "Path registration failed"); } - mgr->paths = g_list_append(mgr->paths, strdup(keyb_path)); + mgr->paths = g_slist_append(mgr->paths, strdup(keyb_path)); dbus_message_append_args(reply, DBUS_TYPE_STRING, &keyb_path, DBUS_TYPE_INVALID); @@ -615,7 +616,7 @@ static DBusHandlerResult manager_list_devices(DBusConnection *conn, struct input_manager *mgr = data; DBusMessageIter iter, iter_array; DBusMessage *reply; - GList *paths; + GSList *paths; reply = dbus_message_new_method_return(msg); if (!reply) diff --git a/input/main.c b/input/main.c index df1eee9e..e74c4482 100644 --- a/input/main.c +++ b/input/main.c @@ -35,9 +35,10 @@ #include +#include + #include "dbus.h" #include "logging.h" -#include "glib-ectomy.h" #include "input-service.h" @@ -45,7 +46,7 @@ static GMainLoop *main_loop; static void sig_term(int sig) { - g_main_quit(main_loop); + g_main_loop_quit(main_loop); } int main(int argc, char *argv[]) @@ -67,14 +68,14 @@ int main(int argc, char *argv[]) enable_debug(); /* Create event loop */ - main_loop = g_main_new(FALSE); + main_loop = g_main_loop_new(NULL, FALSE); if (input_dbus_init() < 0) { error("Unable to get on D-Bus"); exit(1); } - g_main_run(main_loop); + g_main_loop_run(main_loop); input_dbus_exit(); -- cgit From 818744abec2065fd03ee872b671bb21ff2957ac9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 20 Jan 2007 14:30:42 +0000 Subject: Don't use a D-Bus well known name at the moment --- input/Makefile.am | 8 +------- input/bluetooth-input.conf | 21 --------------------- input/input-service.c | 3 +-- 3 files changed, 2 insertions(+), 30 deletions(-) delete mode 100644 input/bluetooth-input.conf (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 6565d8c1..80428b0a 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -1,10 +1,4 @@ -if CONFIGFILES -dbusdir = $(sysconfdir)/dbus-1/system.d - -dbus_DATA = bluetooth-input.conf -endif - servicedir = $(libdir)/bluetooth noinst_PROGRAMS = bluetoothd-service-input @@ -19,6 +13,6 @@ AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ INCLUDES = -I$(top_srcdir)/common -EXTRA_DIST = bluetooth-input.conf +EXTRA_DIST = input-api.txt MAINTAINERCLEANFILES = Makefile.in diff --git a/input/bluetooth-input.conf b/input/bluetooth-input.conf deleted file mode 100644 index 90643f74..00000000 --- a/input/bluetooth-input.conf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/input/input-service.c b/input/input-service.c index 5b9f5204..fcb18352 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -44,7 +44,6 @@ #include "textfile.h" #include "input-service.h" -#define INPUT_SERVICE "org.bluez.input" #define INPUT_PATH "/org/bluez/input" #define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -688,7 +687,7 @@ int input_dbus_init(void) DBusError derr; const char *adapter; - connection = init_dbus(INPUT_SERVICE, NULL, NULL); + connection = init_dbus(NULL, NULL, NULL); if (!connection) return -1; -- cgit From e9cc32a5d3d130cf564853928c6ed77f164999fc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 20 Jan 2007 15:06:03 +0000 Subject: Add service description file --- input/Makefile.am | 2 +- input/input.service | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 input/input.service (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 80428b0a..72f95dca 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -13,6 +13,6 @@ AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ INCLUDES = -I$(top_srcdir)/common -EXTRA_DIST = input-api.txt +EXTRA_DIST = input.service input-api.txt MAINTAINERCLEANFILES = Makefile.in diff --git a/input/input.service b/input/input.service new file mode 100644 index 00000000..f5a105f8 --- /dev/null +++ b/input/input.service @@ -0,0 +1,5 @@ +[Bluetooth Service] +Identifier=input +Name=Input service +Description=Bluetooth HID based Input service +Autostart=true -- cgit From 01c923cbee582b959e2af54364f3d0cf299e5793 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sat, 20 Jan 2007 21:47:30 +0000 Subject: Added function to create the input device D-Bus path --- input/input-service.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index fcb18352..185d915e 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -182,6 +182,55 @@ static int has_hid_record(const char *local, const char *peer) return 1; } +static const char *create_input_path(uint8_t minor) +{ + static char path[48]; + char subpath[32]; + static int next_id = 0; + + switch (minor & 0xc0) { + case 0x40: + strcpy(subpath, "keyboard"); + break; + case 0x80: + strcpy(subpath, "pointing"); + break; + case 0xc0: + strcpy(subpath, "combo"); + break; + } + + if ((minor & 0x3f) && (strlen(subpath) > 0)) + strcat(subpath, "/"); + + switch (minor & 0x3f) { + case 0x01: + strcat(subpath, "joystick"); + break; + case 0x02: + strcat(subpath, "gamepad"); + break; + case 0x03: + strcat(subpath, "remotecontrol"); + break; + case 0x04: + strcat(subpath, "sensing"); + break; + case 0x05: + strcat(subpath, "digitizertablet"); + break; + case 0x06: + strcat(subpath, "cardreader"); + break; + default: + strcat(subpath, "reserved"); + break; + } + + snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++); + return path; +} + /* * Input Device methods */ @@ -547,7 +596,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *reply; DBusError derr; const char *addr; - const char *keyb_path = "/org/bluez/input/keyboard0"; + const char *keyb_path; GSList *path; dbus_error_init(&derr); @@ -588,6 +637,8 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; } + /* FIXME: use HIDDeviceSubclass HID record attribute*/ + keyb_path = create_input_path(0x40); if (!dbus_connection_register_object_path(conn, keyb_path, &device_table, idev)) { error("Input device path registration failed"); -- cgit From 72d07f466c8178d6cfe697ccf2ae8d46a5b19a45 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sun, 21 Jan 2007 21:08:54 +0000 Subject: Added function to parse the HID and PnP record --- input/input-service.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 185d915e..7ce27518 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -182,6 +183,75 @@ static int has_hid_record(const char *local, const char *peer) return 1; } +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, 0x0201); + req->parser = pdlist ? pdlist->val.uint16 : 0x0100; + + pdlist = sdp_data_get(rec, 0x0202); + req->subclass = pdlist ? pdlist->val.uint8 : 0; + + pdlist = sdp_data_get(rec, 0x0203); + req->country = pdlist ? pdlist->val.uint8 : 0; + + pdlist = sdp_data_get(rec, 0x0204); + attr_val = pdlist ? pdlist->val.uint8 : 0; + if (attr_val) + req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); + + pdlist = sdp_data_get(rec, 0x020E); + attr_val = pdlist ? pdlist->val.uint8 : 0; + if (attr_val) + req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); + + pdlist = sdp_data_get(rec, 0x0206); + if (pdlist) { + pdlist = pdlist->val.dataseq; + pdlist = pdlist->val.dataseq; + pdlist = pdlist->next; + + req->rd_data = malloc(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, 0x0201); + req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; + + pdlist = sdp_data_get(rec, 0x0202); + req->product = pdlist ? pdlist->val.uint16 : 0x0000; + + pdlist = sdp_data_get(rec, 0x0203); + req->version = pdlist ? pdlist->val.uint16 : 0x0000; +} + static const char *create_input_path(uint8_t minor) { static char path[48]; @@ -433,6 +503,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; + struct hidp_connadd_req req; DBusError derr; uint8_t *rec_bin; int len, scanned; @@ -458,7 +529,14 @@ static void hid_record_reply(DBusPendingCall *call, void *data) } pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); - /* FIXME: parse SDP records */ + memset(&req, 0, sizeof(struct hidp_connadd_req)); + if (pr->hid_rec) + extract_hid_record(pr->hid_rec, &req); + if (pr->pnp_rec) + extract_pnp_record(pr->pnp_rec, &req); + + /* FIXME: Register the Input device path */ + /* FIXME: Store HID record data and free req */ fail: pending_req_free(pr); dbus_message_unref(reply); -- cgit From 3067733e2e0d88f8e181d30a4727d8fe798e7965 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 21 Jan 2007 21:16:23 +0000 Subject: Do a proper cleanup on exit --- input/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'input') diff --git a/input/main.c b/input/main.c index e74c4482..bc7eb8e7 100644 --- a/input/main.c +++ b/input/main.c @@ -79,5 +79,11 @@ int main(int argc, char *argv[]) input_dbus_exit(); + g_main_loop_unref(main_loop); + + info("Exit"); + + stop_logging(); + return 0; } -- cgit From 0d7b614648f2170aa66c799e0f3a4ea62a59c9d9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 21 Jan 2007 21:20:08 +0000 Subject: Don't request default adapter --- input/input-service.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 7ce27518..975bed81 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -812,9 +812,11 @@ static const DBusObjectPathVTable manager_table = { int input_dbus_init(void) { struct input_manager *mgr; +#if 0 DBusMessage *msg, *reply; DBusError derr; const char *adapter; +#endif connection = init_dbus(NULL, NULL, NULL); if (!connection) @@ -825,6 +827,7 @@ int input_dbus_init(void) mgr = malloc(sizeof(struct input_manager)); memset(mgr, 0, sizeof(struct input_manager)); +#if 0 /* Get the default adapter path */ msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Manager", "DefaultAdapter"); @@ -879,6 +882,7 @@ int input_dbus_init(void) dbus_message_unref(reply); info("Default adapter: %s (%s)", mgr->adapter_path, mgr->adapter); +#endif /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, @@ -902,4 +906,3 @@ void input_dbus_exit(void) dbus_connection_unref(connection); } - -- cgit From ea16654e9f78891fabb4257b3ae88fd1c2991aaf Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sun, 21 Jan 2007 22:34:10 +0000 Subject: Fixed input device D-Bus path creation error --- input/input-service.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 975bed81..48a76baf 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -274,6 +274,8 @@ static const char *create_input_path(uint8_t minor) strcat(subpath, "/"); switch (minor & 0x3f) { + case 0x00: + break; case 0x01: strcat(subpath, "joystick"); break; -- cgit From 72217a2993a6ef3d252e0f3fdafa78bb1726b705 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 21 Jan 2007 23:23:19 +0000 Subject: Add skeleton for server handling --- input/Makefile.am | 3 +- input/main.c | 6 ++- input/server.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ input/server.h | 25 ++++++++++ 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 input/server.c create mode 100644 input/server.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 72f95dca..7716bec6 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -4,7 +4,8 @@ servicedir = $(libdir)/bluetooth noinst_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = \ - main.c input-service.h input-service.c + main.c server.h server.c \ + input-service.h input-service.c LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ diff --git a/input/main.c b/input/main.c index bc7eb8e7..82e3b1b6 100644 --- a/input/main.c +++ b/input/main.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2005-2006 Marcel Holtmann + * Copyright (C) 2004-2007 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify @@ -75,8 +75,12 @@ int main(int argc, char *argv[]) exit(1); } + server_start(); + g_main_loop_run(main_loop); + server_stop(); + input_dbus_exit(); g_main_loop_unref(main_loop); diff --git a/input/server.c b/input/server.c new file mode 100644 index 00000000..0725d0de --- /dev/null +++ b/input/server.c @@ -0,0 +1,134 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include + +#include "logging.h" +#include "server.h" + +static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + if (cond & (G_IO_HUP | G_IO_ERR)) + return FALSE; + + debug("Incoming data session"); + + return FALSE; +} + +static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + GIOChannel *io; + struct sockaddr_l2 addr; + socklen_t optlen; + int sk, nsk; + + sk = g_io_channel_unix_get_fd(chan); + + memset(&addr, 0, sizeof(addr)); + optlen = sizeof(addr); + + nsk = accept(sk, (struct sockaddr *) &addr, &optlen); + if (nsk < 0) + return TRUE; + + io = g_io_channel_unix_new(nsk); + g_io_channel_set_close_on_unref(io, TRUE); + + g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR, + session_event, NULL); + + g_io_channel_unref(io); + + return TRUE; +} + +static GIOChannel *setup_l2cap(unsigned int psm) +{ + GIOChannel *io; + struct sockaddr_l2 addr; + int sk; + + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (sk < 0) + return NULL; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, BDADDR_ANY); + addr.l2_psm = htobs(psm); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(sk); + return NULL; + } + + if (listen(sk, 10) < 0) { + close(sk); + return NULL; + } + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, TRUE); + + g_io_add_watch(io, G_IO_IN, connect_event, NULL); + + return io; +} + +static GIOChannel *ctrl_io = NULL; +static GIOChannel *intr_io = NULL; + +int server_start(void) +{ + ctrl_io = setup_l2cap(17); + if (!ctrl_io) + return -1; + + intr_io = setup_l2cap(19); + if (!intr_io) { + g_io_channel_unref(ctrl_io); + ctrl_io = NULL; + } + + return 0; +} + +void server_stop(void) +{ + if (intr_io) + g_io_channel_unref(intr_io); + + if (ctrl_io) + g_io_channel_unref(ctrl_io); +} diff --git a/input/server.h b/input/server.h new file mode 100644 index 00000000..f0237d4f --- /dev/null +++ b/input/server.h @@ -0,0 +1,25 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +int server_start(void); +void server_stop(void); -- cgit From 65ce50f3aeceec265ee45388c96344f037db43e9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 22 Jan 2007 00:00:50 +0000 Subject: Include server.h header file --- input/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'input') diff --git a/input/main.c b/input/main.c index 82e3b1b6..bb8759a7 100644 --- a/input/main.c +++ b/input/main.c @@ -40,6 +40,7 @@ #include "dbus.h" #include "logging.h" +#include "server.h" #include "input-service.h" static GMainLoop *main_loop; -- cgit From 512e954ad4c9ac938a0f1302a92b36d532725ff3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 00:05:47 +0000 Subject: Created function to register the input device D-Bus path and send the DeviceCreated signal --- input/input-service.c | 92 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 18 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 48a76baf..3c346033 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -56,6 +56,7 @@ const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; struct input_device { char addr[18]; + struct hidp_connadd_req hidp; }; struct pending_req { @@ -116,6 +117,15 @@ struct input_device *input_device_new(const char *addr) return idev; } +void input_device_free(struct input_device *idev) +{ + if (!idev) + return; + if (idev->hidp.rd_data) + free(idev->hidp.rd_data); + free(idev); +} + /* * Common D-Bus BlueZ input error functions */ @@ -429,6 +439,35 @@ void input_manager_free(struct input_manager *mgr) free(mgr); } +static int register_input_device(DBusConnection *conn, + struct input_device *idev, const char *path) +{ + DBusMessage *msg; + struct input_manager *mgr; + + if (!dbus_connection_register_object_path(conn, + 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, 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_INVALID); + + send_message_and_unref(conn, msg); + + return 0; +} + static int path_addr_cmp(const char *path, const char *addr) { struct input_device *idev; @@ -504,10 +543,12 @@ static int get_handles(struct pending_req *pr, const char *uuid, 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 hidp_connadd_req req; + struct input_device *idev; DBusError derr; uint8_t *rec_bin; + const char *path; int len, scanned; dbus_error_init(&derr); @@ -531,13 +572,31 @@ static void hid_record_reply(DBusPendingCall *call, void *data) } pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); - memset(&req, 0, sizeof(struct hidp_connadd_req)); - if (pr->hid_rec) - extract_hid_record(pr->hid_rec, &req); + if (!pr->hid_rec) { + err_failed(pr->conn, pr->msg, "HID not supported"); + goto fail; + } + + idev = input_device_new(pr->peer); + + extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) - extract_pnp_record(pr->pnp_rec, &req); + extract_pnp_record(pr->pnp_rec, &idev->hidp); + + path = create_input_path(idev->hidp.subclass); + + 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); - /* FIXME: Register the Input device path */ /* FIXME: Store HID record data and free req */ fail: pending_req_free(pr); @@ -693,6 +752,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (path) return err_already_exists(conn, msg, "Input Already exists"); + /* FIXME: Retrieve the stored data instead of only check if it exists */ if (!has_hid_record(mgr->adapter, addr)) { struct pending_req *pr; pr = pending_req_new(conn, msg, mgr->adapter_path, addr); @@ -711,22 +771,18 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(idev); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - /* FIXME: use HIDDeviceSubclass HID record attribute*/ keyb_path = create_input_path(0x40); - if (!dbus_connection_register_object_path(conn, - keyb_path, &device_table, idev)) { - error("Input device path registration failed"); - free(idev); - return err_failed(conn, msg, "Path registration failed"); + if (register_input_device(conn, idev, keyb_path) < 0) { + input_device_free(idev); + return err_failed(conn, msg, "D-Bus path registration failed"); } - mgr->paths = g_slist_append(mgr->paths, strdup(keyb_path)); + reply = dbus_message_new_method_return(msg); + if (!reply) { + input_device_free(idev); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } dbus_message_append_args(reply, DBUS_TYPE_STRING, &keyb_path, DBUS_TYPE_INVALID); -- cgit From 90d8e71b0fed203fcc2defe97ee7c1a8c6207772 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 22 Jan 2007 03:23:32 +0000 Subject: Re-activate getting the default adapter --- input/input-service.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 3c346033..946d9cc1 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -870,11 +870,9 @@ static const DBusObjectPathVTable manager_table = { int input_dbus_init(void) { struct input_manager *mgr; -#if 0 DBusMessage *msg, *reply; DBusError derr; const char *adapter; -#endif connection = init_dbus(NULL, NULL, NULL); if (!connection) @@ -885,7 +883,6 @@ int input_dbus_init(void) mgr = malloc(sizeof(struct input_manager)); memset(mgr, 0, sizeof(struct input_manager)); -#if 0 /* Get the default adapter path */ msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Manager", "DefaultAdapter"); @@ -940,7 +937,6 @@ int input_dbus_init(void) dbus_message_unref(reply); info("Default adapter: %s (%s)", mgr->adapter_path, mgr->adapter); -#endif /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, -- cgit From e248da53cf9d33f7a4c3710d7688d240b8aea3a6 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 13:58:53 +0000 Subject: Added DeviceRemove method --- input/input-service.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 946d9cc1..4132f72a 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -161,6 +161,14 @@ static DBusHandlerResult err_already_exists(DBusConnection *conn, 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) { @@ -412,11 +420,15 @@ static DBusHandlerResult device_message(DBusConnection *conn, return err_unknown_method(conn, msg); } -static DBusHandlerResult device_message(DBusConnection *conn, - DBusMessage *msg, void *data); +static void device_unregister(DBusConnection *conn, void *data) +{ + input_device_free(data); +} + /* Virtual table to handle device object path hierarchy */ static const DBusObjectPathVTable device_table = { .message_function = device_message, + .unregister_function = device_unregister, }; /* @@ -468,6 +480,29 @@ static int register_input_device(DBusConnection *conn, return 0; } +static int unregister_input_device(DBusConnection *conn, const char *path) +{ + DBusMessage *msg; + + if (!dbus_connection_unregister_object_path(conn, path)) { + error("Input device path unregister failed"); + return -1; + } + + msg = dbus_message_new_signal(INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceRemoved"); + if (!msg) + return -1; + + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + send_message_and_unref(conn, msg); + + return 0; +} + static int path_addr_cmp(const char *path, const char *addr) { struct input_device *idev; @@ -793,7 +828,37 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, static DBusHandlerResult manager_remove_device(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + 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; + + if (unregister_input_device(conn, path) < 0) { + dbus_message_unref(reply); + return err_failed(conn, msg, "D-Bus path unregistration failed"); + } + + mgr->paths = g_slist_remove(mgr->paths, l->data); + + return send_message_and_unref(conn, reply); } static DBusHandlerResult manager_list_devices(DBusConnection *conn, -- cgit From 1f07bf88cffbd3fedcfde3391746a3f6fb0cac48 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 14:05:09 +0000 Subject: CreateDevice: minor code standard changes --- input/input-service.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 4132f72a..8840754a 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -769,9 +769,8 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, struct input_device *idev; DBusMessage *reply; DBusError derr; - const char *addr; - const char *keyb_path; - GSList *path; + const char *addr, *path; + GSList *l; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -782,9 +781,9 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - path = g_slist_find_custom(mgr->paths, addr, + l = g_slist_find_custom(mgr->paths, addr, (GCompareFunc) path_addr_cmp); - if (path) + if (l) return err_already_exists(conn, msg, "Input Already exists"); /* FIXME: Retrieve the stored data instead of only check if it exists */ @@ -807,8 +806,8 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; /* FIXME: use HIDDeviceSubclass HID record attribute*/ - keyb_path = create_input_path(0x40); - if (register_input_device(conn, idev, keyb_path) < 0) { + path = create_input_path(0x40); + if (register_input_device(conn, idev, path) < 0) { input_device_free(idev); return err_failed(conn, msg, "D-Bus path registration failed"); } @@ -819,7 +818,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; } dbus_message_append_args(reply, - DBUS_TYPE_STRING, &keyb_path, + DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply); -- cgit From 3bb4d3dea5977d127737a3485842350ae7268818 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 14:48:00 +0000 Subject: Added function to retrive the stored HID data --- input/input-service.c | 68 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 13 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 8840754a..dde8f31c 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -187,18 +187,59 @@ static inline int create_filename(char *buf, size_t size, return create_name(buf, size, STORAGEDIR, addr, name); } -static int has_hid_record(const char *local, const char *peer) +/* FIXME: copied from hidd, move to a common library */ +static int get_stored_info(const char *local, const char *peer, + struct hidp_connadd_req *req) { - char filename[PATH_MAX + 1], *str; + char filename[PATH_MAX + 1], tmp[3], *str, *desc; + unsigned int vendor, product, version, subclass, country, parser, pos; + int i; + + desc = malloc(4096); + if (!desc) + return -ENOMEM; + + memset(desc, 0, 4096); create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); str = textfile_get(filename, peer); - if (!str) - return 0; + if (!str) { + free(desc); + return -ENOENT; + } + + sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", + &vendor, &product, &version, &subclass, &country, + &parser, desc, &req->flags, &pos); free(str); - return 1; + + req->vendor = vendor; + req->product = product; + req->version = version; + req->subclass = subclass; + req->country = country; + req->parser = parser; + + snprintf(req->name, 128, str + pos); + + req->rd_size = strlen(desc) / 2; + req->rd_data = malloc(req->rd_size); + if (!req->rd_data) { + free(desc); + return -ENOMEM; + } + + memset(tmp, 0, sizeof(tmp)); + for (i = 0; i < req->rd_size; i++) { + memcpy(tmp, desc + (i * 2), 2); + req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); + } + + free(desc); + + return 0; } static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) @@ -786,9 +827,15 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (l) return err_already_exists(conn, msg, "Input Already exists"); - /* FIXME: Retrieve the stored data instead of only check if it exists */ - if (!has_hid_record(mgr->adapter, addr)) { + idev = input_device_new(addr); + if (!idev) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (get_stored_info(mgr->adapter, addr, &idev->hidp) < 0) { struct pending_req *pr; + + /* Data not found: create the input device later */ + input_device_free(idev); pr = pending_req_new(conn, msg, mgr->adapter_path, addr); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -801,12 +848,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - idev = input_device_new(addr); - if (!idev) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - /* FIXME: use HIDDeviceSubclass HID record attribute*/ - path = create_input_path(0x40); + path = create_input_path(idev->hidp.subclass); if (register_input_device(conn, idev, path) < 0) { input_device_free(idev); return err_failed(conn, msg, "D-Bus path registration failed"); -- cgit From 58c5351058c5741ae1af68bb3e94ae66ebfb6d59 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 14:59:35 +0000 Subject: Removed mem leak(input paths) --- input/input-service.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index dde8f31c..9518b7ee 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -485,8 +485,10 @@ void input_manager_free(struct input_manager *mgr) { if (!mgr) return; - if (mgr->paths) + if (mgr->paths) { g_slist_foreach(mgr->paths, (GFunc) free, NULL); + g_slist_free(mgr->paths); + } if (mgr->adapter_path) free(mgr->adapter_path); free(mgr); @@ -897,6 +899,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, return err_failed(conn, msg, "D-Bus path unregistration failed"); } + free(l->data); mgr->paths = g_slist_remove(mgr->paths, l->data); return send_message_and_unref(conn, reply); -- cgit From a00358121e25b11f1a3540534e2240c12e8763c9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 20:21:10 +0000 Subject: Register well known(stored) inputs when the daemon starts --- input/input-service.c | 66 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 13 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 9518b7ee..377f47e2 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -187,11 +187,9 @@ static inline int create_filename(char *buf, size_t size, return create_name(buf, size, STORAGEDIR, addr, name); } -/* FIXME: copied from hidd, move to a common library */ -static int get_stored_info(const char *local, const char *peer, - struct hidp_connadd_req *req) +static int parse_stored_info(const char *str, struct hidp_connadd_req *req) { - char filename[PATH_MAX + 1], tmp[3], *str, *desc; + char tmp[3], *desc; unsigned int vendor, product, version, subclass, country, parser, pos; int i; @@ -201,20 +199,11 @@ static int get_stored_info(const char *local, const char *peer, memset(desc, 0, 4096); - create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); - - str = textfile_get(filename, peer); - if (!str) { - free(desc); - return -ENOENT; - } sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", &vendor, &product, &version, &subclass, &country, &parser, desc, &req->flags, &pos); - free(str); - req->vendor = vendor; req->product = product; req->version = version; @@ -242,6 +231,26 @@ static int get_stored_info(const char *local, const char *peer, return 0; } +/* FIXME: copied from hidd, move to a common library */ +static int get_stored_info(const char *local, const char *peer, + struct hidp_connadd_req *req) +{ + char filename[PATH_MAX + 1], *str; + int ret; + + create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); + + str = textfile_get(filename, peer); + if (!str) + return -ENOENT; + + ret = parse_stored_info(str, req); + + free(str); + + return ret; +} + static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist, *pdlist2; @@ -520,6 +529,8 @@ static int register_input_device(DBusConnection *conn, send_message_and_unref(conn, msg); + info("Created input device: %s", path); + return 0; } @@ -976,6 +987,33 @@ static const DBusObjectPathVTable manager_table = { .unregister_function = manager_unregister, }; +static void stored_input(char *key, char *value, void *data) +{ + DBusConnection *conn = data; + struct input_device *idev; + const char *path; + + idev = input_device_new(key); + if (parse_stored_info(value, &idev->hidp) < 0) { + input_device_free(idev); + return; + } + + path = create_input_path(idev->hidp.subclass); + if (register_input_device(conn, idev, path) < 0) + input_device_free(idev); +} + +static int register_stored_inputs(DBusConnection *conn, const char *local) +{ + char filename[PATH_MAX + 1]; + + create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); + textfile_foreach(filename, stored_input, conn); + + return 0; +} + int input_dbus_init(void) { struct input_manager *mgr; @@ -1056,6 +1094,8 @@ int input_dbus_init(void) info("Registered input manager path:%s", INPUT_PATH); + register_stored_inputs(connection, mgr->adapter); + return 0; fail: input_manager_free(mgr); -- cgit From 339f5da8b617ade7dee7b57a3edb9800fd95275d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 20:32:35 +0000 Subject: Added GetAddress --- input/input-service.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 377f47e2..76081c1e 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -401,7 +401,19 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + DBusMessage *reply; + const char *paddr = idev->addr; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); } static DBusHandlerResult device_get_name(DBusConnection *conn, -- cgit From 5869694c6f27fe19ed196476e7a3c0e0c320a91c Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 22 Jan 2007 20:36:05 +0000 Subject: Added GetName --- input/input-service.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 76081c1e..2e4c911b 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -419,7 +419,19 @@ static DBusHandlerResult device_get_address(DBusConnection *conn, static DBusHandlerResult device_get_name(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + DBusMessage *reply; + const char *pname = idev->hidp.name; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &pname, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); } static DBusHandlerResult device_get_product_id(DBusConnection *conn, -- cgit From 93c24ae06c11510629bc439a5aa3fed611deae04 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 23 Jan 2007 05:31:49 +0000 Subject: Hand incoming HID sessions over to the kernel --- input/server.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 181 insertions(+), 11 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index 0725d0de..4f553d7e 100644 --- a/input/server.c +++ b/input/server.c @@ -25,50 +25,220 @@ #include #endif +#include #include +#include +#include #include #include #include +#include #include #include "logging.h" +#include "textfile.h" #include "server.h" +struct session_data { + bdaddr_t src; + bdaddr_t dst; + int ctrl_sk; + int intr_sk; +}; + +static GSList *sessions = NULL; + +static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst) +{ + GSList *list; + + for (list = sessions; list != NULL; list = list->next) { + struct session_data *session = list->data; + + if (!bacmp(&session->src, src) && !bacmp(&session->dst, dst)) + return session; + } + + return NULL; +} + static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data) { if (cond & (G_IO_HUP | G_IO_ERR)) return FALSE; - debug("Incoming data session"); + return TRUE; +} + +static int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, + struct hidp_connadd_req *req) +{ + char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc; + unsigned int vendor, product, version, subclass, country, parser, pos; + int i; + + desc = malloc(4096); + if (!desc) + return -ENOMEM; + + memset(desc, 0, 4096); + + ba2str(src, addr); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); + + ba2str(dst, addr); + str = textfile_get(filename, addr); + if (!str) { + free(desc); + return -EIO; + } + + sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", + &vendor, &product, &version, &subclass, &country, + &parser, desc, &req->flags, &pos); + + free(str); + + req->vendor = vendor; + req->product = product; + req->version = version; + req->subclass = subclass; + req->country = country; + req->parser = parser; + + snprintf(req->name, 128, str + pos); - return FALSE; + req->rd_size = strlen(desc) / 2; + req->rd_data = malloc(req->rd_size); + if (!req->rd_data) + return -ENOMEM; + + memset(tmp, 0, sizeof(tmp)); + for (i = 0; i < req->rd_size; i++) { + memcpy(tmp, desc + (i * 2), 2); + req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); + } + + return 0; } -static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) +static void create_device(struct session_data *session) +{ + struct hidp_connadd_req req; + char addr[18]; + int ctl, err, timeout = 30; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP interface"); + goto cleanup; + } + + ba2str(&session->dst, addr); + + memset(&req, 0, sizeof(req)); + req.ctrl_sock = session->ctrl_sk; + req.intr_sock = session->intr_sk; + req.flags = 0; + req.idle_to = timeout * 60; + + if (get_stored_device_info(&session->src, &session->dst, &req) < 0) { + error("Rejected connection from unknown device %s", addr); + goto cleanup; + } + + info("New input device %s (%s)", addr, req.name); + + err = ioctl(ctl, HIDPCONNADD, &req); + + close(ctl); + + if (req.rd_data) + free(req.rd_data); + +cleanup: + sessions = g_slist_remove(sessions, session); + + close(session->intr_sk); + close(session->ctrl_sk); + + g_free(session); +} + +static void create_watch(int sk, struct session_data *session) { GIOChannel *io; + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, TRUE); + + g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR, + session_event, session); + + g_io_channel_unref(io); +} + +static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct session_data *session; struct sockaddr_l2 addr; - socklen_t optlen; + socklen_t addrlen; + bdaddr_t src, dst; + unsigned char psm; int sk, nsk; sk = g_io_channel_unix_get_fd(chan); memset(&addr, 0, sizeof(addr)); - optlen = sizeof(addr); + addrlen = sizeof(addr); - nsk = accept(sk, (struct sockaddr *) &addr, &optlen); + nsk = accept(sk, (struct sockaddr *) &addr, &addrlen); if (nsk < 0) return TRUE; - io = g_io_channel_unix_new(nsk); - g_io_channel_set_close_on_unref(io, TRUE); + bacpy(&dst, &addr.l2_bdaddr); + psm = btohs(addr.l2_psm); - g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR, - session_event, NULL); + memset(&addr, 0, sizeof(addr)); + addrlen = sizeof(addr); - g_io_channel_unref(io); + if (getsockname(nsk, (struct sockaddr *) &addr, &addrlen) < 0) { + close(nsk); + return TRUE; + } + + bacpy(&src, &addr.l2_bdaddr); + + debug("Incoming connection on PSM %d", psm); + + session = find_session(&src, &dst); + if (session) { + if (psm == 19) { + session->intr_sk = nsk; + create_device(session); + } else { + error("Control channel already established"); + close(nsk); + } + } else { + if (psm == 17) { + session = g_new0(struct session_data, 1); + + bacpy(&session->src, &src); + bacpy(&session->dst, &dst); + session->ctrl_sk = nsk; + session->intr_sk = -1; + + sessions = g_slist_append(sessions, session); + + create_watch(nsk, session); + } else { + error("No control channel available"); + close(nsk); + } + } return TRUE; } -- cgit From 77a277e66743cd5f55cec8e4b5e61874bb6ab5b0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 23 Jan 2007 07:18:07 +0000 Subject: Make echo and input service configurable --- input/Makefile.am | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 7716bec6..6aa8ef1b 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -1,7 +1,14 @@ +if INPUTSERVICE +if CONFIGFILES +confdir = $(sysconfdir)/bluetooth + +conf_DATA = input.service +endif + servicedir = $(libdir)/bluetooth -noinst_PROGRAMS = bluetoothd-service-input +service_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = \ main.c server.h server.c \ @@ -9,6 +16,7 @@ bluetoothd_service_input_SOURCES = \ LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ +endif AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ -- cgit From 4ddff0e350fe0139b7c9fe306fedbe81061d65e2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 13:53:49 +0000 Subject: Connect: Added initial functionality --- input/input-service.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 171 insertions(+), 15 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 2e4c911b..06dcad77 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -28,10 +28,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -50,6 +52,9 @@ #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 + static DBusConnection *connection = NULL; const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; @@ -68,6 +73,37 @@ struct pending_req { sdp_record_t *hid_rec; }; +struct pending_connect { + bdaddr_t sba; + bdaddr_t dba; + DBusConnection *conn; + DBusMessage *msg; +}; + +struct input_device *input_device_new(const char *addr) +{ + struct input_device *idev; + + idev = malloc(sizeof(struct input_device)); + if (!idev) + return NULL; + + memset(idev, 0, sizeof(struct input_device)); + + memcpy(idev->addr, addr, 18); + + return idev; +} + +void input_device_free(struct input_device *idev) +{ + if (!idev) + return; + if (idev->hidp.rd_data) + free(idev->hidp.rd_data); + free(idev); +} + struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, const char *adapter_path, const char *peer) { @@ -102,28 +138,32 @@ void pending_req_free(struct pending_req *pr) free(pr); } -struct input_device *input_device_new(const char *addr) +static struct pending_connect *pending_connect_new(bdaddr_t *sba, bdaddr_t *dba, + DBusConnection *conn, DBusMessage *msg) { - struct input_device *idev; - - idev = malloc(sizeof(struct input_device)); - if (!idev) + struct pending_connect *pc; + pc = malloc(sizeof(struct pending_connect)); + if (!pc) return NULL; - memset(idev, 0, sizeof(struct input_device)); + memset(pc, 0, sizeof(struct pending_connect)); + bacpy(&pc->sba, sba); + bacpy(&pc->dba, dba); + pc->conn = dbus_connection_ref(conn); + pc->msg = dbus_message_ref(msg); - memcpy(idev->addr, addr, 18); - - return idev; + return pc; } -void input_device_free(struct input_device *idev) +static void pending_connect_free(struct pending_connect *pc) { - if (!idev) + if (!pc) return; - if (idev->hidp.rd_data) - free(idev->hidp.rd_data); - free(idev); + if (pc->conn) + dbus_connection_unref(pc->conn); + if (pc->msg) + dbus_message_unref(pc->msg); + free(pc); } /* @@ -153,6 +193,15 @@ static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, INPUT_ERROR_INTERFACE ".Failed", str)); } +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) { @@ -371,13 +420,120 @@ static const char *create_input_path(uint8_t minor) return path; } +static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + info("FIXME: Control connect callback"); + return FALSE; +} + +/* FIXME: Move to a common file. It is already used by audio and rfcomm */ +static int set_nonblocking(int fd) +{ + long arg; + + arg = fcntl(fd, F_GETFL); + if (arg < 0) { + error("fcntl(F_GETFL): %s (%d)", strerror(errno), errno); + return -1; + } + + /* Return if already nonblocking */ + if (arg & O_NONBLOCK) + return 0; + + arg |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, arg) < 0) { + error("fcntl(F_SETFL, O_NONBLOCK): %s (%d)", + strerror(errno), errno); + return -1; + } + + return 0; +} + +static int l2cap_connect(struct pending_connect *pc, + unsigned short psm, GIOFunc cb) +{ + GIOChannel *io; + struct sockaddr_l2 addr; + struct l2cap_options opts; + int sk, err; + + if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, &pc->sba); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) + goto failed; + + if (set_nonblocking(sk) < 0) + goto failed; + + memset(&opts, 0, sizeof(opts)); + opts.imtu = HIDP_DEFAULT_MTU; + opts.omtu = HIDP_DEFAULT_MTU; + opts.flush_to = 0xffff; + + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) + goto failed; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, &pc->dba); + addr.l2_psm = htobs(psm); + + /* FIXME: check leaking io channel */ + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, FALSE); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (!(errno == EAGAIN || errno == EINPROGRESS)) + goto failed; + + g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, pc); + } else { + cb(io, G_IO_OUT, pc); + } + + return 0; + +failed: + err = errno; + close(sk); + errno = err; + + return -1; +} + /* * Input Device methods */ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + struct pending_connect *pc; + bdaddr_t dba; + + /* FIXME: check if it is already connected */ + str2ba(idev->addr, &dba); + + pc = pending_connect_new(BDADDR_ANY, &dba, conn, msg); + if (!pc) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb) < 0) { + error("L2CAP connect failed: %s(%d)", strerror(errno), errno); + pending_connect_free(pc); + return err_connection_failed(conn, msg, strerror(errno)); + } + + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult device_disconnect(DBusConnection *conn, -- cgit From 86ac7d918622db3423e4acfaa71a65f2f1a86da6 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 16:45:29 +0000 Subject: Added L2CAP HID control channel connect callback --- input/input-service.c | 67 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 06dcad77..cc6a05c5 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -420,13 +420,6 @@ static const char *create_input_path(uint8_t minor) return path; } -static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) -{ - info("FIXME: Control connect callback"); - return FALSE; -} - /* FIXME: Move to a common file. It is already used by audio and rfcomm */ static int set_nonblocking(int fd) { @@ -509,6 +502,66 @@ failed: return -1; } +static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + info("FIXME: interrupt connect callback"); + return FALSE; +} + +static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + struct input_device *idev; + int csk, ret, err = EHOSTDOWN; + socklen_t len; + const char *path; + + if (cond & G_IO_NVAL) + goto failed; + + csk = g_io_channel_unix_get_fd(chan); + + len = sizeof(ret); + if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + /* Set HID control channel */ + idev->hidp.ctrl_sock = csk; + + /* Connect to the HID interrupt channel */ + if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb) < 0) { + + error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + err = errno; + close(csk); + idev->hidp.ctrl_sock = -1; + goto failed; + } + + return FALSE; + +failed: + + err_connection_failed(pc->conn, pc->msg, strerror(err)); + pending_connect_free(pc); + + return FALSE; +} + /* * Input Device methods */ -- cgit From 706b8b6df5e924d72caac5d477ca1fa4a6b1d794 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 17:29:52 +0000 Subject: Added L2CAP HID interrupt channel connect callback --- input/input-service.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index cc6a05c5..11572c03 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -29,7 +29,10 @@ #include #include #include - +#include +#include +#include + #include #include #include @@ -505,7 +508,60 @@ failed: static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { - info("FIXME: interrupt connect callback"); + struct input_device *idev; + int ctl, ret, err = EHOSTDOWN, isk = -1; + socklen_t len; + const char *path; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + if (cond & G_IO_NVAL) + goto failed; + + isk = g_io_channel_unix_get_fd(chan); + idev->hidp.intr_sock = isk; + + len = sizeof(ret); + if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + err = errno; + error("Can't open HIDP control socket"); + goto failed; + } + if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { + err = errno; + close(ctl); + goto failed; + } + close(ctl); + + send_message_and_unref(pc->conn, + dbus_message_new_method_return(pc->msg)); + + pending_connect_free(pc); + + return FALSE; +failed: + if (isk > 0) + close(isk); + + idev->hidp.intr_sock = -1; + err_connection_failed(pc->conn, pc->msg, strerror(err)); + pending_connect_free(pc); + return FALSE; } -- cgit From 64b9c9c1a2c57a7b602b8d7fb9d5cf6c4df923d5 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 17:48:40 +0000 Subject: Code cleanup: missing HID control socket close and fixed code standard --- input/input-service.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 11572c03..6ba68b0b 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -509,15 +509,18 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { struct input_device *idev; - int ctl, ret, err = EHOSTDOWN, isk = -1; + int ctl, isk, ret, err; socklen_t len; const char *path; path = dbus_message_get_path(pc->msg); dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); - if (cond & G_IO_NVAL) + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + isk = -1; goto failed; + } isk = g_io_channel_unix_get_fd(chan); idev->hidp.intr_sock = isk; @@ -569,14 +572,22 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { struct input_device *idev; - int csk, ret, err = EHOSTDOWN; + int ret, csk, err; socklen_t len; const char *path; - if (cond & G_IO_NVAL) + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + csk = -1; goto failed; + } csk = g_io_channel_unix_get_fd(chan); + /* Set HID control channel */ + idev->hidp.ctrl_sock = csk; len = sizeof(ret); if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { @@ -590,28 +601,23 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, error("connect(): %s (%d)", strerror(ret), ret); goto failed; } - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); - - /* Set HID control channel */ - idev->hidp.ctrl_sock = csk; - /* Connect to the HID interrupt channel */ if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, (GIOFunc) interrupt_connect_cb) < 0) { - error("L2CAP connect failed:%s (%d)", strerror(errno), errno); err = errno; - close(csk); - idev->hidp.ctrl_sock = -1; + error("L2CAP connect failed:%s (%d)", strerror(errno), errno); goto failed; } + pending_connect_free(pc); return FALSE; failed: + if (csk > 0) + close(csk); + idev->hidp.ctrl_sock = -1; err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); -- cgit From 6ff980e40b0cdd9a26b9e44bed8c75d2055a65d9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 19:00:39 +0000 Subject: Added input disconnect --- input/input-service.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 6ba68b0b..fb506fc9 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -205,6 +205,15 @@ static DBusHandlerResult err_connection_failed(DBusConnection *conn, str)); } +static DBusHandlerResult err_not_connected(DBusConnection *conn, + DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE".NotConnected", + "Input device not connected")); +} + static DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str) { @@ -654,7 +663,42 @@ static DBusHandlerResult device_connect(DBusConnection *conn, static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + struct hidp_conndel_req req; + int ctl; + + if ((idev->hidp.intr_sock < 0) || (idev->hidp.ctrl_sock < 0)) + return err_not_connected(conn, msg); + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP control socket"); + goto fail; + } + + memset(&req, 0, sizeof(struct hidp_conndel_req)); + + req.flags = idev->hidp.flags; + str2ba(idev->addr, &req.bdaddr); + + if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { + error("Can't delete the HID device: %s(%d)", + strerror(errno), errno); + goto fail; + } + + close(ctl); + + close(idev->hidp.intr_sock); + idev->hidp.intr_sock = -1; + + close(idev->hidp.ctrl_sock); + idev->hidp.ctrl_sock = -1; + + return send_message_and_unref(conn, + dbus_message_new_method_return(msg)); +fail: + return err_failed(conn, msg, strerror(errno)); } static DBusHandlerResult device_unplug(DBusConnection *conn, -- cgit From 7fee6d805cbba759954746306fd2993efc6136c1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 19:01:57 +0000 Subject: Fixed wrong pending connection unref --- input/input-service.c | 1 - 1 file changed, 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index fb506fc9..a90c6032 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -619,7 +619,6 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, goto failed; } - pending_connect_free(pc); return FALSE; failed: -- cgit From 49cc58fa6f9b70c5d2c0dbd0fb2d6efbae8c246d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 20:04:55 +0000 Subject: Workaround to use the default local adapter --- input/input-service.c | 103 +++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 68 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index a90c6032..cffb4cb3 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -823,8 +823,6 @@ static const DBusObjectPathVTable device_table = { * Input Manager methods */ struct input_manager { - char adapter[18]; - char *adapter_path; GSList *paths; }; @@ -836,8 +834,6 @@ void input_manager_free(struct input_manager *mgr) g_slist_foreach(mgr->paths, (GFunc) free, NULL); g_slist_free(mgr->paths); } - if (mgr->adapter_path) - free(mgr->adapter_path); free(mgr); } @@ -1159,10 +1155,13 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, { struct input_manager *mgr = data; struct input_device *idev; + struct hci_dev_info di; DBusMessage *reply; DBusError derr; + char adapter_addr[18], adapter_path[32]; const char *addr, *path; GSList *l; + int dev_id; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -1178,16 +1177,29 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (l) return err_already_exists(conn, msg, "Input Already exists"); + /* Request the default adapter */ + dev_id = hci_get_route(NULL); + if (dev_id < 0) { + error("Bluetooth device not available"); + return err_failed(conn, msg, "Bluetooth adapter not available"); + } + if (hci_devinfo(dev_id, &di) < 0) { + error("Can't get local adapter device info"); + return err_failed(conn, msg, "Bluetooth adapter not available"); + } + + ba2str(&di.bdaddr, adapter_addr); + snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); + idev = input_device_new(addr); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (get_stored_info(mgr->adapter, addr, &idev->hidp) < 0) { + if (get_stored_info(adapter_addr, addr, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ input_device_free(idev); - pr = pending_req_new(conn, msg, mgr->adapter_path, addr); + pr = pending_req_new(conn, msg, adapter_path, addr); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1342,10 +1354,24 @@ static void stored_input(char *key, char *value, void *data) input_device_free(idev); } -static int register_stored_inputs(DBusConnection *conn, const char *local) +static int register_stored_inputs(DBusConnection *conn) { + struct hci_dev_info di; char filename[PATH_MAX + 1]; + char local[18]; + int dev_id; + dev_id = hci_get_route(NULL); + if (dev_id < 0) { + error("Bluetooth device not available"); + return -1; + } + if (hci_devinfo(dev_id, &di) < 0) { + error("Can't get local adapter device info"); + return -1; + } + + ba2str(&di.bdaddr, local); create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); textfile_foreach(filename, stored_input, conn); @@ -1355,9 +1381,6 @@ static int register_stored_inputs(DBusConnection *conn, const char *local) int input_dbus_init(void) { struct input_manager *mgr; - DBusMessage *msg, *reply; - DBusError derr; - const char *adapter; connection = init_dbus(NULL, NULL, NULL); if (!connection) @@ -1367,62 +1390,6 @@ int input_dbus_init(void) mgr = malloc(sizeof(struct input_manager)); memset(mgr, 0, sizeof(struct input_manager)); - - /* Get the default adapter path */ - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Manager", "DefaultAdapter"); - - dbus_error_init(&derr); - reply = dbus_connection_send_with_reply_and_block(connection, - msg, -1, &derr); - dbus_message_unref(msg); - - if (!reply) { - error("input init failed: %s (%s)", derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_STRING, &adapter, - DBUS_TYPE_INVALID)) { - error("input init failed: %s (%s)", derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - mgr->adapter_path = strdup(adapter); - dbus_message_unref(reply); - - /* Get the adapter address */ - msg = dbus_message_new_method_call("org.bluez", adapter, - "org.bluez.Adapter", "GetAddress"); - - dbus_error_init(&derr); - reply = dbus_connection_send_with_reply_and_block(connection, - msg, -1, &derr); - dbus_message_unref(msg); - - if (!reply) { - error("input init failed: %s (%s)", derr.name, derr.message); - dbus_error_free(&derr); - dbus_error_free(&derr); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_STRING, &adapter, - DBUS_TYPE_INVALID)) { - error("input init failed: %s (%s)", derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - strncpy(mgr->adapter, adapter, 18); - dbus_message_unref(reply); - - info("Default adapter: %s (%s)", mgr->adapter_path, mgr->adapter); - /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, &manager_table, mgr)) { @@ -1432,7 +1399,7 @@ int input_dbus_init(void) info("Registered input manager path:%s", INPUT_PATH); - register_stored_inputs(connection, mgr->adapter); + register_stored_inputs(connection); return 0; fail: -- cgit From 5f80c518582acd9045c952b73bc0f25f97628b37 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 20:34:55 +0000 Subject: Removed GIOChannel memory leak --- input/input-service.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index cffb4cb3..5a891709 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -564,6 +564,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, dbus_message_new_method_return(pc->msg)); pending_connect_free(pc); + g_io_channel_unref(chan); return FALSE; failed: @@ -573,6 +574,7 @@ failed: idev->hidp.intr_sock = -1; err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); + g_io_channel_unref(chan); return FALSE; } @@ -619,6 +621,7 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, goto failed; } + g_io_channel_unref(chan); return FALSE; failed: @@ -628,6 +631,7 @@ failed: idev->hidp.ctrl_sock = -1; err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); + g_io_channel_unref(chan); return FALSE; } @@ -1183,6 +1187,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, error("Bluetooth device not available"); return err_failed(conn, msg, "Bluetooth adapter not available"); } + memset(&di, 0, sizeof(struct hci_dev_info)); if (hci_devinfo(dev_id, &di) < 0) { error("Can't get local adapter device info"); return err_failed(conn, msg, "Bluetooth adapter not available"); @@ -1366,6 +1371,7 @@ static int register_stored_inputs(DBusConnection *conn) error("Bluetooth device not available"); return -1; } + memset(&di, 0, sizeof(struct hci_dev_info)); if (hci_devinfo(dev_id, &di) < 0) { error("Can't get local adapter device info"); return -1; -- cgit From bf9a0168854c71faff3e67c42c6265069230f6ce Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 23 Jan 2007 22:02:47 +0000 Subject: Added HID unplug method --- input/input-service.c | 54 ++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 5a891709..f5568bb4 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -205,15 +205,6 @@ static DBusHandlerResult err_connection_failed(DBusConnection *conn, str)); } -static DBusHandlerResult err_not_connected(DBusConnection *conn, - DBusMessage *msg) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE".NotConnected", - "Input device not connected")); -} - static DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str) { @@ -663,51 +654,66 @@ static DBusHandlerResult device_connect(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } -static DBusHandlerResult device_disconnect(DBusConnection *conn, - DBusMessage *msg, void *data) +static int disconnect(struct input_device *idev, uint32_t flags) { - struct input_device *idev = data; struct hidp_conndel_req req; - int ctl; + int ctl, err; - if ((idev->hidp.intr_sock < 0) || (idev->hidp.ctrl_sock < 0)) - return err_not_connected(conn, msg); + if ((idev->hidp.intr_sock < 0) || (idev->hidp.ctrl_sock < 0)) { + errno = ENOTCONN; + return -1; + } ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { error("Can't open HIDP control socket"); - goto fail; + return -1; } memset(&req, 0, sizeof(struct hidp_conndel_req)); - req.flags = idev->hidp.flags; str2ba(idev->addr, &req.bdaddr); + req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { + err = errno; error("Can't delete the HID device: %s(%d)", strerror(errno), errno); - goto fail; + close(ctl); + errno = err; + return -1; } close(ctl); - close(idev->hidp.intr_sock); idev->hidp.intr_sock = -1; - - close(idev->hidp.ctrl_sock); idev->hidp.ctrl_sock = -1; + return 0; +} + +static DBusHandlerResult device_disconnect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + + if (disconnect(idev, 0) < 0) + return err_failed(conn, msg, strerror(errno)); + return send_message_and_unref(conn, dbus_message_new_method_return(msg)); -fail: - return err_failed(conn, msg, strerror(errno)); } static DBusHandlerResult device_unplug(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + + if (disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) < 0) + return err_failed(conn, msg, strerror(errno)); + + return send_message_and_unref(conn, + dbus_message_new_method_return(msg)); } static DBusHandlerResult device_is_connected(DBusConnection *conn, -- cgit From 398f6814486536e5906c3723f23cdae9e3c4642a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 24 Jan 2007 05:45:11 +0000 Subject: Add support for service debugging --- input/input-service.c | 29 +++++++++++++++++++++++++++++ input/input-service.h | 2 ++ input/main.c | 3 +++ 3 files changed, 34 insertions(+) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index f5568bb4..11e060d2 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -1426,3 +1426,32 @@ void input_dbus_exit(void) 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(reply); + + dbus_connection_flush(connection); +} diff --git a/input/input-service.h b/input/input-service.h index acda934d..179a02c5 100644 --- a/input/input-service.h +++ b/input/input-service.h @@ -27,4 +27,6 @@ int input_dbus_init(void); void input_dbus_exit(void); +void internal_service(const char *identifier); + #endif /* __INPUT_SERVICE_H */ diff --git a/input/main.c b/input/main.c index bb8759a7..340fc776 100644 --- a/input/main.c +++ b/input/main.c @@ -76,6 +76,9 @@ int main(int argc, char *argv[]) exit(1); } + if (argc > 1 && !strcmp(argv[1], "-s")) + internal_service("input"); + server_start(); g_main_loop_run(main_loop); -- cgit From 96a229f1695084dc7aa71d9cd12814f27084e0ad Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 24 Jan 2007 10:11:11 +0000 Subject: Service registration is done via the manager interface --- input/input-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 11e060d2..491eb5f8 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -1435,7 +1435,7 @@ void internal_service(const char *identifier) info("Registering service"); msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "RegisterService"); + "org.bluez.Manager", "RegisterService"); if (!msg) { error("Can't create service register method"); return; -- cgit From e5e024113e3ed63bebe90da4188a1ece73caf364 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 13:21:51 +0000 Subject: Added function to store HID info --- input/input-service.c | 55 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 8 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 491eb5f8..627c2a99 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -68,8 +68,9 @@ struct input_device { }; struct pending_req { - char *adapter_path; - char peer[18]; + char *adapter_path; /* Local adapter D-Bus path */ + char adapter[18]; /* Local adapter BT address */ + char peer[18]; /* Peer BT address */ DBusConnection *conn; DBusMessage *msg; sdp_record_t *pnp_rec; @@ -108,7 +109,7 @@ void input_device_free(struct input_device *idev) } struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, - const char *adapter_path, const char *peer) + const char *adapter_path, const char *adapter, const char *peer) { struct pending_req *pr; pr = malloc(sizeof(struct pending_req)); @@ -117,6 +118,7 @@ struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, memset(pr, 0, sizeof(struct pending_req)); pr->adapter_path = strdup(adapter_path); + strncpy(pr->adapter, adapter, 18); strncpy(pr->peer, peer, 18); pr->conn = dbus_connection_ref(conn); pr->msg = dbus_message_ref(msg); @@ -303,6 +305,43 @@ static int get_stored_info(const char *local, const char *peer, return ret; } +static int store_info(const char *local, const char *peer, + struct hidp_connadd_req *req) +{ + char filename[PATH_MAX + 1], *str, *desc; + int i, size, ret; + + create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); + + size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; + str = malloc(size); + if (!str) + return -ENOMEM; + + desc = malloc((req->rd_size * 2) + 1); + if (!desc) { + free(str); + return -ENOMEM; + } + + memset(desc, 0, (req->rd_size * 2) + 1); + for (i = 0; i < req->rd_size; i++) + sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); + + snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", + req->vendor, req->product, req->version, + req->subclass, req->country, req->parser, desc, + req->flags, req->name); + free(desc); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + ret = textfile_put(filename, peer, str); + free(str); + + return ret; +} + static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist, *pdlist2; @@ -1030,7 +1069,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) DBUS_TYPE_INVALID); send_message_and_unref(pr->conn, pr_reply); - /* FIXME: Store HID record data and free req */ + store_info(pr->adapter, pr->peer, &idev->hidp); fail: pending_req_free(pr); dbus_message_unref(reply); @@ -1168,7 +1207,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, struct hci_dev_info di; DBusMessage *reply; DBusError derr; - char adapter_addr[18], adapter_path[32]; + char adapter[18], adapter_path[32]; const char *addr, *path; GSList *l; int dev_id; @@ -1199,18 +1238,18 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_failed(conn, msg, "Bluetooth adapter not available"); } - ba2str(&di.bdaddr, adapter_addr); + ba2str(&di.bdaddr, adapter); snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); idev = input_device_new(addr); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_stored_info(adapter_addr, addr, &idev->hidp) < 0) { + if (get_stored_info(adapter, addr, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ input_device_free(idev); - pr = pending_req_new(conn, msg, adapter_path, addr); + pr = pending_req_new(conn, msg, adapter_path, adapter, addr); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From e0e5d97ac34119a2cf91d096f20e203d5ffe676d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 14:14:36 +0000 Subject: Disconnect(if applied) when removing the device --- input/input-service.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 627c2a99..4982fc7f 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -696,12 +696,8 @@ static DBusHandlerResult device_connect(DBusConnection *conn, static int disconnect(struct input_device *idev, uint32_t flags) { struct hidp_conndel_req req; - int ctl, err; - - if ((idev->hidp.intr_sock < 0) || (idev->hidp.ctrl_sock < 0)) { - errno = ENOTCONN; - return -1; - } + struct hidp_conninfo ci; + int ctl, err, ret = 0; ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { @@ -709,26 +705,39 @@ static int disconnect(struct input_device *idev, uint32_t flags) return -1; } + memset(&ci, 0, sizeof(struct hidp_conninfo)); + str2ba(idev->addr, &ci.bdaddr); + if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { + error("Can't retrive HID information: %s(%d)", + strerror(errno), errno); + goto fail; + } + + if (ci.state != BT_CONNECTED) { + errno = ENOTCONN; + goto fail; + } + memset(&req, 0, sizeof(struct hidp_conndel_req)); str2ba(idev->addr, &req.bdaddr); req.flags = flags; - if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { - err = errno; error("Can't delete the HID device: %s(%d)", strerror(errno), errno); - close(ctl); - errno = err; - return -1; + goto fail; } + ret = 0; +fail: + err = errno; close(ctl); + errno = err; idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - return 0; + return ret; } static DBusHandlerResult device_disconnect(DBusConnection *conn, @@ -1283,6 +1292,7 @@ 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; @@ -1305,6 +1315,12 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, 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)); + + /* FIXME: Remove stored data */ + if (unregister_input_device(conn, path) < 0) { dbus_message_unref(reply); return err_failed(conn, msg, "D-Bus path unregistration failed"); -- cgit From e1ebd6405afaed4d83308fbfe06f5c487038df62 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 24 Jan 2007 14:19:55 +0000 Subject: Back to the database interface --- input/input-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 4982fc7f..4bda05d2 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -1490,7 +1490,7 @@ void internal_service(const char *identifier) info("Registering service"); msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Manager", "RegisterService"); + "org.bluez.Database", "RegisterService"); if (!msg) { error("Can't create service register method"); return; -- cgit From b992c01c50b195751dbe288061d24b4126550a1c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 24 Jan 2007 15:43:06 +0000 Subject: Add errors when server setup fails --- input/server.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index 4f553d7e..b37c35ff 100644 --- a/input/server.c +++ b/input/server.c @@ -282,11 +282,14 @@ static GIOChannel *intr_io = NULL; int server_start(void) { ctrl_io = setup_l2cap(17); - if (!ctrl_io) + if (!ctrl_io) { + error("Failed to listen on control channel"); return -1; + } intr_io = setup_l2cap(19); if (!intr_io) { + error("Failed to listen on interrupt channel"); g_io_channel_unref(ctrl_io); ctrl_io = NULL; } -- cgit From e232c19d0481943433ad4d4a8ff494cf6237db83 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 17:17:48 +0000 Subject: Store the default adapter Bluetooth address to use it when creating/removing devices --- input/input-service.c | 61 ++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 35 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 4bda05d2..bd8fe004 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -881,7 +881,8 @@ static const DBusObjectPathVTable device_table = { * Input Manager methods */ struct input_manager { - GSList *paths; + char adapter[18]; /* Local adapter BT address */ + GSList *paths; /* Input registered paths */ }; void input_manager_free(struct input_manager *mgr) @@ -1213,10 +1214,9 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, { struct input_manager *mgr = data; struct input_device *idev; - struct hci_dev_info di; DBusMessage *reply; DBusError derr; - char adapter[18], adapter_path[32]; + char adapter_path[32]; const char *addr, *path; GSList *l; int dev_id; @@ -1235,30 +1235,18 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (l) return err_already_exists(conn, msg, "Input Already exists"); - /* Request the default adapter */ - dev_id = hci_get_route(NULL); - if (dev_id < 0) { - error("Bluetooth device not available"); - return err_failed(conn, msg, "Bluetooth adapter not available"); - } - memset(&di, 0, sizeof(struct hci_dev_info)); - if (hci_devinfo(dev_id, &di) < 0) { - error("Can't get local adapter device info"); - return err_failed(conn, msg, "Bluetooth adapter not available"); - } - - ba2str(&di.bdaddr, adapter); + dev_id = hci_devid(mgr->adapter); snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); idev = input_device_new(addr); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_stored_info(adapter, addr, &idev->hidp) < 0) { + if (get_stored_info(mgr->adapter, addr, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ input_device_free(idev); - pr = pending_req_new(conn, msg, adapter_path, adapter, addr); + pr = pending_req_new(conn, msg, adapter_path, mgr->adapter, addr); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1420,25 +1408,10 @@ static void stored_input(char *key, char *value, void *data) input_device_free(idev); } -static int register_stored_inputs(DBusConnection *conn) +static int register_stored_inputs(DBusConnection *conn, const char *local) { - struct hci_dev_info di; char filename[PATH_MAX + 1]; - char local[18]; - int dev_id; - dev_id = hci_get_route(NULL); - if (dev_id < 0) { - error("Bluetooth device not available"); - return -1; - } - memset(&di, 0, sizeof(struct hci_dev_info)); - if (hci_devinfo(dev_id, &di) < 0) { - error("Can't get local adapter device info"); - return -1; - } - - ba2str(&di.bdaddr, local); create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); textfile_foreach(filename, stored_input, conn); @@ -1448,6 +1421,8 @@ static int register_stored_inputs(DBusConnection *conn) int input_dbus_init(void) { struct input_manager *mgr; + bdaddr_t sba; + int dev_id; connection = init_dbus(NULL, NULL, NULL); if (!connection) @@ -1466,7 +1441,23 @@ int input_dbus_init(void) info("Registered input manager path:%s", INPUT_PATH); - register_stored_inputs(connection); + /* Set the default adapter */ + bacpy(&sba, BDADDR_ANY); + dev_id = hci_get_route(&sba); + if (dev_id < 0) { + error("Bluetooth device not available"); + goto fail; + } + + if (hci_devba(dev_id, &sba) < 0) { + error("Can't get local adapter device info"); + goto fail; + } + + ba2str(&sba, mgr->adapter); + + /* Register well known HID devices */ + register_stored_inputs(connection, mgr->adapter); return 0; fail: -- cgit From 7bd6035a5716abf76acf8fc5098c58068e376d59 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 17:22:15 +0000 Subject: Delete the stored HID info when removing the input device --- input/input-service.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index bd8fe004..def6248d 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -305,6 +305,15 @@ static int get_stored_info(const char *local, const char *peer, return ret; } +static int del_stored_info(const char *local, const char *peer) +{ + char filename[PATH_MAX + 1]; + + create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); + + return textfile_del(filename, peer); +} + static int store_info(const char *local, const char *peer, struct hidp_connadd_req *req) { @@ -1307,7 +1316,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, if (dbus_connection_get_object_path_data(conn, path, (void *) &idev) && idev) disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); - /* FIXME: Remove stored data */ + del_stored_info(mgr->adapter, idev->addr); if (unregister_input_device(conn, path) < 0) { dbus_message_unref(reply); -- cgit From 818548335c3aa9eff21e569e8f3148663b28af1a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 17:26:44 +0000 Subject: Device unplug method removed: RemoveDevice is going to address this functionality --- input/input-api.txt | 4 ---- input/input-service.c | 15 --------------- 2 files changed, 19 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index d947d489..42ce2755 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -70,10 +70,6 @@ Methods string GetAddress() Disconnect from the input device. - void Unplug() - - Unplug the virtual cable device. - void SetTimeout(uint32 timeout) Set the idle timeout. diff --git a/input/input-service.c b/input/input-service.c index def6248d..1c3bb604 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -761,18 +761,6 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, dbus_message_new_method_return(msg)); } -static DBusHandlerResult device_unplug(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - - if (disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) < 0) - return err_failed(conn, msg, strerror(errno)); - - return send_message_and_unref(conn, - dbus_message_new_method_return(msg)); -} - static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -851,9 +839,6 @@ static DBusHandlerResult device_message(DBusConnection *conn, if (strcmp(member, "Disconnect") == 0) return device_disconnect(conn, msg, data); - if (strcmp(member, "Unplug") == 0) - return device_unplug(conn, msg, data); - if (strcmp(member, "IsConnected") == 0) return device_is_connected(conn, msg, data); -- cgit From ccf0880203ad1c3c0f6f78a16b271114875fffb4 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 17:44:58 +0000 Subject: Check if the input is already connected when "Connect" is requested --- input/input-service.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 1c3bb604..049792c5 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -530,7 +530,6 @@ static int l2cap_connect(struct pending_connect *pc, bacpy(&addr.l2_bdaddr, &pc->dba); addr.l2_psm = htobs(psm); - /* FIXME: check leaking io channel */ io = g_io_channel_unix_new(sk); g_io_channel_set_close_on_unref(io, FALSE); @@ -682,12 +681,26 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; + struct hidp_conninfo ci; struct pending_connect *pc; bdaddr_t dba; + int ctl; - /* FIXME: check if it is already connected */ - str2ba(idev->addr, &dba); + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) + return err_connection_failed(conn, msg, strerror(errno)); + + /* Check if it is already connected */ + memset(&ci, 0, sizeof(struct hidp_conninfo)); + str2ba(idev->addr, &ci.bdaddr); + if (!ioctl(ctl, HIDPGETCONNINFO, &ci) && (ci.state == BT_CONNECTED)) { + close(ctl); + return err_connection_failed(conn, msg, "Already connected"); + } + close(ctl); + + str2ba(idev->addr, &dba); pc = pending_connect_new(BDADDR_ANY, &dba, conn, msg); if (!pc) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From ffe5dd5b56c8a85fb8d47989477d8c9d1377f5e3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 18:47:11 +0000 Subject: Added IsConnected --- input/input-service.c | 108 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 42 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 049792c5..c5d469e1 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -674,47 +674,6 @@ failed: return FALSE; } -/* - * Input Device methods - */ -static DBusHandlerResult device_connect(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - struct hidp_conninfo ci; - struct pending_connect *pc; - bdaddr_t dba; - int ctl; - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) - return err_connection_failed(conn, msg, strerror(errno)); - - /* Check if it is already connected */ - memset(&ci, 0, sizeof(struct hidp_conninfo)); - str2ba(idev->addr, &ci.bdaddr); - if (!ioctl(ctl, HIDPGETCONNINFO, &ci) && (ci.state == BT_CONNECTED)) { - close(ctl); - return err_connection_failed(conn, msg, "Already connected"); - } - - close(ctl); - - str2ba(idev->addr, &dba); - pc = pending_connect_new(BDADDR_ANY, &dba, conn, msg); - if (!pc) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb) < 0) { - error("L2CAP connect failed: %s(%d)", strerror(errno), errno); - pending_connect_free(pc); - return err_connection_failed(conn, msg, strerror(errno)); - } - - return DBUS_HANDLER_RESULT_HANDLED; -} - static int disconnect(struct input_device *idev, uint32_t flags) { struct hidp_conndel_req req; @@ -762,6 +721,58 @@ fail: return ret; } +static int is_connected(const char *addr) +{ + struct hidp_conninfo ci; + int ctl; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) + return 0; + + memset(&ci, 0, sizeof(struct hidp_conninfo)); + str2ba(addr, &ci.bdaddr); + if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { + close(ctl); + return 0; + } + + close(ctl); + + if (ci.state != BT_CONNECTED) + return 0; + else + return 1; +} + +/* + * Input Device methods + */ +static DBusHandlerResult device_connect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + struct pending_connect *pc; + bdaddr_t dba; + + if (is_connected(idev->addr)) + return err_connection_failed(conn, msg, "Already connected"); + + str2ba(idev->addr, &dba); + pc = pending_connect_new(BDADDR_ANY, &dba, conn, msg); + if (!pc) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb) < 0) { + error("L2CAP connect failed: %s(%d)", strerror(errno), errno); + pending_connect_free(pc); + return err_connection_failed(conn, msg, strerror(errno)); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -777,7 +788,20 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + DBusMessage *reply; + dbus_bool_t connected; + + connected = is_connected(idev->addr); + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); } static DBusHandlerResult device_get_address(DBusConnection *conn, -- cgit From b40a22456a9d9ff5b388152b9fe5d92369f77539 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 19:00:49 +0000 Subject: Added GetProductId --- input/input-api.txt | 2 +- input/input-service.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index 42ce2755..8157adc9 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -50,7 +50,7 @@ Methods string GetAddress() Returns the service name. - string GetProductId() + uint16 GetProductId() Returns the product id. diff --git a/input/input-service.c b/input/input-service.c index c5d469e1..877a3675 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -843,7 +843,18 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, static DBusHandlerResult device_get_product_id(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &idev->hidp.product, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); } static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, -- cgit From 3ff37c86508033361fc1be271fd9895f3162ee03 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 19:03:36 +0000 Subject: Added GetVendorId --- input/input-api.txt | 2 +- input/input-service.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index 8157adc9..2658f3a6 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -54,7 +54,7 @@ Methods string GetAddress() Returns the product id. - string GetVendorId() + uint16 GetVendorId() Returns the vendor id. diff --git a/input/input-service.c b/input/input-service.c index 877a3675..f14edfe1 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -860,7 +860,18 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn, static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, DBusMessage *msg, void *data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + struct input_device *idev = data; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &idev->hidp.vendor, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); } static DBusHandlerResult device_set_timeout(DBusConnection *conn, -- cgit From a0aeaf15caa9e967f6be1a7b3a3087ff9122c7a9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 19:47:56 +0000 Subject: Moved set_nonblocking to common/dbus.c --- input/input-service.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index f14edfe1..c7c07283 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -471,31 +470,6 @@ static const char *create_input_path(uint8_t minor) return path; } -/* FIXME: Move to a common file. It is already used by audio and rfcomm */ -static int set_nonblocking(int fd) -{ - long arg; - - arg = fcntl(fd, F_GETFL); - if (arg < 0) { - error("fcntl(F_GETFL): %s (%d)", strerror(errno), errno); - return -1; - } - - /* Return if already nonblocking */ - if (arg & O_NONBLOCK) - return 0; - - arg |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, arg) < 0) { - error("fcntl(F_SETFL, O_NONBLOCK): %s (%d)", - strerror(errno), errno); - return -1; - } - - return 0; -} - static int l2cap_connect(struct pending_connect *pc, unsigned short psm, GIOFunc cb) { @@ -514,7 +488,7 @@ static int l2cap_connect(struct pending_connect *pc, if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto failed; - if (set_nonblocking(sk) < 0) + if (set_nonblocking(sk, NULL) < 0) goto failed; memset(&opts, 0, sizeof(opts)); -- cgit From 0e1bf963709b5fa4a953a7e97d9c343a2b617cd0 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 20:17:08 +0000 Subject: Set the default idle timeout to 30 sec --- input/input-service.c | 1 + 1 file changed, 1 insertion(+) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index c7c07283..8856e503 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -545,6 +545,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, isk = g_io_channel_unix_get_fd(chan); idev->hidp.intr_sock = isk; + idev->hidp.idle_to = 1800; /* 30 sec */ len = sizeof(ret); if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { -- cgit From d8dc9633f58ace9d5931839d91a091e555c74075 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 24 Jan 2007 22:02:06 +0000 Subject: Code cleanup(missing static modifier) --- input/input-service.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 8856e503..b2fecac3 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -83,7 +83,7 @@ struct pending_connect { DBusMessage *msg; }; -struct input_device *input_device_new(const char *addr) +static struct input_device *input_device_new(const char *addr) { struct input_device *idev; @@ -98,7 +98,7 @@ struct input_device *input_device_new(const char *addr) return idev; } -void input_device_free(struct input_device *idev) +static void input_device_free(struct input_device *idev) { if (!idev) return; @@ -107,7 +107,7 @@ void input_device_free(struct input_device *idev) free(idev); } -struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, +static struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, const char *adapter_path, const char *adapter, const char *peer) { struct pending_req *pr; @@ -125,7 +125,7 @@ struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, return pr; } -void pending_req_free(struct pending_req *pr) +static void pending_req_free(struct pending_req *pr) { if (!pr) return; @@ -913,7 +913,7 @@ struct input_manager { GSList *paths; /* Input registered paths */ }; -void input_manager_free(struct input_manager *mgr) +static void input_manager_free(struct input_manager *mgr) { if (!mgr) return; -- cgit From d0dc2769f9f1e9cd3ef3b430d7eff0d5d90a7e6b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 25 Jan 2007 14:25:07 +0000 Subject: Moved HID store related functions to a new file --- input/Makefile.am | 3 +- input/input-service.c | 219 +++++++++++++------------------------------------- input/server.c | 55 +------------ input/storage.c | 171 +++++++++++++++++++++++++++++++++++++++ input/storage.h | 37 +++++++++ 5 files changed, 268 insertions(+), 217 deletions(-) create mode 100644 input/storage.c create mode 100644 input/storage.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 6aa8ef1b..16061453 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -12,7 +12,8 @@ service_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = \ main.c server.h server.c \ - input-service.h input-service.c + input-service.h input-service.c \ + storage.h storage.c LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ diff --git a/input/input-service.c b/input/input-service.c index b2fecac3..8bbd7437 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -47,7 +47,9 @@ #include "dbus.h" #include "logging.h" #include "textfile.h" + #include "input-service.h" +#include "storage.h" #define INPUT_PATH "/org/bluez/input" #define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" @@ -62,14 +64,14 @@ const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; struct input_device { - char addr[18]; + bdaddr_t dba; struct hidp_connadd_req hidp; }; struct pending_req { char *adapter_path; /* Local adapter D-Bus path */ - char adapter[18]; /* Local adapter BT address */ - char peer[18]; /* Peer BT address */ + bdaddr_t sba; /* Local adapter BT address */ + bdaddr_t dba; /* Peer BT address */ DBusConnection *conn; DBusMessage *msg; sdp_record_t *pnp_rec; @@ -83,7 +85,7 @@ struct pending_connect { DBusMessage *msg; }; -static struct input_device *input_device_new(const char *addr) +static struct input_device *input_device_new(bdaddr_t *dba) { struct input_device *idev; @@ -93,7 +95,7 @@ static struct input_device *input_device_new(const char *addr) memset(idev, 0, sizeof(struct input_device)); - memcpy(idev->addr, addr, 18); + bacpy(&idev->dba, dba); return idev; } @@ -107,8 +109,9 @@ static void input_device_free(struct input_device *idev) free(idev); } -static struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, - const char *adapter_path, const char *adapter, const char *peer) +static struct pending_req *pending_req_new(DBusConnection *conn, + DBusMessage *msg, const char *adapter_path, + bdaddr_t *sba, bdaddr_t *dba) { struct pending_req *pr; pr = malloc(sizeof(struct pending_req)); @@ -117,8 +120,8 @@ static struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *ms memset(pr, 0, sizeof(struct pending_req)); pr->adapter_path = strdup(adapter_path); - strncpy(pr->adapter, adapter, 18); - strncpy(pr->peer, peer, 18); + bacpy(&pr->sba, sba); + bacpy(&pr->dba, dba); pr->conn = dbus_connection_ref(conn); pr->msg = dbus_message_ref(msg); @@ -230,126 +233,6 @@ static DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg, } -static inline int create_filename(char *buf, size_t size, - bdaddr_t *bdaddr, const char *name) -{ - char addr[18]; - - ba2str(bdaddr, addr); - - return create_name(buf, size, STORAGEDIR, addr, name); -} - -static int parse_stored_info(const char *str, struct hidp_connadd_req *req) -{ - char tmp[3], *desc; - unsigned int vendor, product, version, subclass, country, parser, pos; - int i; - - desc = malloc(4096); - if (!desc) - return -ENOMEM; - - memset(desc, 0, 4096); - - - sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", - &vendor, &product, &version, &subclass, &country, - &parser, desc, &req->flags, &pos); - - req->vendor = vendor; - req->product = product; - req->version = version; - req->subclass = subclass; - req->country = country; - req->parser = parser; - - snprintf(req->name, 128, str + pos); - - req->rd_size = strlen(desc) / 2; - req->rd_data = malloc(req->rd_size); - if (!req->rd_data) { - free(desc); - return -ENOMEM; - } - - memset(tmp, 0, sizeof(tmp)); - for (i = 0; i < req->rd_size; i++) { - memcpy(tmp, desc + (i * 2), 2); - req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); - } - - free(desc); - - return 0; -} - -/* FIXME: copied from hidd, move to a common library */ -static int get_stored_info(const char *local, const char *peer, - struct hidp_connadd_req *req) -{ - char filename[PATH_MAX + 1], *str; - int ret; - - create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); - - str = textfile_get(filename, peer); - if (!str) - return -ENOENT; - - ret = parse_stored_info(str, req); - - free(str); - - return ret; -} - -static int del_stored_info(const char *local, const char *peer) -{ - char filename[PATH_MAX + 1]; - - create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); - - return textfile_del(filename, peer); -} - -static int store_info(const char *local, const char *peer, - struct hidp_connadd_req *req) -{ - char filename[PATH_MAX + 1], *str, *desc; - int i, size, ret; - - create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); - - size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; - str = malloc(size); - if (!str) - return -ENOMEM; - - desc = malloc((req->rd_size * 2) + 1); - if (!desc) { - free(str); - return -ENOMEM; - } - - memset(desc, 0, (req->rd_size * 2) + 1); - for (i = 0; i < req->rd_size; i++) - sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); - - snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", - req->vendor, req->product, req->version, - req->subclass, req->country, req->parser, desc, - req->flags, req->name); - free(desc); - - create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - ret = textfile_put(filename, peer, str); - free(str); - - return ret; -} - static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist, *pdlist2; @@ -662,7 +545,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) } memset(&ci, 0, sizeof(struct hidp_conninfo)); - str2ba(idev->addr, &ci.bdaddr); + bacpy(&ci.bdaddr, &idev->dba); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { error("Can't retrive HID information: %s(%d)", strerror(errno), errno); @@ -676,7 +559,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) memset(&req, 0, sizeof(struct hidp_conndel_req)); - str2ba(idev->addr, &req.bdaddr); + bacpy(&req.bdaddr, &idev->dba); req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { error("Can't delete the HID device: %s(%d)", @@ -696,7 +579,7 @@ fail: return ret; } -static int is_connected(const char *addr) +static int is_connected(bdaddr_t *dba) { struct hidp_conninfo ci; int ctl; @@ -706,7 +589,7 @@ static int is_connected(const char *addr) return 0; memset(&ci, 0, sizeof(struct hidp_conninfo)); - str2ba(addr, &ci.bdaddr); + bacpy(&ci.bdaddr, dba); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); return 0; @@ -728,13 +611,11 @@ static DBusHandlerResult device_connect(DBusConnection *conn, { struct input_device *idev = data; struct pending_connect *pc; - bdaddr_t dba; - if (is_connected(idev->addr)) + if (is_connected(&idev->dba)) return err_connection_failed(conn, msg, "Already connected"); - str2ba(idev->addr, &dba); - pc = pending_connect_new(BDADDR_ANY, &dba, conn, msg); + pc = pending_connect_new(BDADDR_ANY, &idev->dba, conn, msg); if (!pc) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -767,7 +648,7 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *reply; dbus_bool_t connected; - connected = is_connected(idev->addr); + connected = is_connected(&idev->dba); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -784,7 +665,10 @@ static DBusHandlerResult device_get_address(DBusConnection *conn, { struct input_device *idev = data; DBusMessage *reply; - const char *paddr = idev->addr; + char addr[18]; + const char *paddr = addr; + + ba2str(&idev->dba, addr); reply = dbus_message_new_method_return(msg); if (!reply) @@ -909,7 +793,7 @@ static const DBusObjectPathVTable device_table = { * Input Manager methods */ struct input_manager { - char adapter[18]; /* Local adapter BT address */ + bdaddr_t sba; /* Local adapter BT address */ GSList *paths; /* Input registered paths */ }; @@ -978,7 +862,7 @@ static int unregister_input_device(DBusConnection *conn, const char *path) return 0; } -static int path_addr_cmp(const char *path, const char *addr) +static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) { struct input_device *idev; @@ -989,7 +873,7 @@ static int path_addr_cmp(const char *path, const char *addr) if (!idev) return -1; - return strcasecmp(idev->addr, addr); + return bacmp(&idev->dba, bdaddr); } static int get_record(struct pending_req *pr, uint32_t handle, @@ -997,14 +881,15 @@ static int get_record(struct pending_req *pr, uint32_t handle, { DBusMessage *msg; DBusPendingCall *pending; - const char *paddr; + 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; - paddr = pr->peer; + ba2str(&pr->dba, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_UINT32, &handle, @@ -1026,14 +911,15 @@ static int get_handles(struct pending_req *pr, const char *uuid, { DBusMessage *msg; DBusPendingCall *pending; - const char *paddr; + 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; - paddr = pr->peer; + ba2str(&pr->dba, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_STRING, &uuid, @@ -1087,7 +973,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(pr->peer); + idev = input_device_new(&pr->dba); extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) @@ -1107,7 +993,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) DBUS_TYPE_INVALID); send_message_and_unref(pr->conn, pr_reply); - store_info(pr->adapter, pr->peer, &idev->hidp); + store_device_info(&pr->sba, &pr->dba, &idev->hidp); fail: pending_req_free(pr); dbus_message_unref(reply); @@ -1244,9 +1130,10 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, struct input_device *idev; DBusMessage *reply; DBusError derr; - char adapter_path[32]; + char adapter[18], adapter_path[32]; const char *addr, *path; GSList *l; + bdaddr_t dba; int dev_id; dbus_error_init(&derr); @@ -1258,23 +1145,26 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - l = g_slist_find_custom(mgr->paths, addr, - (GCompareFunc) path_addr_cmp); + str2ba(addr, &dba); + l = g_slist_find_custom(mgr->paths, &dba, + (GCompareFunc) path_bdaddr_cmp); if (l) return err_already_exists(conn, msg, "Input Already exists"); - dev_id = hci_devid(mgr->adapter); + ba2str(&mgr->sba, adapter); + dev_id = hci_devid(adapter); snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); - idev = input_device_new(addr); + idev = input_device_new(&dba); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_stored_info(mgr->adapter, addr, &idev->hidp) < 0) { + + if (get_stored_device_info(&mgr->sba, &idev->dba, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ input_device_free(idev); - pr = pending_req_new(conn, msg, adapter_path, mgr->adapter, addr); + pr = pending_req_new(conn, msg, adapter_path, &mgr->sba, &dba); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1335,7 +1225,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, if (dbus_connection_get_object_path_data(conn, path, (void *) &idev) && idev) disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); - del_stored_info(mgr->adapter, idev->addr); + del_stored_device_info(&mgr->sba, &idev->dba); if (unregister_input_device(conn, path) < 0) { dbus_message_unref(reply); @@ -1424,9 +1314,11 @@ static void stored_input(char *key, char *value, void *data) DBusConnection *conn = data; struct input_device *idev; const char *path; + bdaddr_t dba; - idev = input_device_new(key); - if (parse_stored_info(value, &idev->hidp) < 0) { + str2ba(key, &dba); + idev = input_device_new(&dba); + if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; } @@ -1436,11 +1328,13 @@ static void stored_input(char *key, char *value, void *data) input_device_free(idev); } -static int register_stored_inputs(DBusConnection *conn, const char *local) +static int register_stored_inputs(DBusConnection *conn, bdaddr_t *sba) { char filename[PATH_MAX + 1]; + char addr[18]; - create_name(filename, PATH_MAX, STORAGEDIR, local, "hidd"); + ba2str(sba, addr); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); textfile_foreach(filename, stored_input, conn); return 0; @@ -1482,10 +1376,9 @@ int input_dbus_init(void) goto fail; } - ba2str(&sba, mgr->adapter); - + bacpy(&mgr->sba, &sba); /* Register well known HID devices */ - register_stored_inputs(connection, mgr->adapter); + register_stored_inputs(connection, &sba); return 0; fail: diff --git a/input/server.c b/input/server.c index b37c35ff..9e97490f 100644 --- a/input/server.c +++ b/input/server.c @@ -38,8 +38,9 @@ #include #include "logging.h" -#include "textfile.h" + #include "server.h" +#include "storage.h" struct session_data { bdaddr_t src; @@ -72,58 +73,6 @@ static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data return TRUE; } -static int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, - struct hidp_connadd_req *req) -{ - char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc; - unsigned int vendor, product, version, subclass, country, parser, pos; - int i; - - desc = malloc(4096); - if (!desc) - return -ENOMEM; - - memset(desc, 0, 4096); - - ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); - - ba2str(dst, addr); - str = textfile_get(filename, addr); - if (!str) { - free(desc); - return -EIO; - } - - sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", - &vendor, &product, &version, &subclass, &country, - &parser, desc, &req->flags, &pos); - - free(str); - - req->vendor = vendor; - req->product = product; - req->version = version; - req->subclass = subclass; - req->country = country; - req->parser = parser; - - snprintf(req->name, 128, str + pos); - - req->rd_size = strlen(desc) / 2; - req->rd_data = malloc(req->rd_size); - if (!req->rd_data) - return -ENOMEM; - - memset(tmp, 0, sizeof(tmp)); - for (i = 0; i < req->rd_size; i++) { - memcpy(tmp, desc + (i * 2), 2); - req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); - } - - return 0; -} - static void create_device(struct session_data *session) { struct hidp_connadd_req req; diff --git a/input/storage.c b/input/storage.c new file mode 100644 index 00000000..cc9f22db --- /dev/null +++ b/input/storage.c @@ -0,0 +1,171 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "textfile.h" + +#include "storage.h" + +static inline int create_filename(char *buf, size_t size, + bdaddr_t *bdaddr, const char *name) +{ + char addr[18]; + + ba2str(bdaddr, addr); + + return create_name(buf, size, STORAGEDIR, addr, name); +} + +int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) +{ + char tmp[3], *desc; + unsigned int vendor, product, version, subclass, country, parser, pos; + int i; + + desc = malloc(4096); + if (!desc) + return -ENOMEM; + + memset(desc, 0, 4096); + + + sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", + &vendor, &product, &version, &subclass, &country, + &parser, desc, &req->flags, &pos); + + req->vendor = vendor; + req->product = product; + req->version = version; + req->subclass = subclass; + req->country = country; + req->parser = parser; + + snprintf(req->name, 128, str + pos); + + req->rd_size = strlen(desc) / 2; + req->rd_data = malloc(req->rd_size); + if (!req->rd_data) { + free(desc); + return -ENOMEM; + } + + memset(tmp, 0, sizeof(tmp)); + for (i = 0; i < req->rd_size; i++) { + memcpy(tmp, desc + (i * 2), 2); + req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); + } + + free(desc); + + return 0; +} + +int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, + struct hidp_connadd_req *req) +{ + char filename[PATH_MAX + 1], *str; + char peer[18]; + int ret; + + create_filename(filename, PATH_MAX, sba, "hidd"); + + ba2str(dba, peer); + str = textfile_get(filename, peer); + if (!str) + return -ENOENT; + + ret = parse_stored_device_info(str, req); + + free(str); + + return ret; +} + +int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba) +{ + char filename[PATH_MAX + 1]; + char addr[18]; + + create_filename(filename, PATH_MAX, sba, "hidd"); + + ba2str(dba, addr); + + return textfile_del(filename, addr); +} + +int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req) +{ + char filename[PATH_MAX + 1], *str, *desc; + int i, size, ret; + char addr[18]; + + create_filename(filename, PATH_MAX, sba, "hidd"); + + size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; + str = malloc(size); + if (!str) + return -ENOMEM; + + desc = malloc((req->rd_size * 2) + 1); + if (!desc) { + free(str); + return -ENOMEM; + } + + memset(desc, 0, (req->rd_size * 2) + 1); + for (i = 0; i < req->rd_size; i++) + sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); + + snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", + req->vendor, req->product, req->version, + req->subclass, req->country, req->parser, desc, + req->flags, req->name); + free(desc); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + ba2str(dba, addr); + + ret = textfile_put(filename, addr, str); + free(str); + + return ret; +} diff --git a/input/storage.h b/input/storage.h new file mode 100644 index 00000000..2f245010 --- /dev/null +++ b/input/storage.h @@ -0,0 +1,37 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __H_INPUT_STORAGE_H +#define __H_INPUT_STORAGE_H + +int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, + struct hidp_connadd_req *req); + +int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba); + +int store_device_info(bdaddr_t *sba, bdaddr_t *dba, + struct hidp_connadd_req *req); + +int parse_stored_device_info(const char *str, + struct hidp_connadd_req *req); +#endif /* __H_INPUT_STORAGE_H */ -- cgit From 8362c93efbfe70942118fe1b148dbaff68c3ceb8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 25 Jan 2007 14:38:38 +0000 Subject: No #ifdef magic for local file includes --- input/storage.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/storage.h b/input/storage.h index 2f245010..adec8bf4 100644 --- a/input/storage.h +++ b/input/storage.h @@ -21,17 +21,13 @@ * */ -#ifndef __H_INPUT_STORAGE_H -#define __H_INPUT_STORAGE_H - int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, - struct hidp_connadd_req *req); + struct hidp_connadd_req *req); int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba); int store_device_info(bdaddr_t *sba, bdaddr_t *dba, - struct hidp_connadd_req *req); + struct hidp_connadd_req *req); int parse_stored_device_info(const char *str, - struct hidp_connadd_req *req); -#endif /* __H_INPUT_STORAGE_H */ + struct hidp_connadd_req *req); -- cgit From 8462276d5289bc23efee4d532248dc79476b6133 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 25 Jan 2007 14:44:06 +0000 Subject: Code cleanup --- input/input-service.c | 4 ++-- input/input-service.h | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 8bbd7437..5f40ffdc 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -536,7 +536,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) { struct hidp_conndel_req req; struct hidp_conninfo ci; - int ctl, err, ret = 0; + int ctl, err, ret = -1; ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { @@ -558,7 +558,6 @@ static int disconnect(struct input_device *idev, uint32_t flags) } memset(&req, 0, sizeof(struct hidp_conndel_req)); - bacpy(&req.bdaddr, &idev->dba); req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { @@ -1418,6 +1417,7 @@ void internal_service(const char *identifier) return; } + dbus_message_unref(msg); dbus_message_unref(reply); dbus_connection_flush(connection); diff --git a/input/input-service.h b/input/input-service.h index 179a02c5..6eefc6d4 100644 --- a/input/input-service.h +++ b/input/input-service.h @@ -21,12 +21,7 @@ * */ -#ifndef __INPUT_SERVICE_H -#define __INPUT_SERVICE_H - int input_dbus_init(void); void input_dbus_exit(void); void internal_service(const char *identifier); - -#endif /* __INPUT_SERVICE_H */ -- cgit From 24aaa3c3825fd26e34730fe64f5e375f7e94bb7d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 25 Jan 2007 15:06:06 +0000 Subject: Small cleanup --- input/storage.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/storage.c b/input/storage.c index cc9f22db..0452a1e9 100644 --- a/input/storage.c +++ b/input/storage.c @@ -45,7 +45,7 @@ #include "storage.h" static inline int create_filename(char *buf, size_t size, - bdaddr_t *bdaddr, const char *name) + bdaddr_t *bdaddr, const char *name) { char addr[18]; @@ -66,7 +66,6 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) memset(desc, 0, 4096); - sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", &vendor, &product, &version, &subclass, &country, &parser, desc, &req->flags, &pos); @@ -99,11 +98,11 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) } int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, - struct hidp_connadd_req *req) + struct hidp_connadd_req *req) { char filename[PATH_MAX + 1], *str; char peer[18]; - int ret; + int err; create_filename(filename, PATH_MAX, sba, "hidd"); @@ -112,11 +111,11 @@ int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, if (!str) return -ENOENT; - ret = parse_stored_device_info(str, req); + err = parse_stored_device_info(str, req); free(str); - return ret; + return err; } int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba) @@ -134,7 +133,7 @@ int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba) int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req) { char filename[PATH_MAX + 1], *str, *desc; - int i, size, ret; + int i, err, size; char addr[18]; create_filename(filename, PATH_MAX, sba, "hidd"); @@ -158,14 +157,16 @@ int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req req->vendor, req->product, req->version, req->subclass, req->country, req->parser, desc, req->flags, req->name); + free(desc); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dba, addr); - ret = textfile_put(filename, addr, str); + err = textfile_put(filename, addr, str); + free(str); - return ret; + return err; } -- cgit From 1f1bd7f99b9e9e87f3fca0499154d0959f089dea Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 25 Jan 2007 15:13:45 +0000 Subject: Initialize subpath with '\0' --- input/input-service.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 5f40ffdc..871075a7 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -318,6 +318,9 @@ static const char *create_input_path(uint8_t minor) case 0xc0: strcpy(subpath, "combo"); break; + default: + subpath[0] = '\0'; + break; } if ((minor & 0x3f) && (strlen(subpath) > 0)) -- cgit From 97e3051ec51ac5bdcb37a371249360163eaf5709 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 25 Jan 2007 17:27:52 +0000 Subject: set_nonblocking: removed err argument --- input/input-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 871075a7..4f9345b3 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -374,7 +374,7 @@ static int l2cap_connect(struct pending_connect *pc, if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto failed; - if (set_nonblocking(sk, NULL) < 0) + if (set_nonblocking(sk) < 0) goto failed; memset(&opts, 0, sizeof(opts)); -- cgit From aa6e167ce4b28f0997c53af89194dab39c082119 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 25 Jan 2007 18:08:37 +0000 Subject: Code cleanup --- input/input-service.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 4f9345b3..c1df0a37 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -539,23 +539,18 @@ static int disconnect(struct input_device *idev, uint32_t flags) { struct hidp_conndel_req req; struct hidp_conninfo ci; - int ctl, err, ret = -1; + int ctl, err; ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { error("Can't open HIDP control socket"); - return -1; + return -errno; } memset(&ci, 0, sizeof(struct hidp_conninfo)); bacpy(&ci.bdaddr, &idev->dba); - if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { - error("Can't retrive HID information: %s(%d)", - strerror(errno), errno); - goto fail; - } - - if (ci.state != BT_CONNECTED) { + if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || + (ci.state != BT_CONNECTED)) { errno = ENOTCONN; goto fail; } @@ -569,7 +564,9 @@ static int disconnect(struct input_device *idev, uint32_t flags) goto fail; } - ret = 0; + close(ctl); + + return 0; fail: err = errno; close(ctl); @@ -578,7 +575,7 @@ fail: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - return ret; + return -errno; } static int is_connected(bdaddr_t *dba) -- cgit From 5753e415a5ef3308f1408ad07623ae07047faaf5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 26 Jan 2007 09:53:30 +0000 Subject: Add encryption support --- input/input-service.c | 82 +++++++++++++++++++++++++++++++++------------------ input/server.c | 10 +++++++ input/storage.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ input/storage.h | 2 ++ 4 files changed, 140 insertions(+), 29 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index c1df0a37..dbbdb877 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -60,6 +60,7 @@ #define L2CAP_PSM_HIDP_INTR 0x13 static DBusConnection *connection = NULL; + const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; @@ -68,6 +69,11 @@ struct input_device { struct hidp_connadd_req hidp; }; +struct input_manager { + bdaddr_t sba; /* Local adapter BT address */ + GSList *paths; /* Input registered paths */ +}; + struct pending_req { char *adapter_path; /* Local adapter D-Bus path */ bdaddr_t sba; /* Local adapter BT address */ @@ -110,8 +116,8 @@ static void input_device_free(struct input_device *idev) } static struct pending_req *pending_req_new(DBusConnection *conn, - DBusMessage *msg, const char *adapter_path, - bdaddr_t *sba, bdaddr_t *dba) + DBusMessage *msg, const char *adapter_path, + bdaddr_t *sba, bdaddr_t *dba) { struct pending_req *pr; pr = malloc(sizeof(struct pending_req)); @@ -357,7 +363,7 @@ static const char *create_input_path(uint8_t minor) } static int l2cap_connect(struct pending_connect *pc, - unsigned short psm, GIOFunc cb) + unsigned short psm, GIOFunc cb) { GIOChannel *io; struct sockaddr_l2 addr; @@ -413,7 +419,7 @@ failed: } static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct pending_connect *pc) { struct input_device *idev; int ctl, isk, ret, err; @@ -431,7 +437,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, isk = g_io_channel_unix_get_fd(chan); idev->hidp.intr_sock = isk; - idev->hidp.idle_to = 1800; /* 30 sec */ + idev->hidp.idle_to = 30 * 60; /* 30 minutes */ len = sizeof(ret); if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { @@ -452,11 +458,21 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, error("Can't open HIDP control socket"); goto failed; } + + if (idev->hidp.subclass & 0x40) { + err = encrypt_link(&pc->sba, &pc->dba); + if (err < 0) { + close(ctl); + goto failed; + } + } + if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { err = errno; close(ctl); goto failed; } + close(ctl); send_message_and_unref(pc->conn, @@ -466,6 +482,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, g_io_channel_unref(chan); return FALSE; + failed: if (isk > 0) close(isk); @@ -479,7 +496,7 @@ failed: } static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct pending_connect *pc) { struct input_device *idev; int ret, csk, err; @@ -511,6 +528,7 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, error("connect(): %s (%d)", strerror(ret), ret); goto failed; } + /* Connect to the HID interrupt channel */ if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, (GIOFunc) interrupt_connect_cb) < 0) { @@ -550,7 +568,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) memset(&ci, 0, sizeof(struct hidp_conninfo)); bacpy(&ci.bdaddr, &idev->dba); if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || - (ci.state != BT_CONNECTED)) { + (ci.state != BT_CONNECTED)) { errno = ENOTCONN; goto fail; } @@ -606,15 +624,17 @@ static int is_connected(bdaddr_t *dba) * Input Device methods */ static DBusHandlerResult device_connect(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; + struct input_manager *mgr; struct pending_connect *pc; if (is_connected(&idev->dba)) return err_connection_failed(conn, msg, "Already connected"); - pc = pending_connect_new(BDADDR_ANY, &idev->dba, conn, msg); + dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); + pc = pending_connect_new(&mgr->sba, &idev->dba, conn, msg); if (!pc) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -629,7 +649,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } static DBusHandlerResult device_disconnect(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; @@ -641,7 +661,7 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, } static DBusHandlerResult device_is_connected(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; DBusMessage *reply; @@ -660,13 +680,13 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, } static DBusHandlerResult device_get_address(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; DBusMessage *reply; char addr[18]; const char *paddr = addr; - + ba2str(&idev->dba, addr); reply = dbus_message_new_method_return(msg); @@ -681,7 +701,7 @@ static DBusHandlerResult device_get_address(DBusConnection *conn, } static DBusHandlerResult device_get_name(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; DBusMessage *reply; @@ -699,7 +719,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, } static DBusHandlerResult device_get_product_id(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; DBusMessage *reply; @@ -716,7 +736,7 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn, } static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_device *idev = data; DBusMessage *reply; @@ -733,13 +753,13 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, } static DBusHandlerResult device_set_timeout(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult device_message(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { const char *iface, *member; @@ -791,19 +811,16 @@ static const DBusObjectPathVTable device_table = { /* * Input Manager methods */ -struct input_manager { - bdaddr_t sba; /* Local adapter BT address */ - GSList *paths; /* Input registered paths */ -}; - 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); } + free(mgr); } @@ -876,7 +893,7 @@ static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) } static int get_record(struct pending_req *pr, uint32_t handle, - DBusPendingCallNotifyFunction cb) + DBusPendingCallNotifyFunction cb) { DBusMessage *msg; DBusPendingCall *pending; @@ -906,7 +923,7 @@ static int get_record(struct pending_req *pr, uint32_t handle, } static int get_handles(struct pending_req *pr, const char *uuid, - DBusPendingCallNotifyFunction cb) + DBusPendingCallNotifyFunction cb) { DBusMessage *msg; DBusPendingCall *pending; @@ -1068,9 +1085,12 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) else goto done; } + err_failed(pr->conn, pr->msg, "SDP error"); + fail: pending_req_free(pr); + done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -1115,15 +1135,17 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) } goto done; + fail: 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) + DBusMessage *msg, void *data) { struct input_manager *mgr = data; struct input_device *idev; @@ -1186,6 +1208,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, input_device_free(idev); return DBUS_HANDLER_RESULT_NEED_MEMORY; } + dbus_message_append_args(reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); @@ -1194,7 +1217,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, } static DBusHandlerResult manager_remove_device(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_manager *mgr = data; struct input_device *idev; @@ -1238,7 +1261,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, } static DBusHandlerResult manager_list_devices(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct input_manager *mgr = data; DBusMessageIter iter, iter_array; @@ -1265,7 +1288,7 @@ static DBusHandlerResult manager_list_devices(DBusConnection *conn, } static DBusHandlerResult manager_message(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { const char *path, *iface, *member; @@ -1380,6 +1403,7 @@ int input_dbus_init(void) register_stored_inputs(connection, &sba); return 0; + fail: input_manager_free(mgr); diff --git a/input/server.c b/input/server.c index 9e97490f..b140bb6b 100644 --- a/input/server.c +++ b/input/server.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include @@ -98,6 +100,14 @@ static void create_device(struct session_data *session) goto cleanup; } + if (req.subclass & 0x40) { + if (encrypt_link(&session->src, &session->dst) < 0) { + if (req.rd_data) + free(req.rd_data); + goto cleanup; + } + } + info("New input device %s (%s)", addr, req.name); err = ioctl(ctl, HIDPCONNADD, &req); diff --git a/input/storage.c b/input/storage.c index 0452a1e9..c46b8d82 100644 --- a/input/storage.c +++ b/input/storage.c @@ -35,12 +35,16 @@ #include #include #include +#include #include #include #include +#include +#include #include "textfile.h" +#include "logging.h" #include "storage.h" @@ -170,3 +174,74 @@ int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req return err; } + +int encrypt_link(bdaddr_t *src, bdaddr_t *dst) +{ + char filename[PATH_MAX + 1]; + struct hci_conn_info_req *cr; + int dd, err, dev_id; + char addr[18], *str; + + create_filename(filename, PATH_MAX, src, "linkkeys"); + + ba2str(dst, addr); + + str = textfile_get(filename, addr); + if (!str) { + error("Encryption link key not found"); + return -ENOKEY; + } + + free(str); + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) + return -ENOMEM; + + ba2str(src, addr); + + dev_id = hci_devid(addr); + if (dev_id < 0) { + free(cr); + return -errno; + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + free(cr); + return -errno; + } + + memset(cr, 0, sizeof(*cr) + sizeof(struct hci_conn_info)); + bacpy(&cr->bdaddr, dst); + cr->type = ACL_LINK; + + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) + goto fail; + + if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 1000) < 0) { + error("Link authentication failed: %s (%d)", + strerror(errno), errno); + goto fail; + } + + if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 1000) < 0) { + error("Link encryption failed: %s (%d)", + strerror(errno), errno); + goto fail; + } + + free(cr); + + hci_close_dev(dd); + + return 0; + +fail: + free(cr); + + err = errno; + hci_close_dev(dd); + + return -err; +} diff --git a/input/storage.h b/input/storage.h index adec8bf4..68b5c535 100644 --- a/input/storage.h +++ b/input/storage.h @@ -31,3 +31,5 @@ int store_device_info(bdaddr_t *sba, bdaddr_t *dba, int parse_stored_device_info(const char *str, struct hidp_connadd_req *req); + +int encrypt_link(bdaddr_t *src, bdaddr_t *dst); -- cgit From 5d6c22d60f55e477d42a546da9c04339c735789b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 26 Jan 2007 14:19:07 +0000 Subject: Code standard(variables names): replaced sba to src and dba to dst --- input/input-service.c | 98 +++++++++++++++++++++++++-------------------------- input/storage.c | 18 +++++----- input/storage.h | 6 ++-- 3 files changed, 61 insertions(+), 61 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index dbbdb877..02903d0e 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -65,19 +65,19 @@ const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; struct input_device { - bdaddr_t dba; + bdaddr_t dst; struct hidp_connadd_req hidp; }; struct input_manager { - bdaddr_t sba; /* Local adapter BT address */ + 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 sba; /* Local adapter BT address */ - bdaddr_t dba; /* Peer BT address */ + bdaddr_t src; /* Local adapter BT address */ + bdaddr_t dst; /* Peer BT address */ DBusConnection *conn; DBusMessage *msg; sdp_record_t *pnp_rec; @@ -85,13 +85,13 @@ struct pending_req { }; struct pending_connect { - bdaddr_t sba; - bdaddr_t dba; + bdaddr_t src; + bdaddr_t dst; DBusConnection *conn; DBusMessage *msg; }; -static struct input_device *input_device_new(bdaddr_t *dba) +static struct input_device *input_device_new(bdaddr_t *dst) { struct input_device *idev; @@ -101,7 +101,7 @@ static struct input_device *input_device_new(bdaddr_t *dba) memset(idev, 0, sizeof(struct input_device)); - bacpy(&idev->dba, dba); + bacpy(&idev->dst, dst); return idev; } @@ -117,7 +117,7 @@ static void input_device_free(struct input_device *idev) static struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, const char *adapter_path, - bdaddr_t *sba, bdaddr_t *dba) + bdaddr_t *src, bdaddr_t *dst) { struct pending_req *pr; pr = malloc(sizeof(struct pending_req)); @@ -126,8 +126,8 @@ static struct pending_req *pending_req_new(DBusConnection *conn, memset(pr, 0, sizeof(struct pending_req)); pr->adapter_path = strdup(adapter_path); - bacpy(&pr->sba, sba); - bacpy(&pr->dba, dba); + bacpy(&pr->src, src); + bacpy(&pr->dst, dst); pr->conn = dbus_connection_ref(conn); pr->msg = dbus_message_ref(msg); @@ -151,7 +151,7 @@ static void pending_req_free(struct pending_req *pr) free(pr); } -static struct pending_connect *pending_connect_new(bdaddr_t *sba, bdaddr_t *dba, +static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, DBusConnection *conn, DBusMessage *msg) { struct pending_connect *pc; @@ -160,8 +160,8 @@ static struct pending_connect *pending_connect_new(bdaddr_t *sba, bdaddr_t *dba, return NULL; memset(pc, 0, sizeof(struct pending_connect)); - bacpy(&pc->sba, sba); - bacpy(&pc->dba, dba); + bacpy(&pc->src, src); + bacpy(&pc->dst, dst); pc->conn = dbus_connection_ref(conn); pc->msg = dbus_message_ref(msg); @@ -375,7 +375,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->sba); + bacpy(&addr.l2_bdaddr, &pc->src); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto failed; @@ -393,7 +393,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->dba); + bacpy(&addr.l2_bdaddr, &pc->dst); addr.l2_psm = htobs(psm); io = g_io_channel_unix_new(sk); @@ -460,7 +460,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&pc->sba, &pc->dba); + err = encrypt_link(&pc->src, &pc->dst); if (err < 0) { close(ctl); goto failed; @@ -566,7 +566,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) } memset(&ci, 0, sizeof(struct hidp_conninfo)); - bacpy(&ci.bdaddr, &idev->dba); + bacpy(&ci.bdaddr, &idev->dst); if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || (ci.state != BT_CONNECTED)) { errno = ENOTCONN; @@ -574,7 +574,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) } memset(&req, 0, sizeof(struct hidp_conndel_req)); - bacpy(&req.bdaddr, &idev->dba); + bacpy(&req.bdaddr, &idev->dst); req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { error("Can't delete the HID device: %s(%d)", @@ -596,7 +596,7 @@ fail: return -errno; } -static int is_connected(bdaddr_t *dba) +static int is_connected(bdaddr_t *dst) { struct hidp_conninfo ci; int ctl; @@ -606,7 +606,7 @@ static int is_connected(bdaddr_t *dba) return 0; memset(&ci, 0, sizeof(struct hidp_conninfo)); - bacpy(&ci.bdaddr, dba); + bacpy(&ci.bdaddr, dst); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); return 0; @@ -630,11 +630,11 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct input_manager *mgr; struct pending_connect *pc; - if (is_connected(&idev->dba)) + if (is_connected(&idev->dst)) return err_connection_failed(conn, msg, "Already connected"); dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - pc = pending_connect_new(&mgr->sba, &idev->dba, conn, msg); + pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); if (!pc) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -667,7 +667,7 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *reply; dbus_bool_t connected; - connected = is_connected(&idev->dba); + connected = is_connected(&idev->dst); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -687,7 +687,7 @@ static DBusHandlerResult device_get_address(DBusConnection *conn, char addr[18]; const char *paddr = addr; - ba2str(&idev->dba, addr); + ba2str(&idev->dst, addr); reply = dbus_message_new_method_return(msg); if (!reply) @@ -889,7 +889,7 @@ static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) if (!idev) return -1; - return bacmp(&idev->dba, bdaddr); + return bacmp(&idev->dst, bdaddr); } static int get_record(struct pending_req *pr, uint32_t handle, @@ -905,7 +905,7 @@ static int get_record(struct pending_req *pr, uint32_t handle, if (!msg) return -1; - ba2str(&pr->dba, addr); + ba2str(&pr->dst, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_UINT32, &handle, @@ -935,7 +935,7 @@ static int get_handles(struct pending_req *pr, const char *uuid, if (!msg) return -1; - ba2str(&pr->dba, addr); + ba2str(&pr->dst, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_STRING, &uuid, @@ -989,7 +989,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dba); + idev = input_device_new(&pr->dst); extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) @@ -1009,7 +1009,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) DBUS_TYPE_INVALID); send_message_and_unref(pr->conn, pr_reply); - store_device_info(&pr->sba, &pr->dba, &idev->hidp); + store_device_info(&pr->src, &pr->dst, &idev->hidp); fail: pending_req_free(pr); dbus_message_unref(reply); @@ -1154,7 +1154,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, char adapter[18], adapter_path[32]; const char *addr, *path; GSList *l; - bdaddr_t dba; + bdaddr_t dst; int dev_id; dbus_error_init(&derr); @@ -1166,26 +1166,26 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - str2ba(addr, &dba); - l = g_slist_find_custom(mgr->paths, &dba, + 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->sba, adapter); + ba2str(&mgr->src, adapter); dev_id = hci_devid(adapter); snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); - idev = input_device_new(&dba); + idev = input_device_new(&dst); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_stored_device_info(&mgr->sba, &idev->dba, &idev->hidp) < 0) { + if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ input_device_free(idev); - pr = pending_req_new(conn, msg, adapter_path, &mgr->sba, &dba); + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1247,7 +1247,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, if (dbus_connection_get_object_path_data(conn, path, (void *) &idev) && idev) disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); - del_stored_device_info(&mgr->sba, &idev->dba); + del_stored_device_info(&mgr->src, &idev->dst); if (unregister_input_device(conn, path) < 0) { dbus_message_unref(reply); @@ -1336,10 +1336,10 @@ static void stored_input(char *key, char *value, void *data) DBusConnection *conn = data; struct input_device *idev; const char *path; - bdaddr_t dba; + bdaddr_t dst; - str2ba(key, &dba); - idev = input_device_new(&dba); + str2ba(key, &dst); + idev = input_device_new(&dst); if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; @@ -1350,12 +1350,12 @@ static void stored_input(char *key, char *value, void *data) input_device_free(idev); } -static int register_stored_inputs(DBusConnection *conn, bdaddr_t *sba) +static int register_stored_inputs(DBusConnection *conn, bdaddr_t *src) { char filename[PATH_MAX + 1]; char addr[18]; - ba2str(sba, addr); + ba2str(src, addr); create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); textfile_foreach(filename, stored_input, conn); @@ -1365,7 +1365,7 @@ static int register_stored_inputs(DBusConnection *conn, bdaddr_t *sba) int input_dbus_init(void) { struct input_manager *mgr; - bdaddr_t sba; + bdaddr_t src; int dev_id; connection = init_dbus(NULL, NULL, NULL); @@ -1386,21 +1386,21 @@ int input_dbus_init(void) info("Registered input manager path:%s", INPUT_PATH); /* Set the default adapter */ - bacpy(&sba, BDADDR_ANY); - dev_id = hci_get_route(&sba); + 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, &sba) < 0) { + if (hci_devba(dev_id, &src) < 0) { error("Can't get local adapter device info"); goto fail; } - bacpy(&mgr->sba, &sba); + bacpy(&mgr->src, &src); /* Register well known HID devices */ - register_stored_inputs(connection, &sba); + register_stored_inputs(connection, &src); return 0; diff --git a/input/storage.c b/input/storage.c index c46b8d82..fab7d6c2 100644 --- a/input/storage.c +++ b/input/storage.c @@ -101,16 +101,16 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) return 0; } -int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, +int get_stored_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req) { char filename[PATH_MAX + 1], *str; char peer[18]; int err; - create_filename(filename, PATH_MAX, sba, "hidd"); + create_filename(filename, PATH_MAX, src, "hidd"); - ba2str(dba, peer); + ba2str(dst, peer); str = textfile_get(filename, peer); if (!str) return -ENOENT; @@ -122,25 +122,25 @@ int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, return err; } -int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba) +int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst) { char filename[PATH_MAX + 1]; char addr[18]; - create_filename(filename, PATH_MAX, sba, "hidd"); + create_filename(filename, PATH_MAX, src, "hidd"); - ba2str(dba, addr); + ba2str(dst, addr); return textfile_del(filename, addr); } -int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req) +int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req) { char filename[PATH_MAX + 1], *str, *desc; int i, err, size; char addr[18]; - create_filename(filename, PATH_MAX, sba, "hidd"); + create_filename(filename, PATH_MAX, src, "hidd"); size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; str = malloc(size); @@ -166,7 +166,7 @@ int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - ba2str(dba, addr); + ba2str(dst, addr); err = textfile_put(filename, addr, str); diff --git a/input/storage.h b/input/storage.h index 68b5c535..09a696cf 100644 --- a/input/storage.h +++ b/input/storage.h @@ -21,12 +21,12 @@ * */ -int get_stored_device_info(bdaddr_t *sba, bdaddr_t *dba, +int get_stored_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req); -int del_stored_device_info(bdaddr_t *sba, bdaddr_t *dba); +int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst); -int store_device_info(bdaddr_t *sba, bdaddr_t *dba, +int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req); int parse_stored_device_info(const char *str, -- cgit From 10cdcaa9bc6a49d98dcd3b3c1bf3c807ff82a578 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 26 Jan 2007 15:02:48 +0000 Subject: Check if the HCI_LM_ENCRYPT is already active --- input/storage.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'input') diff --git a/input/storage.c b/input/storage.c index fab7d6c2..5f467efb 100644 --- a/input/storage.c +++ b/input/storage.c @@ -219,6 +219,11 @@ int encrypt_link(bdaddr_t *src, bdaddr_t *dst) if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) goto fail; + if (cr->conn_info->link_mode & HCI_LM_ENCRYPT) { + /* Already encrypted */ + goto done; + } + if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 1000) < 0) { error("Link authentication failed: %s (%d)", strerror(errno), errno); @@ -231,6 +236,7 @@ int encrypt_link(bdaddr_t *src, bdaddr_t *dst) goto fail; } +done: free(cr); hci_close_dev(dd); -- cgit From f84e31fac1a1f7cf602afac6688bb4b9b02babb9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 26 Jan 2007 16:21:47 +0000 Subject: Close the control and interrupt sockets after call ioctl HIDPCONNADD --- input/input-service.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/input-service.c b/input/input-service.c index 02903d0e..3a309068 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -473,22 +473,24 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, goto failed; } - close(ctl); send_message_and_unref(pc->conn, dbus_message_new_method_return(pc->msg)); - pending_connect_free(pc); - g_io_channel_unref(chan); - - return FALSE; - + close (ctl); + goto cleanup; failed: + err_connection_failed(pc->conn, pc->msg, strerror(err)); + +cleanup: if (isk > 0) close(isk); + close(idev->hidp.ctrl_sock); + idev->hidp.intr_sock = -1; - err_connection_failed(pc->conn, pc->msg, strerror(err)); + idev->hidp.ctrl_sock = -1; + pending_connect_free(pc); g_io_channel_unref(chan); -- cgit From 6a5605954320fe1d43fa6957e07ec4bcc9724454 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 28 Jan 2007 18:06:45 +0000 Subject: Rename input-service.[ch] into device.[ch] --- input/Makefile.am | 6 +- input/device.c | 1450 +++++++++++++++++++++++++++++++++++++++++++++++++ input/device.h | 27 + input/input-service.c | 1450 ------------------------------------------------- input/input-service.h | 27 - input/main.c | 2 +- 6 files changed, 1480 insertions(+), 1482 deletions(-) create mode 100644 input/device.c create mode 100644 input/device.h delete mode 100644 input/input-service.c delete mode 100644 input/input-service.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 16061453..e39bd254 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -10,10 +10,8 @@ servicedir = $(libdir)/bluetooth service_PROGRAMS = bluetoothd-service-input -bluetoothd_service_input_SOURCES = \ - main.c server.h server.c \ - input-service.h input-service.c \ - storage.h storage.c +bluetoothd_service_input_SOURCES = main.c \ + server.h server.c device.h device.c storage.h storage.c LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ diff --git a/input/device.c b/input/device.c new file mode 100644 index 00000000..421b6c20 --- /dev/null +++ b/input/device.c @@ -0,0 +1,1450 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "dbus.h" +#include "logging.h" +#include "textfile.h" + +#include "storage.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 + +static DBusConnection *connection = NULL; + +const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; +const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; + +struct input_device { + bdaddr_t dst; + struct hidp_connadd_req hidp; +}; + +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; +}; + +struct pending_connect { + bdaddr_t src; + bdaddr_t dst; + DBusConnection *conn; + DBusMessage *msg; +}; + +static struct input_device *input_device_new(bdaddr_t *dst) +{ + struct input_device *idev; + + idev = malloc(sizeof(struct input_device)); + if (!idev) + return NULL; + + memset(idev, 0, sizeof(struct input_device)); + + bacpy(&idev->dst, dst); + + return idev; +} + +static void input_device_free(struct input_device *idev) +{ + if (!idev) + return; + if (idev->hidp.rd_data) + free(idev->hidp.rd_data); + 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 = malloc(sizeof(struct pending_req)); + if (!pr) + return NULL; + + memset(pr, 0, sizeof(struct pending_req)); + pr->adapter_path = 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) + 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); + free(pr); +} + +static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, + DBusConnection *conn, DBusMessage *msg) +{ + struct pending_connect *pc; + pc = malloc(sizeof(struct pending_connect)); + if (!pc) + return NULL; + + memset(pc, 0, sizeof(struct pending_connect)); + bacpy(&pc->src, src); + bacpy(&pc->dst, dst); + pc->conn = dbus_connection_ref(conn); + pc->msg = dbus_message_ref(msg); + + return pc; +} + +static void pending_connect_free(struct pending_connect *pc) +{ + if (!pc) + return; + if (pc->conn) + dbus_connection_unref(pc->conn); + if (pc->msg) + dbus_message_unref(pc->msg); + free(pc); +} + +/* + * 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_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, 0x0201); + req->parser = pdlist ? pdlist->val.uint16 : 0x0100; + + pdlist = sdp_data_get(rec, 0x0202); + req->subclass = pdlist ? pdlist->val.uint8 : 0; + + pdlist = sdp_data_get(rec, 0x0203); + req->country = pdlist ? pdlist->val.uint8 : 0; + + pdlist = sdp_data_get(rec, 0x0204); + attr_val = pdlist ? pdlist->val.uint8 : 0; + if (attr_val) + req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); + + pdlist = sdp_data_get(rec, 0x020E); + attr_val = pdlist ? pdlist->val.uint8 : 0; + if (attr_val) + req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); + + pdlist = sdp_data_get(rec, 0x0206); + if (pdlist) { + pdlist = pdlist->val.dataseq; + pdlist = pdlist->val.dataseq; + pdlist = pdlist->next; + + req->rd_data = malloc(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, 0x0201); + req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; + + pdlist = sdp_data_get(rec, 0x0202); + req->product = pdlist ? pdlist->val.uint16 : 0x0000; + + pdlist = sdp_data_get(rec, 0x0203); + req->version = pdlist ? pdlist->val.uint16 : 0x0000; +} + +static const char *create_input_path(uint8_t minor) +{ + static char path[48]; + char subpath[32]; + static int next_id = 0; + + switch (minor & 0xc0) { + case 0x40: + strcpy(subpath, "keyboard"); + break; + case 0x80: + strcpy(subpath, "pointing"); + break; + case 0xc0: + strcpy(subpath, "combo"); + break; + default: + subpath[0] = '\0'; + break; + } + + if ((minor & 0x3f) && (strlen(subpath) > 0)) + strcat(subpath, "/"); + + switch (minor & 0x3f) { + case 0x00: + break; + case 0x01: + strcat(subpath, "joystick"); + break; + case 0x02: + strcat(subpath, "gamepad"); + break; + case 0x03: + strcat(subpath, "remotecontrol"); + break; + case 0x04: + strcat(subpath, "sensing"); + break; + case 0x05: + strcat(subpath, "digitizertablet"); + break; + case 0x06: + strcat(subpath, "cardreader"); + break; + default: + strcat(subpath, "reserved"); + break; + } + + snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++); + return path; +} + +static int l2cap_connect(struct pending_connect *pc, + unsigned short psm, GIOFunc cb) +{ + GIOChannel *io; + struct sockaddr_l2 addr; + struct l2cap_options opts; + int sk, err; + + if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, &pc->src); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) + goto failed; + + if (set_nonblocking(sk) < 0) + goto failed; + + memset(&opts, 0, sizeof(opts)); + opts.imtu = HIDP_DEFAULT_MTU; + opts.omtu = HIDP_DEFAULT_MTU; + opts.flush_to = 0xffff; + + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) + goto failed; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, &pc->dst); + addr.l2_psm = htobs(psm); + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, FALSE); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (!(errno == EAGAIN || errno == EINPROGRESS)) + goto failed; + + g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, pc); + } else { + cb(io, G_IO_OUT, pc); + } + + return 0; + +failed: + err = errno; + close(sk); + errno = err; + + return -1; +} + +static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + struct input_device *idev; + int ctl, isk, ret, err; + socklen_t len; + const char *path; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + isk = -1; + goto failed; + } + + isk = g_io_channel_unix_get_fd(chan); + idev->hidp.intr_sock = isk; + idev->hidp.idle_to = 30 * 60; /* 30 minutes */ + + len = sizeof(ret); + if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + err = errno; + error("Can't open HIDP control socket"); + goto failed; + } + + if (idev->hidp.subclass & 0x40) { + err = encrypt_link(&pc->src, &pc->dst); + if (err < 0) { + close(ctl); + goto failed; + } + } + + if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { + err = errno; + close(ctl); + goto failed; + } + + + send_message_and_unref(pc->conn, + dbus_message_new_method_return(pc->msg)); + + close (ctl); + goto cleanup; +failed: + err_connection_failed(pc->conn, pc->msg, strerror(err)); + +cleanup: + if (isk > 0) + close(isk); + + close(idev->hidp.ctrl_sock); + + idev->hidp.intr_sock = -1; + idev->hidp.ctrl_sock = -1; + + pending_connect_free(pc); + g_io_channel_unref(chan); + + return FALSE; +} + +static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + struct input_device *idev; + int ret, csk, err; + socklen_t len; + const char *path; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + csk = -1; + goto failed; + } + + csk = g_io_channel_unix_get_fd(chan); + /* Set HID control channel */ + idev->hidp.ctrl_sock = csk; + + len = sizeof(ret); + if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + /* Connect to the HID interrupt channel */ + if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb) < 0) { + + err = errno; + error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + goto failed; + } + + g_io_channel_unref(chan); + return FALSE; + +failed: + if (csk > 0) + close(csk); + + idev->hidp.ctrl_sock = -1; + err_connection_failed(pc->conn, pc->msg, strerror(err)); + pending_connect_free(pc); + g_io_channel_unref(chan); + + return FALSE; +} + +static int disconnect(struct input_device *idev, uint32_t flags) +{ + struct hidp_conndel_req req; + struct hidp_conninfo ci; + int ctl, err; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP control socket"); + return -errno; + } + + memset(&ci, 0, sizeof(struct hidp_conninfo)); + bacpy(&ci.bdaddr, &idev->dst); + if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || + (ci.state != BT_CONNECTED)) { + errno = ENOTCONN; + goto fail; + } + + memset(&req, 0, sizeof(struct hidp_conndel_req)); + bacpy(&req.bdaddr, &idev->dst); + req.flags = flags; + if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { + error("Can't delete the HID device: %s(%d)", + strerror(errno), errno); + goto fail; + } + + close(ctl); + + return 0; +fail: + err = errno; + close(ctl); + errno = err; + + idev->hidp.intr_sock = -1; + idev->hidp.ctrl_sock = -1; + + return -errno; +} + +static int is_connected(bdaddr_t *dst) +{ + struct hidp_conninfo ci; + int ctl; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) + return 0; + + memset(&ci, 0, sizeof(struct hidp_conninfo)); + bacpy(&ci.bdaddr, dst); + if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { + close(ctl); + return 0; + } + + close(ctl); + + if (ci.state != BT_CONNECTED) + return 0; + else + return 1; +} + +/* + * Input Device methods + */ +static DBusHandlerResult device_connect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + struct input_manager *mgr; + struct pending_connect *pc; + + if (is_connected(&idev->dst)) + return err_connection_failed(conn, msg, "Already connected"); + + dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); + pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); + if (!pc) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb) < 0) { + error("L2CAP connect failed: %s(%d)", strerror(errno), errno); + pending_connect_free(pc); + return err_connection_failed(conn, msg, strerror(errno)); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult device_disconnect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + + if (disconnect(idev, 0) < 0) + return err_failed(conn, msg, strerror(errno)); + + return send_message_and_unref(conn, + dbus_message_new_method_return(msg)); +} + +static DBusHandlerResult device_is_connected(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + dbus_bool_t connected; + + connected = is_connected(&idev->dst); + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_address(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + char addr[18]; + const char *paddr = addr; + + ba2str(&idev->dst, addr); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_name(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + const char *pname = idev->hidp.name; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &pname, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_product_id(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &idev->hidp.product, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &idev->hidp.vendor, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_set_timeout(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult device_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const char *iface, *member; + + iface = dbus_message_get_interface(msg); + member = dbus_message_get_member(msg); + + /* Accept messages from the input interface only */ + if (strcmp(INPUT_DEVICE_INTERFACE, iface)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (strcmp(member, "Connect") == 0) + return device_connect(conn, msg, data); + + if (strcmp(member, "Disconnect") == 0) + return device_disconnect(conn, msg, data); + + if (strcmp(member, "IsConnected") == 0) + return device_is_connected(conn, msg, data); + + if (strcmp(member, "GetAddress") == 0) + return device_get_address(conn, msg, data); + + if (strcmp(member, "GetName") == 0) + return device_get_name(conn, msg, data); + + if (strcmp(member, "GetProductId") == 0) + return device_get_product_id(conn, msg, data); + + if (strcmp(member, "GetVendorId") == 0) + return device_get_vendor_id(conn, msg, data); + + if (strcmp(member, "SetTimeout") == 0) + return device_set_timeout(conn, msg, data); + + return err_unknown_method(conn, msg); +} + +static void device_unregister(DBusConnection *conn, void *data) +{ + input_device_free(data); +} + +/* Virtual table to handle device object path hierarchy */ +static const DBusObjectPathVTable device_table = { + .message_function = device_message, + .unregister_function = device_unregister, +}; + +/* + * Input Manager methods + */ +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); + } + + free(mgr); +} + +static int register_input_device(DBusConnection *conn, + struct input_device *idev, const char *path) +{ + DBusMessage *msg; + struct input_manager *mgr; + + if (!dbus_connection_register_object_path(conn, + 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, 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_INVALID); + + send_message_and_unref(conn, msg); + + info("Created input device: %s", path); + + return 0; +} + +static int unregister_input_device(DBusConnection *conn, const char *path) +{ + DBusMessage *msg; + + if (!dbus_connection_unregister_object_path(conn, path)) { + error("Input device path unregister failed"); + return -1; + } + + msg = dbus_message_new_signal(INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceRemoved"); + if (!msg) + return -1; + + dbus_message_append_args(msg, + 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; + + if (!dbus_connection_get_object_path_data(connection, path, + (void *) &idev)) + return -1; + + if (!idev) + return -1; + + return bacmp(&idev->dst, bdaddr); +} + +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 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; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len == 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + + pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); + if (!pr->hid_rec) { + err_failed(pr->conn, pr->msg, "HID not supported"); + goto fail; + } + + idev = input_device_new(&pr->dst); + + 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->hidp.subclass); + + 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: + 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); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { + + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len != 0) { + if (get_record(pr, *phandle, hid_record_reply) < 0) + error("HID record search error"); + else + goto done; + } + err_failed(pr->conn, pr->msg, "SDP error"); +fail: + 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; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len != 0) { + int scanned; + pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); + if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) + error("HID record search error"); + else + goto done; + } + + err_failed(pr->conn, pr->msg, "SDP error"); + +fail: + 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); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { + + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + 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_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + } else { + /* Request PnP record */ + if (get_record(pr, *phandle, pnp_record_reply) < 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + } + + goto done; + +fail: + 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 input_device *idev; + DBusMessage *reply; + DBusError derr; + char adapter[18], adapter_path[32]; + const char *addr, *path; + GSList *l; + bdaddr_t dst; + 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); + + idev = input_device_new(&dst); + if (!idev) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { + struct pending_req *pr; + + /* Data not found: create the input device later */ + input_device_free(idev); + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); + if (!pr) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { + pending_req_free(pr); + return err_failed(conn, msg, "SDP error"); + } + + return DBUS_HANDLER_RESULT_HANDLED; + } + + path = create_input_path(idev->hidp.subclass); + if (register_input_device(conn, idev, path) < 0) { + input_device_free(idev); + return err_failed(conn, msg, "D-Bus path registration failed"); + } + + reply = dbus_message_new_method_return(msg); + if (!reply) { + input_device_free(idev); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +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"); + } + + 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) +{ + DBusConnection *conn = data; + struct input_device *idev; + const char *path; + bdaddr_t dst; + + str2ba(key, &dst); + idev = input_device_new(&dst); + if (parse_stored_device_info(value, &idev->hidp) < 0) { + input_device_free(idev); + return; + } + + path = create_input_path(idev->hidp.subclass); + if (register_input_device(conn, idev, path) < 0) + input_device_free(idev); +} + +static int register_stored_inputs(DBusConnection *conn, bdaddr_t *src) +{ + char filename[PATH_MAX + 1]; + char addr[18]; + + ba2str(src, addr); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); + textfile_foreach(filename, stored_input, conn); + + 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 = malloc(sizeof(struct input_manager)); + memset(mgr, 0, sizeof(struct input_manager)); + /* 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(connection, &src); + + 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 new file mode 100644 index 00000000..957756fd --- /dev/null +++ b/input/device.h @@ -0,0 +1,27 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +int input_dbus_init(void); +void input_dbus_exit(void); + +void internal_service(const char *identifier); diff --git a/input/input-service.c b/input/input-service.c deleted file mode 100644 index 3a309068..00000000 --- a/input/input-service.c +++ /dev/null @@ -1,1450 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2005-2006 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "dbus.h" -#include "logging.h" -#include "textfile.h" - -#include "input-service.h" -#include "storage.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 - -static DBusConnection *connection = NULL; - -const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; -const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; - -struct input_device { - bdaddr_t dst; - struct hidp_connadd_req hidp; -}; - -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; -}; - -struct pending_connect { - bdaddr_t src; - bdaddr_t dst; - DBusConnection *conn; - DBusMessage *msg; -}; - -static struct input_device *input_device_new(bdaddr_t *dst) -{ - struct input_device *idev; - - idev = malloc(sizeof(struct input_device)); - if (!idev) - return NULL; - - memset(idev, 0, sizeof(struct input_device)); - - bacpy(&idev->dst, dst); - - return idev; -} - -static void input_device_free(struct input_device *idev) -{ - if (!idev) - return; - if (idev->hidp.rd_data) - free(idev->hidp.rd_data); - 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 = malloc(sizeof(struct pending_req)); - if (!pr) - return NULL; - - memset(pr, 0, sizeof(struct pending_req)); - pr->adapter_path = 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) - 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); - free(pr); -} - -static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, - DBusConnection *conn, DBusMessage *msg) -{ - struct pending_connect *pc; - pc = malloc(sizeof(struct pending_connect)); - if (!pc) - return NULL; - - memset(pc, 0, sizeof(struct pending_connect)); - bacpy(&pc->src, src); - bacpy(&pc->dst, dst); - pc->conn = dbus_connection_ref(conn); - pc->msg = dbus_message_ref(msg); - - return pc; -} - -static void pending_connect_free(struct pending_connect *pc) -{ - if (!pc) - return; - if (pc->conn) - dbus_connection_unref(pc->conn); - if (pc->msg) - dbus_message_unref(pc->msg); - free(pc); -} - -/* - * 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_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, 0x0201); - req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - - pdlist = sdp_data_get(rec, 0x0202); - req->subclass = pdlist ? pdlist->val.uint8 : 0; - - pdlist = sdp_data_get(rec, 0x0203); - req->country = pdlist ? pdlist->val.uint8 : 0; - - pdlist = sdp_data_get(rec, 0x0204); - attr_val = pdlist ? pdlist->val.uint8 : 0; - if (attr_val) - req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); - - pdlist = sdp_data_get(rec, 0x020E); - attr_val = pdlist ? pdlist->val.uint8 : 0; - if (attr_val) - req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); - - pdlist = sdp_data_get(rec, 0x0206); - if (pdlist) { - pdlist = pdlist->val.dataseq; - pdlist = pdlist->val.dataseq; - pdlist = pdlist->next; - - req->rd_data = malloc(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, 0x0201); - req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; - - pdlist = sdp_data_get(rec, 0x0202); - req->product = pdlist ? pdlist->val.uint16 : 0x0000; - - pdlist = sdp_data_get(rec, 0x0203); - req->version = pdlist ? pdlist->val.uint16 : 0x0000; -} - -static const char *create_input_path(uint8_t minor) -{ - static char path[48]; - char subpath[32]; - static int next_id = 0; - - switch (minor & 0xc0) { - case 0x40: - strcpy(subpath, "keyboard"); - break; - case 0x80: - strcpy(subpath, "pointing"); - break; - case 0xc0: - strcpy(subpath, "combo"); - break; - default: - subpath[0] = '\0'; - break; - } - - if ((minor & 0x3f) && (strlen(subpath) > 0)) - strcat(subpath, "/"); - - switch (minor & 0x3f) { - case 0x00: - break; - case 0x01: - strcat(subpath, "joystick"); - break; - case 0x02: - strcat(subpath, "gamepad"); - break; - case 0x03: - strcat(subpath, "remotecontrol"); - break; - case 0x04: - strcat(subpath, "sensing"); - break; - case 0x05: - strcat(subpath, "digitizertablet"); - break; - case 0x06: - strcat(subpath, "cardreader"); - break; - default: - strcat(subpath, "reserved"); - break; - } - - snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++); - return path; -} - -static int l2cap_connect(struct pending_connect *pc, - unsigned short psm, GIOFunc cb) -{ - GIOChannel *io; - struct sockaddr_l2 addr; - struct l2cap_options opts; - int sk, err; - - if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->src); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) - goto failed; - - if (set_nonblocking(sk) < 0) - goto failed; - - memset(&opts, 0, sizeof(opts)); - opts.imtu = HIDP_DEFAULT_MTU; - opts.omtu = HIDP_DEFAULT_MTU; - opts.flush_to = 0xffff; - - if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) - goto failed; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->dst); - addr.l2_psm = htobs(psm); - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, FALSE); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - if (!(errno == EAGAIN || errno == EINPROGRESS)) - goto failed; - - g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, pc); - } else { - cb(io, G_IO_OUT, pc); - } - - return 0; - -failed: - err = errno; - close(sk); - errno = err; - - return -1; -} - -static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) -{ - struct input_device *idev; - int ctl, isk, ret, err; - socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - isk = -1; - goto failed; - } - - isk = g_io_channel_unix_get_fd(chan); - idev->hidp.intr_sock = isk; - idev->hidp.idle_to = 30 * 60; /* 30 minutes */ - - len = sizeof(ret); - if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); - goto failed; - } - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - err = errno; - error("Can't open HIDP control socket"); - goto failed; - } - - if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&pc->src, &pc->dst); - if (err < 0) { - close(ctl); - goto failed; - } - } - - if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { - err = errno; - close(ctl); - goto failed; - } - - - send_message_and_unref(pc->conn, - dbus_message_new_method_return(pc->msg)); - - close (ctl); - goto cleanup; -failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); - -cleanup: - if (isk > 0) - close(isk); - - close(idev->hidp.ctrl_sock); - - idev->hidp.intr_sock = -1; - idev->hidp.ctrl_sock = -1; - - pending_connect_free(pc); - g_io_channel_unref(chan); - - return FALSE; -} - -static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) -{ - struct input_device *idev; - int ret, csk, err; - socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - csk = -1; - goto failed; - } - - csk = g_io_channel_unix_get_fd(chan); - /* Set HID control channel */ - idev->hidp.ctrl_sock = csk; - - len = sizeof(ret); - if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); - goto failed; - } - - /* Connect to the HID interrupt channel */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb) < 0) { - - err = errno; - error("L2CAP connect failed:%s (%d)", strerror(errno), errno); - goto failed; - } - - g_io_channel_unref(chan); - return FALSE; - -failed: - if (csk > 0) - close(csk); - - idev->hidp.ctrl_sock = -1; - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); - g_io_channel_unref(chan); - - return FALSE; -} - -static int disconnect(struct input_device *idev, uint32_t flags) -{ - struct hidp_conndel_req req; - struct hidp_conninfo ci; - int ctl, err; - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - error("Can't open HIDP control socket"); - return -errno; - } - - memset(&ci, 0, sizeof(struct hidp_conninfo)); - bacpy(&ci.bdaddr, &idev->dst); - if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || - (ci.state != BT_CONNECTED)) { - errno = ENOTCONN; - goto fail; - } - - memset(&req, 0, sizeof(struct hidp_conndel_req)); - bacpy(&req.bdaddr, &idev->dst); - req.flags = flags; - if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { - error("Can't delete the HID device: %s(%d)", - strerror(errno), errno); - goto fail; - } - - close(ctl); - - return 0; -fail: - err = errno; - close(ctl); - errno = err; - - idev->hidp.intr_sock = -1; - idev->hidp.ctrl_sock = -1; - - return -errno; -} - -static int is_connected(bdaddr_t *dst) -{ - struct hidp_conninfo ci; - int ctl; - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) - return 0; - - memset(&ci, 0, sizeof(struct hidp_conninfo)); - bacpy(&ci.bdaddr, dst); - if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { - close(ctl); - return 0; - } - - close(ctl); - - if (ci.state != BT_CONNECTED) - return 0; - else - return 1; -} - -/* - * Input Device methods - */ -static DBusHandlerResult device_connect(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - struct input_manager *mgr; - struct pending_connect *pc; - - if (is_connected(&idev->dst)) - return err_connection_failed(conn, msg, "Already connected"); - - dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); - if (!pc) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb) < 0) { - error("L2CAP connect failed: %s(%d)", strerror(errno), errno); - pending_connect_free(pc); - return err_connection_failed(conn, msg, strerror(errno)); - } - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static DBusHandlerResult device_disconnect(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - - if (disconnect(idev, 0) < 0) - return err_failed(conn, msg, strerror(errno)); - - return send_message_and_unref(conn, - dbus_message_new_method_return(msg)); -} - -static DBusHandlerResult device_is_connected(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - DBusMessage *reply; - dbus_bool_t connected; - - connected = is_connected(&idev->dst); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_BOOLEAN, &connected, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult device_get_address(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - DBusMessage *reply; - char addr[18]; - const char *paddr = addr; - - ba2str(&idev->dst, addr); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult device_get_name(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - DBusMessage *reply; - const char *pname = idev->hidp.name; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &pname, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult device_get_product_id(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - DBusMessage *reply; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->hidp.product, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_device *idev = data; - DBusMessage *reply; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->hidp.vendor, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult device_set_timeout(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static DBusHandlerResult device_message(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *iface, *member; - - iface = dbus_message_get_interface(msg); - member = dbus_message_get_member(msg); - - /* Accept messages from the input interface only */ - if (strcmp(INPUT_DEVICE_INTERFACE, iface)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (strcmp(member, "Connect") == 0) - return device_connect(conn, msg, data); - - if (strcmp(member, "Disconnect") == 0) - return device_disconnect(conn, msg, data); - - if (strcmp(member, "IsConnected") == 0) - return device_is_connected(conn, msg, data); - - if (strcmp(member, "GetAddress") == 0) - return device_get_address(conn, msg, data); - - if (strcmp(member, "GetName") == 0) - return device_get_name(conn, msg, data); - - if (strcmp(member, "GetProductId") == 0) - return device_get_product_id(conn, msg, data); - - if (strcmp(member, "GetVendorId") == 0) - return device_get_vendor_id(conn, msg, data); - - if (strcmp(member, "SetTimeout") == 0) - return device_set_timeout(conn, msg, data); - - return err_unknown_method(conn, msg); -} - -static void device_unregister(DBusConnection *conn, void *data) -{ - input_device_free(data); -} - -/* Virtual table to handle device object path hierarchy */ -static const DBusObjectPathVTable device_table = { - .message_function = device_message, - .unregister_function = device_unregister, -}; - -/* - * Input Manager methods - */ -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); - } - - free(mgr); -} - -static int register_input_device(DBusConnection *conn, - struct input_device *idev, const char *path) -{ - DBusMessage *msg; - struct input_manager *mgr; - - if (!dbus_connection_register_object_path(conn, - 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, 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_INVALID); - - send_message_and_unref(conn, msg); - - info("Created input device: %s", path); - - return 0; -} - -static int unregister_input_device(DBusConnection *conn, const char *path) -{ - DBusMessage *msg; - - if (!dbus_connection_unregister_object_path(conn, path)) { - error("Input device path unregister failed"); - return -1; - } - - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceRemoved"); - if (!msg) - return -1; - - dbus_message_append_args(msg, - 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; - - if (!dbus_connection_get_object_path_data(connection, path, - (void *) &idev)) - return -1; - - if (!idev) - return -1; - - return bacmp(&idev->dst, bdaddr); -} - -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 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; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - if (len == 0) { - err_failed(pr->conn, pr->msg, "SDP error"); - goto fail; - } - - pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); - if (!pr->hid_rec) { - err_failed(pr->conn, pr->msg, "HID not supported"); - goto fail; - } - - idev = input_device_new(&pr->dst); - - 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->hidp.subclass); - - 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: - 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); - dbus_error_free(&derr); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - - err_generic(pr->conn, pr->msg, derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - if (len != 0) { - if (get_record(pr, *phandle, hid_record_reply) < 0) - error("HID record search error"); - else - goto done; - } - err_failed(pr->conn, pr->msg, "SDP error"); -fail: - 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; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - dbus_error_free(&derr); - goto fail; - } - - if (len != 0) { - int scanned; - pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) - error("HID record search error"); - else - goto done; - } - - err_failed(pr->conn, pr->msg, "SDP error"); - -fail: - 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); - dbus_error_free(&derr); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - - err_generic(pr->conn, pr->msg, derr.name, derr.message); - dbus_error_free(&derr); - 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_failed(pr->conn, pr->msg, "SDP error"); - goto fail; - } - } else { - /* Request PnP record */ - if (get_record(pr, *phandle, pnp_record_reply) < 0) { - err_failed(pr->conn, pr->msg, "SDP error"); - goto fail; - } - } - - goto done; - -fail: - 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 input_device *idev; - DBusMessage *reply; - DBusError derr; - char adapter[18], adapter_path[32]; - const char *addr, *path; - GSList *l; - bdaddr_t dst; - 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); - - idev = input_device_new(&dst); - if (!idev) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { - struct pending_req *pr; - - /* Data not found: create the input device later */ - input_device_free(idev); - pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); - if (!pr) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { - pending_req_free(pr); - return err_failed(conn, msg, "SDP error"); - } - - return DBUS_HANDLER_RESULT_HANDLED; - } - - path = create_input_path(idev->hidp.subclass); - if (register_input_device(conn, idev, path) < 0) { - input_device_free(idev); - return err_failed(conn, msg, "D-Bus path registration failed"); - } - - reply = dbus_message_new_method_return(msg); - if (!reply) { - input_device_free(idev); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -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"); - } - - 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) -{ - DBusConnection *conn = data; - struct input_device *idev; - const char *path; - bdaddr_t dst; - - str2ba(key, &dst); - idev = input_device_new(&dst); - if (parse_stored_device_info(value, &idev->hidp) < 0) { - input_device_free(idev); - return; - } - - path = create_input_path(idev->hidp.subclass); - if (register_input_device(conn, idev, path) < 0) - input_device_free(idev); -} - -static int register_stored_inputs(DBusConnection *conn, bdaddr_t *src) -{ - char filename[PATH_MAX + 1]; - char addr[18]; - - ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); - textfile_foreach(filename, stored_input, conn); - - 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 = malloc(sizeof(struct input_manager)); - memset(mgr, 0, sizeof(struct input_manager)); - /* 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(connection, &src); - - 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/input-service.h b/input/input-service.h deleted file mode 100644 index 6eefc6d4..00000000 --- a/input/input-service.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2006 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -int input_dbus_init(void); -void input_dbus_exit(void); - -void internal_service(const char *identifier); diff --git a/input/main.c b/input/main.c index 340fc776..084493f5 100644 --- a/input/main.c +++ b/input/main.c @@ -41,7 +41,7 @@ #include "logging.h" #include "server.h" -#include "input-service.h" +#include "device.h" static GMainLoop *main_loop; -- cgit From 928217b1aca4c7a16e77cf68d7c9e63fa0e6bdb2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 13 Feb 2007 17:51:09 +0000 Subject: Return NotSupported error if the remote device doesn't support the required services(compliant to audio daemon) --- input/device.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 421b6c20..54c5d3dc 100644 --- a/input/device.c +++ b/input/device.c @@ -206,6 +206,14 @@ static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *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) { @@ -967,7 +975,8 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -975,19 +984,20 @@ static void hid_record_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } if (len == 0) { - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); goto fail; } pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); if (!pr->hid_rec) { - err_failed(pr->conn, pr->msg, "HID not supported"); + err_not_supported(pr->conn, pr->msg); goto fail; } @@ -1028,7 +1038,8 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) 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); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1036,8 +1047,8 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { - - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1048,7 +1059,7 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) else goto done; } - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); fail: pending_req_free(pr); done: @@ -1066,7 +1077,8 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) 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); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1074,7 +1086,8 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1088,8 +1101,7 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) goto done; } - err_failed(pr->conn, pr->msg, "SDP error"); - + err_not_supported(pr->conn, pr->msg); fail: pending_req_free(pr); @@ -1108,7 +1120,8 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) 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); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1116,8 +1129,8 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { - - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1125,13 +1138,13 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) if (len == 0) { /* PnP is optional: Ignore it and request the HID handle */ if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); goto fail; } } else { /* Request PnP record */ if (get_record(pr, *phandle, pnp_record_reply) < 0) { - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); goto fail; } } @@ -1193,7 +1206,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); - return err_failed(conn, msg, "SDP error"); + return err_not_supported(conn, msg); } return DBUS_HANDLER_RESULT_HANDLED; -- cgit From c90bdcc8c0c7659b2bb31bbbe5eb7e16fd7e9b5a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 18:45:59 +0000 Subject: Fake input: added initial code for headset support --- input/device.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 54c5d3dc..a1d4e1f5 100644 --- a/input/device.c +++ b/input/device.c @@ -63,6 +63,7 @@ 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 input_device { bdaddr_t dst; @@ -932,6 +933,28 @@ static int get_record(struct pending_req *pr, uint32_t handle, 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; + + *cls = strtol(str, NULL, 16); + + free(str); + if ((*cls == LONG_MIN) || (*cls == LONG_MAX)) + return -ERANGE; + + return 0; +} + static int get_handles(struct pending_req *pr, const char *uuid, DBusPendingCallNotifyFunction cb) { @@ -1159,6 +1182,26 @@ done: 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; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); + dbus_error_free(&derr); + } + + /*FIXME: Parse the content */ + + pending_req_free(pr); + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -1170,6 +1213,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, const char *addr, *path; GSList *l; bdaddr_t dst; + uint32_t cls = 0; int dev_id; dbus_error_init(&derr); @@ -1195,16 +1239,33 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; + if (get_class(&mgr->src, &dst, &cls) < 0) + return err_not_supported(conn, msg); + if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; - /* Data not found: create the input device later */ input_device_free(idev); + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { + 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); } @@ -1212,6 +1273,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } + /* FIXME: Stored data found, create a fake input or a standard HID */ path = create_input_path(idev->hidp.subclass); if (register_input_device(conn, idev, path) < 0) { input_device_free(idev); -- cgit From 86fa3713b108d19fcf8add8ce109de337ede94c7 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 20:12:27 +0000 Subject: Fake input: added code to request the headset service record --- input/device.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index a1d4e1f5..fd448768 100644 --- a/input/device.c +++ b/input/device.c @@ -1182,22 +1182,77 @@ done: 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; + struct pending_req *pr = data; + DBusError derr; + const char *path = "/org/bluez/input/headset0"; + + 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); + dbus_error_free(&derr); + goto fail; + } + + /* FIXME: extract the record */ + /* FIXME: Register the fake input 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: + 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); - dbus_error_free(&derr); + error("%s: %s", derr.name, derr.message); + goto fail; } - /*FIXME: Parse the content */ + 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; + } + + /* Wait record reply */ + goto done; +fail: + dbus_error_free(&derr); pending_req_free(pr); +done: dbus_message_unref(reply); dbus_pending_call_unref(call); } -- cgit From 45bbf75895cf2f6902089e00bf23d7d96326416e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 21:03:27 +0000 Subject: Fake input: added headset record parsing --- input/device.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index fd448768..5f805ca2 100644 --- a/input/device.c +++ b/input/device.c @@ -1186,20 +1186,73 @@ static void headset_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusMessage *pr_reply; - struct pending_req *pr = data; DBusError derr; + struct pending_req *pr = data; + struct input_device *idev; + uint8_t *rec_bin; + sdp_record_t *rec; + sdp_list_t *protos; + int len, scanned; + uint8_t ch; const char *path = "/org/bluez/input/headset0"; 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); - dbus_error_free(&derr); goto fail; } - /* FIXME: extract the record */ - /* FIXME: Register the fake input path */ + 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; + } + + idev = input_device_new(&pr->dst); + if (!idev) { + error("Out of memory when allocating new input"); + goto fail; + } + + /* FIXME: Store the ch and create the fake input path */ + + 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, @@ -1207,6 +1260,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) 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); @@ -1237,13 +1291,13 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) if (len == 0) { err_not_supported(pr->conn, pr->msg); - error("headset record handle not found"); + 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"); + error("Headset service attribute request failed"); goto fail; } -- cgit From a83064cf50b360efc354f85d02cde8fda20399d2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 21:13:54 +0000 Subject: Don't hide errors returned by hcid --- input/device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 5f805ca2..01b38b18 100644 --- a/input/device.c +++ b/input/device.c @@ -998,8 +998,8 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1061,8 +1061,8 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) 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); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1100,8 +1100,8 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) 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); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1143,8 +1143,8 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) 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); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } -- cgit From 0f08988e53758147e3394bbc24c751f186392b06 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 13:44:11 +0000 Subject: Code cleanup: removing deep indentation and added error messages --- input/device.c | 71 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 30 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 01b38b18..2c44750e 100644 --- a/input/device.c +++ b/input/device.c @@ -1000,21 +1000,20 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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); - dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { - error("%s: %s", derr.name, derr.message); err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + 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; } @@ -1046,6 +1045,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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); @@ -1063,27 +1063,33 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) 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); - dbus_error_free(&derr); 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); - dbus_error_free(&derr); + error("HID record handle not found"); goto fail; } - if (len != 0) { - if (get_record(pr, *phandle, hid_record_reply) < 0) - error("HID record search error"); - else - goto done; + 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; } - err_not_supported(pr->conn, pr->msg); fail: + dbus_error_free(&derr); pending_req_free(pr); done: dbus_message_unref(reply); @@ -1096,38 +1102,42 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) struct pending_req *pr = data; DBusError derr; uint8_t *rec_bin; - int len; + 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); - dbus_error_free(&derr); 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); - dbus_error_free(&derr); + error("Invalid PnP service record length"); goto fail; } - if (len != 0) { - int scanned; - pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) - error("HID record search error"); - else - goto done; + 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; } - err_not_supported(pr->conn, pr->msg); fail: + dbus_error_free(&derr); pending_req_free(pr); - done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -1145,16 +1155,14 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) 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); - dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { - error("%s: %s", derr.name, derr.message); err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + error("%s: %s", derr.name, derr.message); goto fail; } @@ -1162,21 +1170,24 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) /* 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); @@ -1299,10 +1310,10 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) err_not_supported(pr->conn, pr->msg); error("Headset service attribute request failed"); goto fail; + } else { + /* Wait record reply */ + goto done; } - - /* Wait record reply */ - goto done; fail: dbus_error_free(&derr); pending_req_free(pr); -- cgit From 2957490728208811926b2d548ef77432564fc916 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 18:22:03 +0000 Subject: Fake input: added function to create the D-Bus fake input path --- input/device.c | 177 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 119 insertions(+), 58 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 2c44750e..495886bd 100644 --- a/input/device.c +++ b/input/device.c @@ -65,9 +65,17 @@ 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 { + uint8_t ch; +}; + struct input_device { bdaddr_t dst; - struct hidp_connadd_req hidp; + uint8_t major; + uint8_t minor; + struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + struct fake_input *fake; + }; struct input_manager { @@ -92,7 +100,7 @@ struct pending_connect { DBusMessage *msg; }; -static struct input_device *input_device_new(bdaddr_t *dst) +static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) { struct input_device *idev; @@ -104,6 +112,9 @@ static struct input_device *input_device_new(bdaddr_t *dst) bacpy(&idev->dst, dst); + idev->major = (cls >> 8) & 0x1f; + idev->minor = (cls >> 2) & 0x3f; + return idev; } @@ -317,54 +328,76 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -static const char *create_input_path(uint8_t minor) +static const char *create_input_path(uint8_t major, uint8_t minor) { static char path[48]; char subpath[32]; static int next_id = 0; - switch (minor & 0xc0) { - case 0x40: - strcpy(subpath, "keyboard"); - break; - case 0x80: - strcpy(subpath, "pointing"); - break; - case 0xc0: - strcpy(subpath, "combo"); - break; - default: - subpath[0] = '\0'; + switch (major) { + case 0x04: /* Audio */ + switch (minor) { + /* FIXME: Testing required */ + case 0x01: /* Wearable Headset Device */ + strcpy(subpath, "wearable"); + break; + case 0x02: /* Hands-free */ + strcpy(subpath, "handsfree"); + break; + case 0x06: /* Headphone */ + strcpy(subpath, "headphone"); + break; + default: + return NULL; + } break; - } + case 0x05: /* Peripheral */ + switch (minor & 0x30) { + case 0x10: + strcpy(subpath, "keyboard"); + break; + case 0x20: + strcpy(subpath, "pointing"); + break; + case 0x30: + strcpy(subpath, "combo"); + break; + default: + subpath[0] = '\0'; + break; + } - if ((minor & 0x3f) && (strlen(subpath) > 0)) - strcat(subpath, "/"); + if ((minor & 0x0f) && (strlen(subpath) > 0)) + strcat(subpath, "/"); - switch (minor & 0x3f) { - case 0x00: - break; - case 0x01: - strcat(subpath, "joystick"); - break; - case 0x02: - strcat(subpath, "gamepad"); - break; - case 0x03: - strcat(subpath, "remotecontrol"); - break; - case 0x04: - strcat(subpath, "sensing"); - break; - case 0x05: - strcat(subpath, "digitizertablet"); - break; - case 0x06: - strcat(subpath, "cardreader"); + switch (minor & 0x0f) { + case 0x00: + break; + case 0x01: + strcat(subpath, "joystick"); + break; + case 0x02: + strcat(subpath, "gamepad"); + break; + case 0x03: + strcat(subpath, "remotecontrol"); + break; + case 0x04: + strcat(subpath, "sensing"); + break; + case 0x05: + strcat(subpath, "digitizertablet"); + break; + case 0x06: + strcat(subpath, "cardreader"); + break; + default: + strcat(subpath, "reserved"); + break; + } break; default: - strcat(subpath, "reserved"); - break; + return NULL; } snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++); @@ -995,6 +1028,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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)) { @@ -1023,13 +1057,19 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst); + 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->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->hidp.subclass); + 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"); @@ -1203,9 +1243,10 @@ static void headset_record_reply(DBusPendingCall *call, void *data) uint8_t *rec_bin; sdp_record_t *rec; sdp_list_t *protos; + const char *path; int len, scanned; + uint32_t cls; uint8_t ch; - const char *path = "/org/bluez/input/headset0"; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { @@ -1250,14 +1291,28 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst); + 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->dst, cls); if (!idev) { error("Out of memory when allocating new input"); goto fail; } - /* FIXME: Store the ch and create the fake input path */ + idev->fake = malloc(sizeof(struct fake_input)); + if (!idev->fake) { + error("Out of memory when allocating new fake input"); + input_device_free(idev); + goto fail; + } + memset(idev->fake, 0, sizeof(struct fake_input)); + idev->fake->ch = ch; + 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"); @@ -1355,13 +1410,15 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, dev_id = hci_devid(adapter); snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); - idev = input_device_new(&dst); + if (get_class(&mgr->src, &dst, &cls) < 0) { + error("Device class not available"); + return err_not_supported(conn, msg); + } + + idev = input_device_new(&dst, cls); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_class(&mgr->src, &dst, &cls) < 0) - return err_not_supported(conn, msg); - if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ @@ -1393,8 +1450,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - /* FIXME: Stored data found, create a fake input or a standard HID */ - path = create_input_path(idev->hidp.subclass); + path = create_input_path(idev->major, idev->minor); if (register_input_device(conn, idev, path) < 0) { input_device_free(idev); return err_failed(conn, msg, "D-Bus path registration failed"); @@ -1530,31 +1586,36 @@ static const DBusObjectPathVTable manager_table = { static void stored_input(char *key, char *value, void *data) { - DBusConnection *conn = data; + bdaddr_t *src = data; struct input_device *idev; const char *path; bdaddr_t dst; + uint32_t cls; str2ba(key, &dst); - idev = input_device_new(&dst); + + if (get_class(src, &dst, &cls) < 0) + return; + + idev = input_device_new(&dst, cls); if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; } - path = create_input_path(idev->hidp.subclass); - if (register_input_device(conn, idev, path) < 0) + 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(DBusConnection *conn, bdaddr_t *src) +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, "hidd"); - textfile_foreach(filename, stored_input, conn); + textfile_foreach(filename, stored_input, src); return 0; } @@ -1597,7 +1658,7 @@ int input_dbus_init(void) bacpy(&mgr->src, &src); /* Register well known HID devices */ - register_stored_inputs(connection, &src); + register_stored_inputs(&src); return 0; -- cgit From e977c52ef242556e3af44bec99c64bac91cc0b11 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 18:26:47 +0000 Subject: Fake input: missing input device fake struct free --- input/device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'input') diff --git a/input/device.c b/input/device.c index 495886bd..20c2a1d0 100644 --- a/input/device.c +++ b/input/device.c @@ -124,6 +124,8 @@ static void input_device_free(struct input_device *idev) return; if (idev->hidp.rd_data) free(idev->hidp.rd_data); + if (idev->fake) + free(idev->fake); free(idev); } @@ -1312,6 +1314,8 @@ static void headset_record_reply(DBusPendingCall *call, void *data) memset(idev->fake, 0, sizeof(struct fake_input)); 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); -- cgit From c436cfee30f6272b256f7cdbf66b2e35c70ac603 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 18:45:54 +0000 Subject: Fake input: added initial skeleton for Connect method --- input/device.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'input') diff --git a/input/device.c b/input/device.c index 20c2a1d0..c487b4ee 100644 --- a/input/device.c +++ b/input/device.c @@ -406,6 +406,18 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) +{ + char addr[18]; + /* FIXME: not implemented */ + + ba2str(&pc->dst, addr); + debug("RFCOMM connecting to %s on channel:%d", addr, ch); + errno = EIO; + + return -EIO; +} + static int l2cap_connect(struct pending_connect *pc, unsigned short psm, GIOFunc cb) { @@ -673,17 +685,33 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; + struct fake_input *fake = idev->fake; struct input_manager *mgr; struct pending_connect *pc; + /* FIXME: check if the fake input is connected */ if (is_connected(&idev->dst)) return err_connection_failed(conn, msg, "Already connected"); + /* FIXME: Check if there is a pending connection */ + dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); if (!pc) return DBUS_HANDLER_RESULT_NEED_MEMORY; + /* Fake input device */ + if (fake) { + if (rfcomm_connect(pc, fake->ch) < 0) { + const char *str = strerror(errno); + error("RFCOMM connect failed: %s(%d)", str, errno); + pending_connect_free(pc); + return err_connection_failed(conn, msg, str); + } + return DBUS_HANDLER_RESULT_HANDLED; + } + + /* HID devices */ if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb) < 0) { error("L2CAP connect failed: %s(%d)", strerror(errno), errno); -- cgit From 57e21703e213e61fdfd6571a421e2f9da118444b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 19:04:43 +0000 Subject: Fake input: added rfcomm_connect --- input/device.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index c487b4ee..3b11f491 100644 --- a/input/device.c +++ b/input/device.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -406,16 +407,88 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static gboolean rfcomm_connect_cb(GIOChannel *chan, + GIOCondition cond, struct pending_connect *pc) +{ + int err = EIO; + + err_connection_failed(pc->conn, pc->msg, strerror(err)); + pending_connect_free(pc); + g_io_channel_unref(chan); + return FALSE; +} + static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) { - char addr[18]; - /* FIXME: not implemented */ + struct sockaddr_rc addr; + GIOChannel *io; + int sk, err; + + sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (sk < 0) { + err = errno; + error("socket: %s (%d)", strerror(err), err); + return -err; + } + + io = g_io_channel_unix_new(sk); + if (!io) { + err = -EIO; + error("channel_unix_new failed in rfcomm connect"); + goto failed; + } + + g_io_channel_set_close_on_unref(io, FALSE); + + memset(&addr, 0, sizeof(addr)); + addr.rc_family = AF_BLUETOOTH; + bacpy(&addr.rc_bdaddr, &pc->src); + addr.rc_channel = 0; - ba2str(&pc->dst, addr); - debug("RFCOMM connecting to %s on channel:%d", addr, ch); - errno = EIO; + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + err = errno; + error("bind: %s (%d)", strerror(err), err); + goto failed; + } + + if (set_nonblocking(sk) < 0) { + err = errno; + error("Set non blocking: %s (%d)", strerror(err), err); + goto failed; + } + + memset(&addr, 0, sizeof(addr)); + addr.rc_family = AF_BLUETOOTH; + bacpy(&addr.rc_bdaddr, &pc->dst); + addr.rc_channel = ch; + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + char peer[18]; /* FIXME: debug purpose */ + if (!(errno == EAGAIN || errno == EINPROGRESS)) { + err = errno; + error("connect() failed: %s (%d)", + strerror(err), err); + goto failed; + } + + ba2str(&pc->dst, peer); + debug("RFCOMM connection in progress: %s channel:%d", peer, ch); + g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + (GIOFunc) rfcomm_connect_cb, pc); + } else { + debug("Connect succeeded with first try"); + rfcomm_connect_cb(io, G_IO_OUT, pc); + } + + return 0; + +failed: + if (io) + g_io_channel_unref(io); + + close(sk); + errno = err; - return -EIO; + return -err; } static int l2cap_connect(struct pending_connect *pc, -- cgit From 6130f3819aa5e51d90202b0bd974c0d79f65f5ad Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 20:11:08 +0000 Subject: Fake input: added rfcomm connect callback function --- input/device.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 3b11f491..f92eb3b9 100644 --- a/input/device.c +++ b/input/device.c @@ -67,6 +67,7 @@ const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct fake_input { + int rfcomm; uint8_t ch; }; @@ -410,8 +411,63 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { - int err = EIO; + struct input_device *idev; + struct fake_input *fake; + DBusMessage *reply; + const char *path; + socklen_t len; + int ret, err; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + fake = idev->fake; + + if (cond & G_IO_NVAL) { + g_io_channel_unref(chan); + return FALSE; + } + + if (cond & (G_IO_ERR | G_IO_HUP)) { + err = EIO; + goto failed; + } + + fake->rfcomm = g_io_channel_unix_get_fd(chan); + + len = sizeof(ret); + if (getsockopt(fake->rfcomm, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(err), err); + goto failed; + } + + /* + * FIXME: Some headsets required a sco connection + * first to report volume gain key events + */ + + /* FIXME: Create the uinput */ + /* FIXME: Add the watch to listen on rfcomm channel */ + + reply = dbus_message_new_method_return(pc->msg); + if (reply) { + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + + pending_connect_free(pc); + g_io_channel_unref(chan); + return FALSE; + +failed: + /* FIXME: close the rfcomm socket */ err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); g_io_channel_unref(chan); -- cgit From 14f36096be225e8c30e439abf19e731bdc3feb02 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 20:58:43 +0000 Subject: Fake input: added uinput create function --- input/device.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index f92eb3b9..26443177 100644 --- a/input/device.c +++ b/input/device.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include "dbus.h" #include "logging.h" #include "textfile.h" +#include "uinput.h" #include "storage.h" #include "device.h" @@ -67,8 +69,9 @@ const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct fake_input { - int rfcomm; - uint8_t ch; + int rfcomm; /* RFCOMM socket */ + int uinput; /* uinput socket */ + uint8_t ch; /* RFCOMM channel number */ }; struct input_device { @@ -332,6 +335,64 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } +static int uinput_create(char *name) +{ + struct uinput_dev dev; + int fd, err; + + fd = open("/dev/uinput", O_RDWR); + if (fd < 0) { + fd = open("/dev/input/uinput", O_RDWR); + if (fd < 0) { + fd = open("/dev/misc/uinput", O_RDWR); + if (fd < 0) { + err = errno; + error("Can't open input device: %s (%d)", + strerror(err), err); + return -err; + } + } + } + + memset(&dev, 0, sizeof(dev)); + if (name) + strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE); + + dev.id.bustype = BUS_BLUETOOTH; + dev.id.vendor = 0x0000; + dev.id.product = 0x0000; + dev.id.version = 0x0000; + + if (write(fd, &dev, sizeof(dev)) < 0) { + err = errno; + error("Can't write device information: %s (%d)", + strerror(err), err); + close(fd); + errno = err; + return -err; + } + + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_EVBIT, EV_REL); + ioctl(fd, UI_SET_EVBIT, EV_REP); + + ioctl(fd, UI_SET_KEYBIT, KEY_UP); + ioctl(fd, UI_SET_KEYBIT, KEY_PAGEUP); + ioctl(fd, UI_SET_KEYBIT, KEY_DOWN); + ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN); + + if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) { + err = errno; + error("Can't create uinput device: %s (%d)", + strerror(err), err); + close(fd); + errno = err; + return -err; + } + + return fd; +} + static const char *create_input_path(uint8_t major, uint8_t minor) { static char path[48]; @@ -453,6 +514,11 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, */ /* FIXME: Create the uinput */ + fake->uinput = uinput_create("Fake input"); + if (fake->uinput < 0) { + err = errno; + goto failed; + } /* FIXME: Add the watch to listen on rfcomm channel */ @@ -467,7 +533,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, return FALSE; failed: - /* FIXME: close the rfcomm socket */ + /* FIXME: close the rfcomm and uinput socket */ err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); g_io_channel_unref(chan); -- cgit From 22021d175f4946a5e9f5a663542016bceec3106e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 15:05:03 +0000 Subject: Fake input: added watch for RFCOMM IO channel --- input/device.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 26443177..25235ece 100644 --- a/input/device.c +++ b/input/device.c @@ -62,6 +62,8 @@ #define L2CAP_PSM_HIDP_CTRL 0x11 #define L2CAP_PSM_HIDP_INTR 0x13 +#define BUF_SIZE 16 + static DBusConnection *connection = NULL; const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; @@ -69,6 +71,7 @@ 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 */ int uinput; /* uinput socket */ uint8_t ch; /* RFCOMM channel number */ @@ -469,6 +472,50 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct fake_input *fake = data; + const char *ok = "\r\nOK\r\n"; + GError *gerr = NULL; + char buf[BUF_SIZE]; + gsize bread = 0, bwritten; + + if (cond & G_IO_NVAL) + return FALSE; + + if (cond & (G_IO_HUP | G_IO_ERR)) { + error("Hangup or error on rfcomm server socket"); + goto failed; + } + + memset(buf, 0, BUF_SIZE); + if (g_io_channel_read_chars(chan, (gchar *)buf, sizeof(buf) - 1, + &bread, &gerr) != G_IO_STATUS_NORMAL) { + error("IO Channel read error: %s", gerr->message); + g_error_free(gerr); + goto failed; + } + + if (g_io_channel_write_chars(chan, ok, 6, &bwritten, + &gerr) != G_IO_STATUS_NORMAL) { + error("IO Channel write error: %s", gerr->message); + g_error_free(gerr); + goto failed; + } + + debug("FIXME: decode %s", buf); + + return TRUE; + +failed: + g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_unref(chan); + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + return FALSE; +} + static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { @@ -513,14 +560,16 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, * first to report volume gain key events */ - /* FIXME: Create the uinput */ fake->uinput = uinput_create("Fake input"); if (fake->uinput < 0) { err = errno; goto failed; } - /* FIXME: Add the watch to listen on rfcomm channel */ + fake->io = g_io_channel_unix_new(fake->rfcomm); + g_io_channel_set_close_on_unref(fake->io, TRUE); + g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) rfcomm_io_cb, fake); reply = dbus_message_new_method_return(pc->msg); if (reply) { -- cgit From 15b471676729c330796ebabe9481a028a76b1112 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 15:38:33 +0000 Subject: Fake input: Added function to decode keys --- input/device.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 25235ece..674a1c53 100644 --- a/input/device.c +++ b/input/device.c @@ -64,6 +64,8 @@ #define BUF_SIZE 16 +#define UPDOWN_ENABLED 1 + static DBusConnection *connection = NULL; const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; @@ -472,6 +474,37 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static int decode_key(const char *str) +{ + static int mode = UPDOWN_ENABLED, gain = 0; + + uint16_t key; + int new_gain; + + /* Switch from key up/down to page up/down */ + if (strncmp("AT+CKPD=200", str, 11) == 0) { + mode = ~mode; + return KEY_RESERVED; + } + + if (strncmp("AT+VG", str, 5)) + return KEY_RESERVED; + + /* Gain key pressed */ + if (strlen(str) != 10) + return KEY_RESERVED; + + new_gain = strtol(&str[7], NULL, 10); + if (new_gain <= gain) + key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); + else + key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP); + + gain = new_gain; + + return key; +} + static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; @@ -479,6 +512,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) GError *gerr = NULL; char buf[BUF_SIZE]; gsize bread = 0, bwritten; + uint16_t key; if (cond & G_IO_NVAL) return FALSE; @@ -503,7 +537,11 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) goto failed; } - debug("FIXME: decode %s", buf); + key = decode_key(buf); + if (key != KEY_RESERVED) { + /* FIXME: send the key to uinput */ + debug("Key code: %d", key); + } return TRUE; -- cgit From e67c250c80d1da4e8210c62cf473deeb2ba4e152 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 15:53:47 +0000 Subject: Fake input: fixed get_class --- input/device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 674a1c53..7cd595d0 100644 --- a/input/device.c +++ b/input/device.c @@ -1291,11 +1291,12 @@ static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls) if (!str) return -ENOENT; - *cls = strtol(str, NULL, 16); + if (sscanf(str, "%x", cls) != 1) { + free(str); + return -ENOENT; + } free(str); - if ((*cls == LONG_MIN) || (*cls == LONG_MAX)) - return -ERANGE; return 0; } -- cgit From 1f4fd0b880866139504a0e233c7327c8b88dbbbd Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 17:45:51 +0000 Subject: Fake input: added uinput send key/event --- input/device.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 7cd595d0..b28ae45b 100644 --- a/input/device.c +++ b/input/device.c @@ -496,15 +496,37 @@ static int decode_key(const char *str) new_gain = strtol(&str[7], NULL, 10); if (new_gain <= gain) - key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); - else key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP); + else + key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); gain = new_gain; return key; } +static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) +{ + struct uinput_event event; + + memset(&event, 0, sizeof(event)); + event.type = type; + event.code = code; + event.value = value; + + write(fd, &event, sizeof(event)); +} + +static void send_key(int fd, uint16_t key) +{ + /* Key press */ + send_event(fd, EV_KEY, key, 1); + send_event(fd, EV_SYN, SYN_REPORT, 0); + /* Key release */ + send_event(fd, EV_KEY, key, 0); + send_event(fd, EV_SYN, SYN_REPORT, 0); +} + static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; @@ -530,6 +552,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) goto failed; } + debug("Received: %s", buf); + if (g_io_channel_write_chars(chan, ok, 6, &bwritten, &gerr) != G_IO_STATUS_NORMAL) { error("IO Channel write error: %s", gerr->message); @@ -538,10 +562,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) } key = decode_key(buf); - if (key != KEY_RESERVED) { - /* FIXME: send the key to uinput */ - debug("Key code: %d", key); - } + if (key != KEY_RESERVED) + send_key(fake->uinput, key); return TRUE; -- cgit From af47f85ea4422e8ec35564c1e26f84469c94c1e4 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 12:20:59 +0000 Subject: Fake input: Changed disconnect function to support fake devices --- input/device.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index b28ae45b..bf20257e 100644 --- a/input/device.c +++ b/input/device.c @@ -915,12 +915,31 @@ failed: return FALSE; } -static int disconnect(struct input_device *idev, uint32_t flags) +static int disconnect(struct input_device *idev, uint32_t flags) { + struct fake_input *fake = idev->fake; struct hidp_conndel_req req; struct hidp_conninfo ci; int ctl, err; + /* Fake input disconnect */ + if (fake) { + if (fake->io) { + g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_unref(fake->io); + fake->io = NULL; + } + if (fake->uinput >= 0) { + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + } + + return 0; + } + + /* Standard HID disconnect */ + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { error("Can't open HIDP control socket"); -- cgit From bebbd2498d580e91d8184970732383449d856a3c Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 13:07:02 +0000 Subject: Fake input: fixed build error when glib is disabled --- input/device.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index bf20257e..0ae644a5 100644 --- a/input/device.c +++ b/input/device.c @@ -531,7 +531,6 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; const char *ok = "\r\nOK\r\n"; - GError *gerr = NULL; char buf[BUF_SIZE]; gsize bread = 0, bwritten; uint16_t key; @@ -545,19 +544,16 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) } memset(buf, 0, BUF_SIZE); - if (g_io_channel_read_chars(chan, (gchar *)buf, sizeof(buf) - 1, - &bread, &gerr) != G_IO_STATUS_NORMAL) { - error("IO Channel read error: %s", gerr->message); - g_error_free(gerr); + if (g_io_channel_read(chan, buf, sizeof(buf) - 1, + &bread) != G_IO_ERROR_NONE) { + error("IO Channel read error"); goto failed; } debug("Received: %s", buf); - if (g_io_channel_write_chars(chan, ok, 6, &bwritten, - &gerr) != G_IO_STATUS_NORMAL) { - error("IO Channel write error: %s", gerr->message); - g_error_free(gerr); + if (g_io_channel_write(chan, ok, 6, &bwritten) != G_IO_ERROR_NONE) { + error("IO Channel write error"); goto failed; } @@ -568,7 +564,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) return TRUE; failed: - g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_close(chan); g_io_channel_unref(chan); ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); @@ -925,7 +921,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) /* Fake input disconnect */ if (fake) { if (fake->io) { - g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_close(fake->io); g_io_channel_unref(fake->io); fake->io = NULL; } -- cgit From d242929462d90d619156709b9188f455d6f1fea3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 19:39:03 +0000 Subject: Fake input: changed is_connected function to support fake inputs --- input/device.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 0ae644a5..3c6c2f12 100644 --- a/input/device.c +++ b/input/device.c @@ -564,6 +564,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) return TRUE; failed: + /* FIXME: Missing clean/free fake io channel */ g_io_channel_close(chan); g_io_channel_unref(chan); ioctl(fake->uinput, UI_DEV_DESTROY); @@ -638,7 +639,6 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, return FALSE; failed: - /* FIXME: close the rfcomm and uinput socket */ err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); g_io_channel_unref(chan); @@ -973,17 +973,27 @@ fail: return -errno; } -static int is_connected(bdaddr_t *dst) +static int is_connected(struct input_device *idev) { + struct fake_input *fake = idev->fake; struct hidp_conninfo ci; int ctl; + /* Fake input */ + if (fake) { + if (fake->io) + return 1; + else + return 0; + } + + /* Standard HID */ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) return 0; memset(&ci, 0, sizeof(struct hidp_conninfo)); - bacpy(&ci.bdaddr, dst); + bacpy(&ci.bdaddr, &idev->dst); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); return 0; @@ -1008,8 +1018,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct input_manager *mgr; struct pending_connect *pc; - /* FIXME: check if the fake input is connected */ - if (is_connected(&idev->dst)) + if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); /* FIXME: Check if there is a pending connection */ @@ -1060,7 +1069,7 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *reply; dbus_bool_t connected; - connected = is_connected(&idev->dst); + connected = is_connected(idev); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From 40d70645a6e6954eaeb6790d7e191ff8f8d958f3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 21:40:12 +0000 Subject: Input: added verification for pending connection --- input/device.c | 182 ++++++++++++++++++++++++++------------------------------- 1 file changed, 83 insertions(+), 99 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 3c6c2f12..816342c0 100644 --- a/input/device.c +++ b/input/device.c @@ -79,13 +79,19 @@ struct fake_input { uint8_t ch; /* RFCOMM channel number */ }; +struct pending_connect { + DBusConnection *conn; + DBusMessage *msg; +}; + struct input_device { + bdaddr_t src; bdaddr_t dst; uint8_t major; uint8_t minor; struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ struct fake_input *fake; - + struct pending_connect *pending_connect; }; struct input_manager { @@ -103,14 +109,7 @@ struct pending_req { sdp_record_t *hid_rec; }; -struct pending_connect { - bdaddr_t src; - bdaddr_t dst; - DBusConnection *conn; - DBusMessage *msg; -}; - -static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) +static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint32_t cls) { struct input_device *idev; @@ -120,6 +119,7 @@ static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) memset(idev, 0, sizeof(struct input_device)); + bacpy(&idev->src, src); bacpy(&idev->dst, dst); idev->major = (cls >> 8) & 0x1f; @@ -128,6 +128,17 @@ static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) return idev; } +static void pending_connect_free(struct pending_connect *pc) +{ + if (!pc) + return; + if (pc->conn) + dbus_connection_unref(pc->conn); + if (pc->msg) + dbus_message_unref(pc->msg); + free(pc); +} + static void input_device_free(struct input_device *idev) { if (!idev) @@ -136,6 +147,9 @@ static void input_device_free(struct input_device *idev) free(idev->hidp.rd_data); if (idev->fake) free(idev->fake); + if (idev->pending_connect) + pending_connect_free(idev->pending_connect); + free(idev); } @@ -175,34 +189,6 @@ static void pending_req_free(struct pending_req *pr) free(pr); } -static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, - DBusConnection *conn, DBusMessage *msg) -{ - struct pending_connect *pc; - pc = malloc(sizeof(struct pending_connect)); - if (!pc) - return NULL; - - memset(pc, 0, sizeof(struct pending_connect)); - bacpy(&pc->src, src); - bacpy(&pc->dst, dst); - pc->conn = dbus_connection_ref(conn); - pc->msg = dbus_message_ref(msg); - - return pc; -} - -static void pending_connect_free(struct pending_connect *pc) -{ - if (!pc) - return; - if (pc->conn) - dbus_connection_unref(pc->conn); - if (pc->msg) - dbus_message_unref(pc->msg); - free(pc); -} - /* * Common D-Bus BlueZ input error functions */ @@ -573,18 +559,14 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_connect *pc) +static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, + struct input_device *idev) { - struct input_device *idev; struct fake_input *fake; DBusMessage *reply; - const char *path; socklen_t len; int ret, err; - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); fake = idev->fake; if (cond & G_IO_NVAL) { @@ -628,24 +610,27 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); - reply = dbus_message_new_method_return(pc->msg); + reply = dbus_message_new_method_return(idev->pending_connect->msg); if (reply) { dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; } -static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) +static int rfcomm_connect(struct input_device *idev) { struct sockaddr_rc addr; GIOChannel *io; @@ -669,7 +654,7 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &pc->src); + bacpy(&addr.rc_bdaddr, &idev->src); addr.rc_channel = 0; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { @@ -686,8 +671,8 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &pc->dst); - addr.rc_channel = ch; + bacpy(&addr.rc_bdaddr, &idev->dst); + addr.rc_channel = idev->fake->ch; if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { char peer[18]; /* FIXME: debug purpose */ if (!(errno == EAGAIN || errno == EINPROGRESS)) { @@ -697,13 +682,13 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) goto failed; } - ba2str(&pc->dst, peer); - debug("RFCOMM connection in progress: %s channel:%d", peer, ch); + ba2str(&idev->dst, peer); + debug("RFCOMM connection in progress: %s channel:%d", peer, idev->fake->ch); g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, pc); + (GIOFunc) rfcomm_connect_cb, idev); } else { debug("Connect succeeded with first try"); - rfcomm_connect_cb(io, G_IO_OUT, pc); + rfcomm_connect_cb(io, G_IO_OUT, idev); } return 0; @@ -718,8 +703,8 @@ failed: return -err; } -static int l2cap_connect(struct pending_connect *pc, - unsigned short psm, GIOFunc cb) +static int l2cap_connect(struct input_device *idev, + unsigned short psm, GIOFunc cb) { GIOChannel *io; struct sockaddr_l2 addr; @@ -731,7 +716,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->src); + bacpy(&addr.l2_bdaddr, &idev->src); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto failed; @@ -749,7 +734,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->dst); + bacpy(&addr.l2_bdaddr, &idev->dst); addr.l2_psm = htobs(psm); io = g_io_channel_unix_new(sk); @@ -759,9 +744,9 @@ static int l2cap_connect(struct pending_connect *pc, if (!(errno == EAGAIN || errno == EINPROGRESS)) goto failed; - g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, pc); + g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, idev); } else { - cb(io, G_IO_OUT, pc); + cb(io, G_IO_OUT, idev); } return 0; @@ -775,15 +760,10 @@ failed: } static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct input_device *idev) { - struct input_device *idev; int ctl, isk, ret, err; socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); if (cond & G_IO_NVAL) { err = EHOSTDOWN; @@ -816,7 +796,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&pc->src, &pc->dst); + err = encrypt_link(&idev->src, &idev->dst); if (err < 0) { close(ctl); goto failed; @@ -830,13 +810,14 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } - send_message_and_unref(pc->conn, - dbus_message_new_method_return(pc->msg)); + send_message_and_unref(idev->pending_connect->conn, + dbus_message_new_method_return(idev->pending_connect->msg)); close (ctl); goto cleanup; failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); cleanup: if (isk > 0) @@ -847,22 +828,18 @@ cleanup: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; } static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct input_device *idev) { - struct input_device *idev; int ret, csk, err; socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); if (cond & G_IO_NVAL) { err = EHOSTDOWN; @@ -888,7 +865,7 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, } /* Connect to the HID interrupt channel */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, + if (l2cap_connect(idev, L2CAP_PSM_HIDP_INTR, (GIOFunc) interrupt_connect_cb) < 0) { err = errno; @@ -904,8 +881,10 @@ failed: close(csk); idev->hidp.ctrl_sock = -1; - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; @@ -970,7 +949,7 @@ fail: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - return -errno; + return -err; } static int is_connected(struct input_device *idev) @@ -1014,36 +993,41 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; - struct fake_input *fake = idev->fake; - struct input_manager *mgr; - struct pending_connect *pc; + + if (idev->pending_connect) + return err_connection_failed(conn, msg, "Connection in progress"); if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); - /* FIXME: Check if there is a pending connection */ - - dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); - if (!pc) + idev->pending_connect = malloc(sizeof(struct pending_connect)); + if (!idev->pending_connect) { + error("Out of memory when allocating new struct pending_connect"); return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + memset(idev->pending_connect, 0, sizeof(struct pending_connect)); + idev->pending_connect->conn = dbus_connection_ref(conn); + idev->pending_connect->msg = dbus_message_ref(msg); /* Fake input device */ - if (fake) { - if (rfcomm_connect(pc, fake->ch) < 0) { + if (idev->fake) { + if (rfcomm_connect(idev) < 0) { const char *str = strerror(errno); error("RFCOMM connect failed: %s(%d)", str, errno); - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; return err_connection_failed(conn, msg, str); } return DBUS_HANDLER_RESULT_HANDLED; } /* HID devices */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + if (l2cap_connect(idev, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb) < 0) { error("L2CAP connect failed: %s(%d)", strerror(errno), errno); - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; return err_connection_failed(conn, msg, strerror(errno)); } @@ -1422,7 +1406,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst, cls); + idev = input_device_new(&pr->src, &pr->dst, cls); extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) @@ -1656,7 +1640,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst, cls); + idev = input_device_new(&pr->src, &pr->dst, cls); if (!idev) { error("Out of memory when allocating new input"); goto fail; @@ -1776,7 +1760,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_not_supported(conn, msg); } - idev = input_device_new(&dst, cls); + idev = input_device_new(&mgr->src, &dst, cls); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1958,7 +1942,7 @@ static void stored_input(char *key, char *value, void *data) if (get_class(src, &dst, &cls) < 0) return; - idev = input_device_new(&dst, cls); + idev = input_device_new(src, &dst, cls); if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; -- cgit From acfdab3a74249dc4e04078523a7fd10fd6fe4d5d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 28 Feb 2007 12:31:25 +0000 Subject: Input: Using glib memory alloc functions --- input/device.c | 57 ++++++++++++++++++++------------------------------------- input/storage.c | 35 ++++++++++++++++------------------- 2 files changed, 36 insertions(+), 56 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 816342c0..a3e4d7de 100644 --- a/input/device.c +++ b/input/device.c @@ -113,11 +113,7 @@ static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint3 { struct input_device *idev; - idev = malloc(sizeof(struct input_device)); - if (!idev) - return NULL; - - memset(idev, 0, sizeof(struct input_device)); + idev = g_new0(struct input_device, 1); bacpy(&idev->src, src); bacpy(&idev->dst, dst); @@ -136,7 +132,7 @@ static void pending_connect_free(struct pending_connect *pc) dbus_connection_unref(pc->conn); if (pc->msg) dbus_message_unref(pc->msg); - free(pc); + g_free(pc); } static void input_device_free(struct input_device *idev) @@ -144,13 +140,13 @@ static void input_device_free(struct input_device *idev) if (!idev) return; if (idev->hidp.rd_data) - free(idev->hidp.rd_data); + g_free(idev->hidp.rd_data); if (idev->fake) - free(idev->fake); + g_free(idev->fake); if (idev->pending_connect) pending_connect_free(idev->pending_connect); - free(idev); + g_free(idev); } static struct pending_req *pending_req_new(DBusConnection *conn, @@ -158,12 +154,11 @@ static struct pending_req *pending_req_new(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst) { struct pending_req *pr; - pr = malloc(sizeof(struct pending_req)); + pr = g_try_new0(struct pending_req, 1); if (!pr) return NULL; - memset(pr, 0, sizeof(struct pending_req)); - pr->adapter_path = strdup(adapter_path); + pr->adapter_path = g_strdup(adapter_path); bacpy(&pr->src, src); bacpy(&pr->dst, dst); pr->conn = dbus_connection_ref(conn); @@ -177,7 +172,7 @@ static void pending_req_free(struct pending_req *pr) if (!pr) return; if (pr->adapter_path) - free(pr->adapter_path); + g_free(pr->adapter_path); if (pr->conn) dbus_connection_unref(pr->conn); if (pr->msg) @@ -186,7 +181,7 @@ static void pending_req_free(struct pending_req *pr) sdp_record_free(pr->pnp_rec); if (pr->hid_rec) sdp_record_free(pr->hid_rec); - free(pr); + g_free(pr); } /* @@ -304,7 +299,7 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) pdlist = pdlist->val.dataseq; pdlist = pdlist->next; - req->rd_data = malloc(pdlist->unitSize); + 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; @@ -1000,13 +995,12 @@ static DBusHandlerResult device_connect(DBusConnection *conn, if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); - idev->pending_connect = malloc(sizeof(struct pending_connect)); + idev->pending_connect = g_try_new0(struct pending_connect, 1); if (!idev->pending_connect) { error("Out of memory when allocating new struct pending_connect"); return DBUS_HANDLER_RESULT_NEED_MEMORY; } - memset(idev->pending_connect, 0, sizeof(struct pending_connect)); idev->pending_connect->conn = dbus_connection_ref(conn); idev->pending_connect->msg = dbus_message_ref(msg); @@ -1207,7 +1201,7 @@ static void input_manager_free(struct input_manager *mgr) g_slist_free(mgr->paths); } - free(mgr); + g_free(mgr); } static int register_input_device(DBusConnection *conn, @@ -1223,7 +1217,7 @@ static int register_input_device(DBusConnection *conn, } dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - mgr->paths = g_slist_append(mgr->paths, strdup(path)); + mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); @@ -1322,11 +1316,11 @@ static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls) return -ENOENT; if (sscanf(str, "%x", cls) != 1) { - free(str); + g_free(str); return -ENOENT; } - free(str); + g_free(str); return 0; } @@ -1641,18 +1635,8 @@ static void headset_record_reply(DBusPendingCall *call, void *data) } idev = input_device_new(&pr->src, &pr->dst, cls); - if (!idev) { - error("Out of memory when allocating new input"); - goto fail; - } - idev->fake = malloc(sizeof(struct fake_input)); - if (!idev->fake) { - error("Out of memory when allocating new fake input"); - input_device_free(idev); - goto fail; - } - memset(idev->fake, 0, sizeof(struct fake_input)); + idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; /* FIXME: Store the fake input data */ @@ -1761,8 +1745,6 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, } idev = input_device_new(&mgr->src, &dst, cls); - if (!idev) - return DBUS_HANDLER_RESULT_NEED_MEMORY; if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; @@ -1852,7 +1834,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, return err_failed(conn, msg, "D-Bus path unregistration failed"); } - free(l->data); + g_free(l->data); mgr->paths = g_slist_remove(mgr->paths, l->data); return send_message_and_unref(conn, reply); @@ -1943,6 +1925,7 @@ static void stored_input(char *key, char *value, void *data) return; idev = input_device_new(src, &dst, cls); + if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; @@ -1977,8 +1960,8 @@ int input_dbus_init(void) dbus_connection_set_exit_on_disconnect(connection, TRUE); - mgr = malloc(sizeof(struct input_manager)); - memset(mgr, 0, sizeof(struct input_manager)); + mgr = g_new0(struct input_manager, 1); + /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, &manager_table, mgr)) { diff --git a/input/storage.c b/input/storage.c index 5f467efb..ca96da0b 100644 --- a/input/storage.c +++ b/input/storage.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,8 @@ #include #include +#include + #include "textfile.h" #include "logging.h" @@ -64,12 +65,10 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) unsigned int vendor, product, version, subclass, country, parser, pos; int i; - desc = malloc(4096); + desc = g_try_malloc0(4096); if (!desc) return -ENOMEM; - memset(desc, 0, 4096); - sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", &vendor, &product, &version, &subclass, &country, &parser, desc, &req->flags, &pos); @@ -84,9 +83,9 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) snprintf(req->name, 128, str + pos); req->rd_size = strlen(desc) / 2; - req->rd_data = malloc(req->rd_size); + req->rd_data = g_try_malloc0(req->rd_size); if (!req->rd_data) { - free(desc); + g_free(desc); return -ENOMEM; } @@ -96,7 +95,7 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); } - free(desc); + g_free(desc); return 0; } @@ -143,17 +142,16 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req create_filename(filename, PATH_MAX, src, "hidd"); size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; - str = malloc(size); + str = g_try_malloc0(size); if (!str) return -ENOMEM; - desc = malloc((req->rd_size * 2) + 1); + desc = g_try_malloc0((req->rd_size * 2) + 1); if (!desc) { - free(str); + g_free(str); return -ENOMEM; } - memset(desc, 0, (req->rd_size * 2) + 1); for (i = 0; i < req->rd_size; i++) sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); @@ -162,7 +160,7 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req req->subclass, req->country, req->parser, desc, req->flags, req->name); - free(desc); + g_free(desc); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); @@ -170,7 +168,7 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req err = textfile_put(filename, addr, str); - free(str); + g_free(str); return err; } @@ -194,7 +192,7 @@ int encrypt_link(bdaddr_t *src, bdaddr_t *dst) free(str); - cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + cr = g_try_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info)); if (!cr) return -ENOMEM; @@ -202,17 +200,16 @@ int encrypt_link(bdaddr_t *src, bdaddr_t *dst) dev_id = hci_devid(addr); if (dev_id < 0) { - free(cr); + g_free(cr); return -errno; } dd = hci_open_dev(dev_id); if (dd < 0) { - free(cr); + g_free(cr); return -errno; } - memset(cr, 0, sizeof(*cr) + sizeof(struct hci_conn_info)); bacpy(&cr->bdaddr, dst); cr->type = ACL_LINK; @@ -237,14 +234,14 @@ int encrypt_link(bdaddr_t *src, bdaddr_t *dst) } done: - free(cr); + g_free(cr); hci_close_dev(dd); return 0; fail: - free(cr); + g_free(cr); err = errno; hci_close_dev(dd); -- cgit From bf2f0ef935869db6d1c6e4ea26ee8133b42b49b6 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 28 Feb 2007 16:39:34 +0000 Subject: Input: code cleanup --- input/device.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index a3e4d7de..94122554 100644 --- a/input/device.c +++ b/input/device.c @@ -274,26 +274,26 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) strncpy(req->name, pdlist2->val.str, 127); } - pdlist = sdp_data_get(rec, 0x0201); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION); req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - pdlist = sdp_data_get(rec, 0x0202); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); req->subclass = pdlist ? pdlist->val.uint8 : 0; - pdlist = sdp_data_get(rec, 0x0203); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE); req->country = pdlist ? pdlist->val.uint8 : 0; - pdlist = sdp_data_get(rec, 0x0204); + 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, 0x020E); + 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, 0x0206); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST); if (pdlist) { pdlist = pdlist->val.dataseq; pdlist = pdlist->val.dataseq; @@ -311,13 +311,13 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist; - pdlist = sdp_data_get(rec, 0x0201); + pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID); req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; - pdlist = sdp_data_get(rec, 0x0202); + pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID); req->product = pdlist ? pdlist->val.uint16 : 0x0000; - pdlist = sdp_data_get(rec, 0x0203); + pdlist = sdp_data_get(rec, SDP_ATTR_VERSION); req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -- cgit From fd660e28020d6b26f8fe49c0a87545f04e981fa9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 Mar 2007 11:40:20 +0000 Subject: Input: renamed input storage file to "input" --- input/device.c | 2 +- input/storage.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 94122554..6e701862 100644 --- a/input/device.c +++ b/input/device.c @@ -1942,7 +1942,7 @@ static int register_stored_inputs(bdaddr_t *src) char addr[18]; ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "input"); textfile_foreach(filename, stored_input, src); return 0; diff --git a/input/storage.c b/input/storage.c index ca96da0b..3833d09e 100644 --- a/input/storage.c +++ b/input/storage.c @@ -107,7 +107,7 @@ int get_stored_device_info(bdaddr_t *src, bdaddr_t *dst, char peer[18]; int err; - create_filename(filename, PATH_MAX, src, "hidd"); + create_filename(filename, PATH_MAX, src, "input"); ba2str(dst, peer); str = textfile_get(filename, peer); @@ -126,7 +126,7 @@ int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst) char filename[PATH_MAX + 1]; char addr[18]; - create_filename(filename, PATH_MAX, src, "hidd"); + create_filename(filename, PATH_MAX, src, "input"); ba2str(dst, addr); @@ -139,8 +139,9 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req int i, err, size; char addr[18]; - create_filename(filename, PATH_MAX, src, "hidd"); + create_filename(filename, PATH_MAX, src, "input"); + /* FIXME: name is not required */ size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; str = g_try_malloc0(size); if (!str) -- cgit From 553db8d4150c59628105bf8df4ddb68311b2fb58 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 Mar 2007 13:02:21 +0000 Subject: Input: don't store the HID name in the "input" file && removed magic number in the memory alloc --- input/storage.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'input') diff --git a/input/storage.c b/input/storage.c index 3833d09e..be5ab3e3 100644 --- a/input/storage.c +++ b/input/storage.c @@ -61,17 +61,21 @@ static inline int create_filename(char *buf, size_t size, int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) { - char tmp[3], *desc; + char tmp[3]; + const char *desc; unsigned int vendor, product, version, subclass, country, parser, pos; + size_t len; int i; - desc = g_try_malloc0(4096); - if (!desc) - return -ENOMEM; - - sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", + sscanf(str, "%04X:%04X:%04X %02X %02X %04X %08X %n", &vendor, &product, &version, &subclass, &country, - &parser, desc, &req->flags, &pos); + &parser, &req->flags, &pos); + + + desc = &str[pos]; + len = strlen(desc); + if (len <= 0) + return -ENOENT; req->vendor = vendor; req->product = product; @@ -80,12 +84,11 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) req->country = country; req->parser = parser; - snprintf(req->name, 128, str + pos); + /* FIXME: Retrieve the name from the filesystem file "names" */ - req->rd_size = strlen(desc) / 2; + req->rd_size = len / 2; req->rd_data = g_try_malloc0(req->rd_size); if (!req->rd_data) { - g_free(desc); return -ENOMEM; } @@ -95,8 +98,6 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); } - g_free(desc); - return 0; } @@ -141,8 +142,7 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req create_filename(filename, PATH_MAX, src, "input"); - /* FIXME: name is not required */ - size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; + size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9; str = g_try_malloc0(size); if (!str) return -ENOMEM; @@ -156,10 +156,10 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req for (i = 0; i < req->rd_size; i++) sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); - snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", + snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %08X %s", req->vendor, req->product, req->version, - req->subclass, req->country, req->parser, desc, - req->flags, req->name); + req->subclass, req->country, req->parser, + req->flags, desc); g_free(desc); -- cgit From 3f27f7f7a01ad43532b65504e6204194e3e259df Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 Mar 2007 14:10:10 +0000 Subject: Input: Use stored device name instead of the service name attribute --- input/device.c | 14 +++++++++++--- input/storage.c | 34 +++++++++++++++++++++++++++++++--- input/storage.h | 2 ++ 3 files changed, 44 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 6e701862..2d05d264 100644 --- a/input/device.c +++ b/input/device.c @@ -85,8 +85,9 @@ struct pending_connect { }; struct input_device { - bdaddr_t src; - bdaddr_t dst; + bdaddr_t src; + bdaddr_t dst; + char *name; uint8_t major; uint8_t minor; struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ @@ -121,6 +122,11 @@ static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint3 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); + return idev; } @@ -139,6 +145,8 @@ static void input_device_free(struct input_device *idev) { if (!idev) return; + if (idev->name) + g_free(idev->name); if (idev->hidp.rd_data) g_free(idev->hidp.rd_data); if (idev->fake) @@ -594,7 +602,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, * first to report volume gain key events */ - fake->uinput = uinput_create("Fake input"); + fake->uinput = uinput_create(idev->name); if (fake->uinput < 0) { err = errno; goto failed; diff --git a/input/storage.c b/input/storage.c index be5ab3e3..fd8d4bcb 100644 --- a/input/storage.c +++ b/input/storage.c @@ -71,7 +71,6 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) &vendor, &product, &version, &subclass, &country, &parser, &req->flags, &pos); - desc = &str[pos]; len = strlen(desc); if (len <= 0) @@ -84,8 +83,6 @@ int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) req->country = country; req->parser = parser; - /* FIXME: Retrieve the name from the filesystem file "names" */ - req->rd_size = len / 2; req->rd_data = g_try_malloc0(req->rd_size); if (!req->rd_data) { @@ -174,6 +171,37 @@ 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) +{ + char filename[PATH_MAX + 1], addr[18], *str; + int len; + + create_filename(filename, PATH_MAX, local, "names"); + + ba2str(peer, addr); + str = textfile_get(filename, addr); + if (!str) + return -ENOENT; + + len = strlen(str); + + /* HID max name size is 128 chars */ + if (len < 128) { + *name = str; + return 0; + } + + *name = g_try_malloc0(128); + if (!*name) + return -ENOMEM; + + snprintf(*name, 128, "%s", str); + + 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 09a696cf..60df915d 100644 --- a/input/storage.h +++ b/input/storage.h @@ -32,4 +32,6 @@ 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 encrypt_link(bdaddr_t *src, bdaddr_t *dst); -- cgit From d53935995279d96e4a2f973d11d3a3ba3d9c9bfc Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 5 Mar 2007 20:10:35 +0000 Subject: Input: added extra GIOConditon(HUP, ERR and NVAL) for watches --- input/device.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 2d05d264..0e182224 100644 --- a/input/device.c +++ b/input/device.c @@ -747,7 +747,8 @@ static int l2cap_connect(struct input_device *idev, if (!(errno == EAGAIN || errno == EINPROGRESS)) goto failed; - g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, idev); + g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) cb, idev); } else { cb(io, G_IO_OUT, idev); } @@ -774,6 +775,14 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, goto failed; } + if (cond & (G_IO_HUP | G_IO_ERR)) { + err = EINTR; + isk = -1; + error("Hangup or error on HIDP interrupt socket"); + goto failed; + + } + isk = g_io_channel_unix_get_fd(chan); idev->hidp.intr_sock = isk; idev->hidp.idle_to = 30 * 60; /* 30 minutes */ @@ -850,6 +859,14 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, goto failed; } + if (cond & (G_IO_HUP | G_IO_ERR)) { + err = EINTR; + csk = -1; + error("Hangup or error on HIDP control socket"); + goto failed; + + } + csk = g_io_channel_unix_get_fd(chan); /* Set HID control channel */ idev->hidp.ctrl_sock = csk; -- cgit From 6752c3025ac9320ae2b60f5eba1f64205a7f6b78 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 6 Mar 2007 19:33:02 +0000 Subject: Input: useless code removed, stored devices are always created when the daemon initializes --- input/device.c | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 0e182224..72bab4c0 100644 --- a/input/device.c +++ b/input/device.c @@ -601,7 +601,6 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, * FIXME: Some headsets required a sco connection * first to report volume gain key events */ - fake->uinput = uinput_create(idev->name); if (fake->uinput < 0) { err = errno; @@ -1735,11 +1734,10 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_manager *mgr = data; - struct input_device *idev; - DBusMessage *reply; + struct pending_req *pr; DBusError derr; char adapter[18], adapter_path[32]; - const char *addr, *path; + const char *addr; GSList *l; bdaddr_t dst; uint32_t cls = 0; @@ -1769,18 +1767,11 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_not_supported(conn, msg); } - idev = input_device_new(&mgr->src, &dst, cls); - - if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { - struct pending_req *pr; - /* Data not found: create the input device later */ - input_device_free(idev); - - pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); - if (!pr) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); + if (!pr) + return DBUS_HANDLER_RESULT_NEED_MEMORY; - switch (cls & 0x1f00) { + switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); @@ -1797,28 +1788,9 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, default: pending_req_free(pr); return err_not_supported(conn, msg); - } - - return DBUS_HANDLER_RESULT_HANDLED; - } - - path = create_input_path(idev->major, idev->minor); - if (register_input_device(conn, idev, path) < 0) { - input_device_free(idev); - return err_failed(conn, msg, "D-Bus path registration failed"); - } - - reply = dbus_message_new_method_return(msg); - if (!reply) { - input_device_free(idev); - return DBUS_HANDLER_RESULT_NEED_MEMORY; } - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult manager_remove_device(DBusConnection *conn, -- cgit From dbe77da3c57a741201e91956bd81945578f2b6ab Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 9 Mar 2007 15:09:31 +0000 Subject: Removed dupplicated errno header include --- input/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 084493f5..db0678c5 100644 --- a/input/main.c +++ b/input/main.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include -- cgit From 6e3cd312032917facce3e8ef35812b713c16db2b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 9 Mar 2007 15:31:27 +0000 Subject: Fix not result checking warning --- input/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 72bab4c0..fb1e5e5d 100644 --- a/input/device.c +++ b/input/device.c @@ -497,13 +497,14 @@ static int decode_key(const char *str) static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) { struct uinput_event event; + int err; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; - write(fd, &event, sizeof(event)); + err = write(fd, &event, sizeof(event)); } static void send_key(int fd, uint16_t key) -- cgit From 74b978057e7b3f8cad2952c0fe50a17a118339ad Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 13 Mar 2007 18:13:28 +0000 Subject: Add skeleton for manager interface --- input/Makefile.am | 3 ++- input/main.c | 1 + input/manager.c | 37 +++++++++++++++++++++++++++++++++++++ input/manager.h | 25 +++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 input/manager.c create mode 100644 input/manager.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index e39bd254..523e001b 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -11,7 +11,8 @@ servicedir = $(libdir)/bluetooth service_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = main.c \ - server.h server.c device.h device.c storage.h storage.c + manager.h manager.c server.h server.c \ + device.h device.c storage.h storage.c LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ diff --git a/input/main.c b/input/main.c index db0678c5..688c8a58 100644 --- a/input/main.c +++ b/input/main.c @@ -39,6 +39,7 @@ #include "dbus.h" #include "logging.h" +#include "manager.h" #include "server.h" #include "device.h" diff --git a/input/manager.c b/input/manager.c new file mode 100644 index 00000000..ab45339f --- /dev/null +++ b/input/manager.c @@ -0,0 +1,37 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "manager.h" + +int input_init(void) +{ + return 0; +} + +void input_exit(void) +{ +} diff --git a/input/manager.h b/input/manager.h new file mode 100644 index 00000000..98e6d2d8 --- /dev/null +++ b/input/manager.h @@ -0,0 +1,25 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +int input_init(void); +void input_exit(void); -- cgit From 57821cca7bfdb47cd3ddc32e70b6779a4a6cca2d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 16 Mar 2007 18:17:27 +0000 Subject: Add error specific skeleton files --- input/Makefile.am | 4 ++-- input/error.c | 28 ++++++++++++++++++++++++++++ input/error.h | 22 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 input/error.c create mode 100644 input/error.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 523e001b..576580f9 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -11,8 +11,8 @@ servicedir = $(libdir)/bluetooth service_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = main.c \ - manager.h manager.c server.h server.c \ - device.h device.c storage.h storage.c + manager.h manager.c error.h error.c \ + server.h server.c device.h device.c storage.h storage.c LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ diff --git a/input/error.c b/input/error.c new file mode 100644 index 00000000..55c459da --- /dev/null +++ b/input/error.c @@ -0,0 +1,28 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "error.h" diff --git a/input/error.h b/input/error.h new file mode 100644 index 00000000..e87dd676 --- /dev/null +++ b/input/error.h @@ -0,0 +1,22 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ -- cgit From f2c6a6f2debcccfb51d239834c3cf91a2c3a6c40 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 14:58:44 +0000 Subject: Moving input functions to the right files --- input/device.c | 1011 +++---------------------------------------------------- input/device.h | 9 +- input/error.c | 64 ++++ input/error.h | 22 ++ input/main.c | 5 +- input/manager.c | 854 ++++++++++++++++++++++++++++++++++++++++++++++ input/manager.h | 4 + input/storage.c | 31 +- input/storage.h | 3 +- 9 files changed, 1029 insertions(+), 974 deletions(-) (limited to 'input') 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 #include -#include -#include #include #include -#include -#include #include #include @@ -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 #endif +#include +#include + #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 #endif +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 -#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); -- cgit From a798bf638f53dacb92d23265a0d228886e8bd5f0 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 15:07:03 +0000 Subject: input: handling encrypt_link function return value properly --- input/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 8488b406..8f255fd7 100644 --- a/input/device.c +++ b/input/device.c @@ -612,8 +612,10 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&idev->src, &idev->dst); - if (err < 0) { + int ret; + ret = encrypt_link(&idev->src, &idev->dst); + if (ret < 0) { + err = -ret; close(ctl); goto failed; } -- cgit From d307da66278af3505e2bb1a35de4ef2ccefb9a6d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 15:17:15 +0000 Subject: input: moving "struct input_device" to device.h --- input/device.c | 23 ----------------------- input/device.h | 23 +++++++++++++++++++++++ input/manager.c | 9 ++++----- 3 files changed, 27 insertions(+), 28 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 8f255fd7..7e7325fb 100644 --- a/input/device.c +++ b/input/device.c @@ -61,29 +61,6 @@ #define UPDOWN_ENABLED 1 -struct fake_input { - GIOChannel *io; - int rfcomm; /* RFCOMM socket */ - int uinput; /* uinput socket */ - uint8_t ch; /* RFCOMM channel number */ -}; - -struct pending_connect { - DBusConnection *conn; - DBusMessage *msg; -}; - -struct input_device { - bdaddr_t src; - bdaddr_t dst; - char *name; - uint8_t major; - uint8_t minor; - struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ - struct fake_input *fake; - struct pending_connect *pending_connect; -}; - static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst) { struct input_device *idev; diff --git a/input/device.h b/input/device.h index b51056e2..604d7b79 100644 --- a/input/device.h +++ b/input/device.h @@ -21,6 +21,29 @@ * */ +struct fake_input { + GIOChannel *io; + int rfcomm; /* RFCOMM socket */ + int uinput; /* uinput socket */ + uint8_t ch; /* RFCOMM channel number */ +}; + +struct pending_connect { + DBusConnection *conn; + DBusMessage *msg; +}; + +struct input_device { + bdaddr_t src; + bdaddr_t dst; + char *name; + uint8_t major; + uint8_t minor; + struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + struct fake_input *fake; + struct pending_connect *pending_connect; +}; + 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, diff --git a/input/manager.c b/input/manager.c index 143471bc..38020a22 100644 --- a/input/manager.c +++ b/input/manager.c @@ -103,7 +103,6 @@ static void pending_req_free(struct pending_req *pr) g_free(pr); } -#if 0 static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) { struct input_device *idev; @@ -117,7 +116,7 @@ static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) return bacmp(&idev->dst, bdaddr); } -#endif + static int get_record(struct pending_req *pr, uint32_t handle, DBusPendingCallNotifyFunction cb) { @@ -589,6 +588,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusError derr; char adapter[18], adapter_path[32]; const char *addr; + GSList *l; bdaddr_t dst; uint32_t cls = 0; int dev_id; @@ -603,13 +603,12 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, } 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); -- cgit From 17033a18b3ee31d14b19f52d2328a2ba80f4ce1f Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 17:30:08 +0000 Subject: input: code cleanup --- input/manager.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 38020a22..ea34960b 100644 --- a/input/manager.c +++ b/input/manager.c @@ -68,15 +68,21 @@ struct input_manager { static DBusConnection *connection = NULL; -static struct pending_req *pending_req_new(DBusConnection *conn, - DBusMessage *msg, const char *adapter_path, +static struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, bdaddr_t *src, bdaddr_t *dst) { + char adapter[18], adapter_path[32]; struct pending_req *pr; + int dev_id; + pr = g_try_new0(struct pending_req, 1); if (!pr) return NULL; + ba2str(src, adapter); + dev_id = hci_devid(adapter); + snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); + pr->adapter_path = g_strdup(adapter_path); bacpy(&pr->src, src); bacpy(&pr->dst, dst); @@ -586,12 +592,10 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, 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, @@ -609,17 +613,12 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (l) return err_already_exists(conn, msg, "Input Already exists"); - /* 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); + pr = pending_req_new(conn, msg, &mgr->src, &dst); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From ab0791e294f317f970e5dc288c2d9f87fd22a4e2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 17:49:20 +0000 Subject: input: delete the stored input date when RemoveDevice is called --- input/manager.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index ea34960b..2675b5cb 100644 --- a/input/manager.c +++ b/input/manager.c @@ -114,7 +114,7 @@ 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)) + (void *) &idev)) return -1; if (!idev) @@ -648,6 +648,7 @@ 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; @@ -673,8 +674,10 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, 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 (!dbus_connection_get_object_path_data(connection, path, (void *) &idev)) + return err_does_not_exist(conn, msg, "Input doesn't exist"); + + del_stored_device_info(&mgr->src, &idev->dst); if (input_device_unregister(conn, path) < 0) { dbus_message_unref(reply); -- cgit From aa2c3ce4dcbbe498216407141479e20410d55b77 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 21 Mar 2007 14:40:19 +0000 Subject: input: code cleanup --- input/device.c | 74 +++++++++++++++++++++++++++------------------------------ input/device.h | 4 ++-- input/error.h | 2 -- input/manager.c | 6 ++--- 4 files changed, 40 insertions(+), 46 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 7e7325fb..5f70ede1 100644 --- a/input/device.c +++ b/input/device.c @@ -34,9 +34,9 @@ #include #include +#include #include #include -#include #include @@ -47,10 +47,10 @@ #include "textfile.h" #include "uinput.h" -#include "storage.h" +#include "device.h" #include "error.h" #include "manager.h" -#include "device.h" +#include "storage.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -1003,21 +1003,11 @@ static const DBusObjectPathVTable device_table = { /* * Input registration functions */ -int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, - struct hidp_connadd_req *hid, const char **path) +static int register_path(DBusConnection *conn, const char *path, struct input_device *idev) { DBusMessage *msg; - struct input_device *idev; - - idev = input_device_new(src, dst); - *path = create_input_path(idev->major, idev->minor); - - memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); - - /* FIXME: rd_data is a pointer - hacking */ - - if (!dbus_connection_register_object_path(conn, - *path, &device_table, idev)) { + if (!dbus_connection_register_object_path(conn, path, + &device_table, idev)) { error("Input device path registration failed"); return -1; } @@ -1028,50 +1018,56 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, 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; } -int fake_input_register(DBusConnection *conn, bdaddr_t *src, - bdaddr_t *dst, uint8_t ch, const char **path) +int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, + struct hidp_connadd_req *hid, const char **ppath) { - DBusMessage *msg; struct input_device *idev; + const char *path; idev = input_device_new(src, dst); - *path = create_input_path(idev->major, idev->minor); + path = create_input_path(idev->major, idev->minor); - idev->fake = g_new0(struct fake_input, 1); - idev->fake->ch = ch; + /* rd_data must not be deallocated since the memory address is copied */ + memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); - if (!dbus_connection_register_object_path(conn, - *path, &device_table, idev)) { - error("Fake input device path registration failed"); + if (register_path(conn, path, idev) < 0) return -1; - } - /* FIXME: dupplicated code */ - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceCreated"); - if (!msg) - return -1; + if (*ppath) + *ppath = path; - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &*path, - DBUS_TYPE_INVALID); + return 0; +} - send_message_and_unref(conn, msg); +int fake_input_register(DBusConnection *conn, bdaddr_t *src, + bdaddr_t *dst, uint8_t ch, const char **ppath) +{ + struct input_device *idev; + const char *path; - info("Created input device: %s", *path); + idev = input_device_new(src, dst); + path = create_input_path(idev->major, idev->minor); - return 0; + idev->fake = g_new0(struct fake_input, 1); + idev->fake->ch = ch; + + if (register_path(conn, path, idev) < 0) + return -1; + if (*ppath) + *ppath = path; + + return 0; } int input_device_unregister(DBusConnection *conn, const char *path) diff --git a/input/device.h b/input/device.h index 604d7b79..fa5cec12 100644 --- a/input/device.h +++ b/input/device.h @@ -45,7 +45,7 @@ struct input_device { }; int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, - struct hidp_connadd_req *hidp, const char **path); + struct hidp_connadd_req *hidp, const char **ppath); int fake_input_register(DBusConnection *conn, bdaddr_t *src, - bdaddr_t *dst, uint8_t ch, const char **path); + bdaddr_t *dst, uint8_t ch, const char **ppath); int input_device_unregister(DBusConnection *conn, const char *path); diff --git a/input/error.h b/input/error.h index 9f767d1a..f5f4c757 100644 --- a/input/error.h +++ b/input/error.h @@ -40,5 +40,3 @@ DBusHandlerResult err_does_not_exist(DBusConnection *conn, DBusMessage *msg, const char *str); DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg); - - diff --git a/input/manager.c b/input/manager.c index 2675b5cb..2ad8948e 100644 --- a/input/manager.c +++ b/input/manager.c @@ -30,9 +30,9 @@ #include #include #include +#include #include #include -#include #include @@ -42,10 +42,10 @@ #include "logging.h" #include "textfile.h" -#include "error.h" -#include "storage.h" #include "device.h" +#include "error.h" #include "manager.h" +#include "storage.h" const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; -- cgit From 75eb97849ccc85e25ca303c90e0fa4ccb03cad2f Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 21 Mar 2007 17:51:02 +0000 Subject: input: added possible errors returned by the methods. --- input/input-api.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index 2658f3a6..8d38fbb0 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -24,10 +24,18 @@ Methods array{string} ListDevices() On success it will return the path of the newly created device object. + Possible errors:org.bluez.input.AlreadyExists + org.bluez.input.NotSupported + org.bluez.input.ConnectionAttemptFailed + org.bluez.input.Failed + void RemoveDevice(string path) Remove the input device object for a given path. + Possible errors:org.bluez.input.DoesNotExist + org.bluez.input.Failed + Signals void DeviceCreated(string path) void DeviceRemoved(string path) @@ -66,10 +74,11 @@ Methods string GetAddress() Connect to the input device. + Possible errors:org.bluez.input.AlreadyConnected + org.bluez.input.ConnectionAttemptFailed + void Disconnect() Disconnect from the input device. - void SetTimeout(uint32 timeout) - - Set the idle timeout. + Possible errors:org.bluez.input.Failed -- cgit From 2bdadb9a01d23b0118161dfc598cc688ef5719e5 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 21 Mar 2007 18:02:00 +0000 Subject: input: added already connected error --- input/device.c | 2 +- input/error.c | 8 ++++++++ input/error.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 5f70ede1..45c7fa4a 100644 --- a/input/device.c +++ b/input/device.c @@ -801,7 +801,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, return err_connection_failed(conn, msg, "Connection in progress"); if (is_connected(idev)) - return err_connection_failed(conn, msg, "Already connected"); + return err_already_connected(conn, msg); idev->pending_connect = g_try_new0(struct pending_connect, 1); if (!idev->pending_connect) { diff --git a/input/error.c b/input/error.c index 658bdeff..24492ae2 100644 --- a/input/error.c +++ b/input/error.c @@ -66,6 +66,14 @@ DBusHandlerResult err_connection_failed(DBusConnection *conn, str)); } +DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".AlreadyConnected", + "Already connected to this device")); +} + DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str) { diff --git a/input/error.h b/input/error.h index f5f4c757..45981be5 100644 --- a/input/error.h +++ b/input/error.h @@ -33,6 +33,8 @@ DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, DBusHandlerResult err_connection_failed(DBusConnection *conn, DBusMessage *msg, const char *str); +DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg); + DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str); -- cgit From c95cdbbf157765752d7d9f8700ee721587d56f70 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 21 Mar 2007 19:19:27 +0000 Subject: input: return an input error instead of forward it(from hcid). --- input/error.c | 15 +++++++-------- input/error.h | 6 +++--- input/manager.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 25 deletions(-) (limited to 'input') diff --git a/input/error.c b/input/error.c index 24492ae2..3049b47f 100644 --- a/input/error.c +++ b/input/error.c @@ -41,14 +41,6 @@ DBusHandlerResult err_unknown_device(DBusConnection *conn, "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) { @@ -98,3 +90,10 @@ DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg) "The service is not supported by the remote device")); } +DBusHandlerResult err_invalid_args(DBusConnection *conn, + DBusMessage *msg, const char *str) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".InvalidArguments", str)); +} diff --git a/input/error.h b/input/error.h index 45981be5..32f080fb 100644 --- a/input/error.h +++ b/input/error.h @@ -24,9 +24,6 @@ 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); @@ -42,3 +39,6 @@ DBusHandlerResult err_does_not_exist(DBusConnection *conn, DBusMessage *msg, const char *str); DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg); + +DBusHandlerResult err_invalid_args(DBusConnection *conn, + DBusMessage *msg, const char *str); diff --git a/input/manager.c b/input/manager.c index 2ad8948e..4a973023 100644 --- a/input/manager.c +++ b/input/manager.c @@ -266,8 +266,12 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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); + if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + err_connection_failed(pr->conn, pr->msg, derr.message); + else + err_not_supported(pr->conn, pr->msg); + + error("GetRemoteServiceRecord failed: %s(%s)", derr.name, derr.message); goto fail; } @@ -329,8 +333,12 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) 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); + if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + err_connection_failed(pr->conn, pr->msg, derr.message); + else + err_not_supported(pr->conn, pr->msg); + + error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); goto fail; } @@ -374,8 +382,12 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) 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); + if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + err_connection_failed(pr->conn, pr->msg, derr.message); + else + err_not_supported(pr->conn, pr->msg); + + error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); goto fail; } @@ -421,8 +433,12 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) 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); + if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + err_connection_failed(pr->conn, pr->msg, derr.message); + else + err_not_supported(pr->conn, pr->msg); + + error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); goto fail; } @@ -477,8 +493,12 @@ static void headset_record_reply(DBusPendingCall *call, void *data) 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); + if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + err_connection_failed(pr->conn, pr->msg, derr.message); + else + err_not_supported(pr->conn, pr->msg); + + error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); goto fail; } @@ -551,8 +571,12 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) 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); + if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + err_connection_failed(pr->conn, pr->msg, derr.message); + else + err_not_supported(pr->conn, pr->msg); + + error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); goto fail; } @@ -601,7 +625,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &addr, DBUS_TYPE_INVALID)) { - err_generic(conn, msg, derr.name, derr.message); + err_invalid_args(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } @@ -658,7 +682,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) { - err_generic(conn, msg, derr.name, derr.message); + err_invalid_args(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } -- cgit From 07701210404d9bc7153af287cb58e7ea329fd8a8 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 13:34:37 +0000 Subject: input: minor code standard fixes --- input/device.c | 58 ++++++++++++++++++++++++++++----------------------------- input/device.h | 2 +- input/manager.c | 50 ++++++++++++++++++++++++------------------------- 3 files changed, 55 insertions(+), 55 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 45c7fa4a..3283e657 100644 --- a/input/device.c +++ b/input/device.c @@ -61,12 +61,12 @@ #define UPDOWN_ENABLED 1 -static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst) +static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) { - struct input_device *idev; + struct device *idev; uint32_t cls; - idev = g_new0(struct input_device, 1); + idev = g_new0(struct device, 1); bacpy(&idev->src, src); bacpy(&idev->dst, dst); @@ -94,7 +94,7 @@ static void pending_connect_free(struct pending_connect *pc) g_free(pc); } -static void input_device_free(struct input_device *idev) +static void device_free(struct device *idev) { if (!idev) return; @@ -344,8 +344,8 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, - struct input_device *idev) +static gboolean rfcomm_connect_cb(GIOChannel *chan, + GIOCondition cond, struct device *idev) { struct fake_input *fake; DBusMessage *reply; @@ -414,7 +414,7 @@ failed: return FALSE; } -static int rfcomm_connect(struct input_device *idev) +static int rfcomm_connect(struct device *idev) { struct sockaddr_rc addr; GIOChannel *io; @@ -487,7 +487,7 @@ failed: return -err; } -static int l2cap_connect(struct input_device *idev, +static int l2cap_connect(struct device *idev, unsigned short psm, GIOFunc cb) { GIOChannel *io; @@ -544,8 +544,8 @@ failed: return -1; } -static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct input_device *idev) +static gboolean interrupt_connect_cb(GIOChannel *chan, + GIOCondition cond, struct device *idev) { int ctl, isk, ret, err; socklen_t len; @@ -630,8 +630,8 @@ cleanup: return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct input_device *idev) +static gboolean control_connect_cb(GIOChannel *chan, + GIOCondition cond, struct device *idev) { int ret, csk, err; socklen_t len; @@ -693,7 +693,7 @@ failed: return FALSE; } -static int disconnect(struct input_device *idev, uint32_t flags) +static int disconnect(struct device *idev, uint32_t flags) { struct fake_input *fake = idev->fake; struct hidp_conndel_req req; @@ -755,7 +755,7 @@ fail: return -err; } -static int is_connected(struct input_device *idev) +static int is_connected(struct device *idev) { struct fake_input *fake = idev->fake; struct hidp_conninfo ci; @@ -793,9 +793,9 @@ static int is_connected(struct input_device *idev) * Input Device methods */ static DBusHandlerResult device_connect(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; if (idev->pending_connect) return err_connection_failed(conn, msg, "Connection in progress"); @@ -839,7 +839,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; if (disconnect(idev, 0) < 0) return err_failed(conn, msg, strerror(errno)); @@ -851,7 +851,7 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; dbus_bool_t connected; @@ -870,7 +870,7 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; char addr[18]; const char *paddr = addr; @@ -891,7 +891,7 @@ static DBusHandlerResult device_get_address(DBusConnection *conn, static DBusHandlerResult device_get_name(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; const char *pname = idev->hidp.name; @@ -909,7 +909,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, static DBusHandlerResult device_get_product_id(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; reply = dbus_message_new_method_return(msg); @@ -926,7 +926,7 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn, static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; reply = dbus_message_new_method_return(msg); @@ -987,11 +987,11 @@ static DBusHandlerResult device_message(DBusConnection *conn, static void device_unregister(DBusConnection *conn, void *data) { - struct input_device *idev = data; + struct device *idev = data; /* Disconnect if applied */ disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); - input_device_free(idev); + device_free(idev); } /* Virtual table to handle device object path hierarchy */ @@ -1003,7 +1003,7 @@ static const DBusObjectPathVTable device_table = { /* * Input registration functions */ -static int register_path(DBusConnection *conn, const char *path, struct input_device *idev) +static int register_path(DBusConnection *conn, const char *path, struct device *idev) { DBusMessage *msg; if (!dbus_connection_register_object_path(conn, path, @@ -1031,10 +1031,10 @@ static int register_path(DBusConnection *conn, const char *path, struct input_de int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hid, const char **ppath) { - struct input_device *idev; + struct device *idev; const char *path; - idev = input_device_new(src, dst); + idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); /* rd_data must not be deallocated since the memory address is copied */ @@ -1052,10 +1052,10 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, int fake_input_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, uint8_t ch, const char **ppath) { - struct input_device *idev; + struct device *idev; const char *path; - idev = input_device_new(src, dst); + idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); idev->fake = g_new0(struct fake_input, 1); diff --git a/input/device.h b/input/device.h index fa5cec12..398e3751 100644 --- a/input/device.h +++ b/input/device.h @@ -33,7 +33,7 @@ struct pending_connect { DBusMessage *msg; }; -struct input_device { +struct device { bdaddr_t src; bdaddr_t dst; char *name; diff --git a/input/manager.c b/input/manager.c index 4a973023..2faef35d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -61,7 +61,7 @@ struct pending_req { sdp_record_t *hid_rec; }; -struct input_manager { +struct manager { bdaddr_t src; /* Local adapter BT address */ GSList *paths; /* Input registered paths */ }; @@ -111,7 +111,7 @@ static void pending_req_free(struct pending_req *pr) static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) { - struct input_device *idev; + struct device *idev; if (!dbus_connection_get_object_path_data(connection, path, (void *) &idev)) @@ -256,7 +256,7 @@ 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 manager *mgr; struct pending_req *pr = data; struct hidp_connadd_req hidp; DBusError derr; @@ -482,7 +482,7 @@ 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 manager *mgr; struct pending_req *pr = data; uint8_t *rec_bin; sdp_record_t *rec; @@ -610,10 +610,10 @@ done: dbus_pending_call_unref(call); } -static DBusHandlerResult manager_create_device(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult create_device(DBusConnection *conn, + DBusMessage *msg, void *data) { - struct input_manager *mgr = data; + struct manager *mgr = data; struct pending_req *pr; DBusError derr; const char *addr; @@ -668,11 +668,11 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } -static DBusHandlerResult manager_remove_device(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult remove_device(DBusConnection *conn, + DBusMessage *msg, void *data) { - struct input_manager *mgr = data; - struct input_device *idev; + struct manager *mgr = data; + struct device *idev; DBusMessage *reply; DBusError derr; GSList *l; @@ -711,10 +711,10 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, return send_message_and_unref(conn, reply); } -static DBusHandlerResult manager_list_devices(DBusConnection *conn, - DBusMessage *msg, void *data) +static DBusHandlerResult list_devices(DBusConnection *conn, + DBusMessage *msg, void *data) { - struct input_manager *mgr = data; + struct manager *mgr = data; DBusMessageIter iter, iter_array; DBusMessage *reply; GSList *paths; @@ -755,18 +755,18 @@ static DBusHandlerResult manager_message(DBusConnection *conn, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (strcmp(member, "ListDevices") == 0) - return manager_list_devices(conn, msg, data); + return list_devices(conn, msg, data); if (strcmp(member, "CreateDevice") == 0) - return manager_create_device(conn, msg, data); + return create_device(conn, msg, data); if (strcmp(member, "RemoveDevice") == 0) - return manager_remove_device(conn, msg, data); + return remove_device(conn, msg, data); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -static void input_manager_free(struct input_manager *mgr) +static void manager_free(struct manager *mgr) { if (!mgr) return; @@ -781,11 +781,11 @@ static void input_manager_free(struct input_manager *mgr) static void manager_unregister(DBusConnection *conn, void *data) { - struct input_manager *mgr = data; + struct manager *mgr = data; info("Unregistered manager path"); - input_manager_free(mgr); + manager_free(mgr); } /* Virtual table to handle manager object path hierarchy */ @@ -800,7 +800,7 @@ static const DBusObjectPathVTable manager_table = { static void stored_input(char *key, char *value, void *data) { - struct input_manager *mgr = data; + struct manager *mgr = data; const char *path; struct hidp_connadd_req hidp; bdaddr_t dst; @@ -818,7 +818,7 @@ static void stored_input(char *key, char *value, void *data) mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); } -static int register_stored_inputs(struct input_manager *mgr) +static int register_stored_inputs(struct manager *mgr) { char filename[PATH_MAX + 1]; char addr[18]; @@ -832,7 +832,7 @@ static int register_stored_inputs(struct input_manager *mgr) int input_init(void) { - struct input_manager *mgr; + struct manager *mgr; bdaddr_t src; int dev_id; @@ -842,7 +842,7 @@ int input_init(void) dbus_connection_set_exit_on_disconnect(connection, TRUE); - mgr = g_new0(struct input_manager, 1); + mgr = g_new0(struct manager, 1); /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, @@ -873,7 +873,7 @@ int input_init(void) return 0; fail: - input_manager_free(mgr); + manager_free(mgr); return -1; } -- cgit From 0156f06757a3d7e813ae4124b499eac6c28d2ab7 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 13:42:31 +0000 Subject: input: Removed SetTimeout(method not defined) --- input/device.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 3283e657..f765c6f1 100644 --- a/input/device.c +++ b/input/device.c @@ -604,7 +604,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } - send_message_and_unref(idev->pending_connect->conn, dbus_message_new_method_return(idev->pending_connect->msg)); @@ -940,12 +939,6 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, return send_message_and_unref(conn, reply); } -static DBusHandlerResult device_set_timeout(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - static DBusHandlerResult device_message(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -979,9 +972,6 @@ static DBusHandlerResult device_message(DBusConnection *conn, if (strcmp(member, "GetVendorId") == 0) return device_get_vendor_id(conn, msg, data); - if (strcmp(member, "SetTimeout") == 0) - return device_set_timeout(conn, msg, data); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -- cgit From 27fe6a301b25a0a3196e27267e8a40f32b303f86 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 14:46:25 +0000 Subject: input: added Connected signal --- input/device.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index f765c6f1..fe38e759 100644 --- a/input/device.c +++ b/input/device.c @@ -348,7 +348,8 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { struct fake_input *fake; - DBusMessage *reply; + DBusMessage *reply, *signal; + const char *path; socklen_t len; int ret, err; @@ -394,11 +395,15 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); + /* Replying to the requestor */ reply = dbus_message_new_method_return(idev->pending_connect->msg); - if (reply) { - dbus_connection_send(idev->pending_connect->conn, reply, NULL); - dbus_message_unref(reply); - } + send_message_and_unref(idev->pending_connect->conn, reply); + + /* Sending the Connected signal */ + path = dbus_message_get_path(idev->pending_connect->msg); + signal = dbus_message_new_signal(path, + INPUT_DEVICE_INTERFACE, "Connected"); + send_message_and_unref(idev->pending_connect->conn, signal); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -548,6 +553,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { int ctl, isk, ret, err; + DBusMessage *signal; + const char *path; socklen_t len; if (cond & G_IO_NVAL) { @@ -604,9 +611,16 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } + /* Replying to the requestor */ send_message_and_unref(idev->pending_connect->conn, dbus_message_new_method_return(idev->pending_connect->msg)); + /* Sending the Connected signal */ + path = dbus_message_get_path(idev->pending_connect->msg); + signal = dbus_message_new_signal(path, + INPUT_DEVICE_INTERFACE, "Connected"); + send_message_and_unref(idev->pending_connect->conn, signal); + close (ctl); goto cleanup; failed: -- cgit From 6caed0053e1c938737111e9f34c671803131bfbf Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 14:53:22 +0000 Subject: input: Added the Disconnect signal --- input/device.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index fe38e759..5ebeb1ec 100644 --- a/input/device.c +++ b/input/device.c @@ -853,12 +853,21 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; + DBusMessage *signal; + const char *path; if (disconnect(idev, 0) < 0) return err_failed(conn, msg, strerror(errno)); - return send_message_and_unref(conn, + /* Replying to the requestor */ + send_message_and_unref(conn, dbus_message_new_method_return(msg)); + + /* Sending the Disconnect signal */ + path = dbus_message_get_path(msg); + signal = dbus_message_new_signal(path, + INPUT_DEVICE_INTERFACE, "Disconnected"); + return send_message_and_unref(conn, signal); } static DBusHandlerResult device_is_connected(DBusConnection *conn, -- cgit From 0506dca4cd766729a580bd81fa5c69b4e45a47fa Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 14:55:35 +0000 Subject: input API: added device Connected/Disconnected signals --- input/input-api.txt | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index 8d38fbb0..a4425914 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -82,3 +82,9 @@ Methods string GetAddress() Disconnect from the input device. Possible errors:org.bluez.input.Failed + +Signals void Connected() + + void Disconnected() + + -- cgit From 40ebcf393b790a4e6553e1314b29f0f34b3377a3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 Mar 2007 10:27:01 +0000 Subject: Improve integration with D-Bus system bus --- input/main.c | 17 +++++++++++++---- input/manager.c | 36 +++--------------------------------- input/manager.h | 3 +-- 3 files changed, 17 insertions(+), 39 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 2a6b3b59..057ee0db 100644 --- a/input/main.c +++ b/input/main.c @@ -51,6 +51,7 @@ static void sig_term(int sig) int main(int argc, char *argv[]) { + DBusConnection *conn; struct sigaction sa; start_logging("input", "Bluetooth Input daemon"); @@ -67,16 +68,22 @@ int main(int argc, char *argv[]) enable_debug(); - /* Create event loop */ main_loop = g_main_loop_new(NULL, FALSE); - if (input_init() < 0) { - error("Unable to get on D-Bus"); + conn = dbus_bus_system_setup_with_main_loop(NULL, NULL, NULL); + if (!conn) { + g_main_loop_unref(main_loop); + exit(1); + } + + if (input_init(conn) < 0) { + dbus_connection_unref(conn); + g_main_loop_unref(main_loop); exit(1); } if (argc > 1 && !strcmp(argv[1], "-s")) - internal_service("input"); + register_external_service(conn, "input", "Input service", ""); server_start(); @@ -86,6 +93,8 @@ int main(int argc, char *argv[]) input_exit(); + dbus_connection_unref(conn); + g_main_loop_unref(main_loop); info("Exit"); diff --git a/input/manager.c b/input/manager.c index 2faef35d..a4269df3 100644 --- a/input/manager.c +++ b/input/manager.c @@ -830,15 +830,13 @@ static int register_stored_inputs(struct manager *mgr) return 0; } -int input_init(void) +int input_init(DBusConnection *conn) { struct manager *mgr; bdaddr_t src; int dev_id; - connection = init_dbus(NULL, NULL, NULL); - if (!connection) - return -1; + connection = dbus_connection_ref(conn); dbus_connection_set_exit_on_disconnect(connection, TRUE); @@ -883,34 +881,6 @@ 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); + connection = NULL; } diff --git a/input/manager.h b/input/manager.h index 9eee22aa..7fc6f162 100644 --- a/input/manager.h +++ b/input/manager.h @@ -24,6 +24,5 @@ #define INPUT_PATH "/org/bluez/input" #define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" -int input_init(void); +int input_init(DBusConnection *conn); void input_exit(void); -void internal_service(const char *identifier); -- cgit From 9691f47c9f858b4ae512e6d3b78bd1bb398bec06 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 Mar 2007 10:40:42 +0000 Subject: Service must start even if there is no adapter available --- input/manager.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index a4269df3..7a8ce746 100644 --- a/input/manager.c +++ b/input/manager.c @@ -834,7 +834,9 @@ int input_init(DBusConnection *conn) { struct manager *mgr; bdaddr_t src; +#if 0 int dev_id; +#endif connection = dbus_connection_ref(conn); @@ -853,6 +855,7 @@ int input_init(DBusConnection *conn) /* Set the default adapter */ bacpy(&src, BDADDR_ANY); +#if 0 dev_id = hci_get_route(&src); if (dev_id < 0) { error("Bluetooth device not available"); @@ -863,6 +866,7 @@ int input_init(DBusConnection *conn) error("Can't get local adapter device info"); goto fail; } +#endif bacpy(&mgr->src, &src); /* Register well known HID devices */ -- cgit From a36be2a103e95b04d5b348c83b41dc8c06439990 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 4 Apr 2007 07:30:14 +0000 Subject: Fix missing G_IO_NVAL handling --- input/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index b140bb6b..911fc8e7 100644 --- a/input/server.c +++ b/input/server.c @@ -69,7 +69,7 @@ static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst) static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data) { - if (cond & (G_IO_HUP | G_IO_ERR)) + if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) return FALSE; return TRUE; @@ -133,7 +133,7 @@ static void create_watch(int sk, struct session_data *session) io = g_io_channel_unix_new(sk); g_io_channel_set_close_on_unref(io, TRUE); - g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR, + g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, session_event, session); g_io_channel_unref(io); -- cgit From 1826edb5d4e3998ba026d2d0436bbbae9047ed3a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 4 Apr 2007 21:36:45 +0000 Subject: input: Added authorization support for incomming connections --- input/main.c | 5 ---- input/manager.c | 5 ++++ input/server.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- input/server.h | 2 +- 4 files changed, 85 insertions(+), 8 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 057ee0db..cfe31b56 100644 --- a/input/main.c +++ b/input/main.c @@ -40,7 +40,6 @@ #include "logging.h" #include "manager.h" -#include "server.h" static GMainLoop *main_loop; @@ -85,12 +84,8 @@ int main(int argc, char *argv[]) if (argc > 1 && !strcmp(argv[1], "-s")) register_external_service(conn, "input", "Input service", ""); - server_start(); - g_main_loop_run(main_loop); - server_stop(); - input_exit(); dbus_connection_unref(conn); diff --git a/input/manager.c b/input/manager.c index 7a8ce746..567ea6ee 100644 --- a/input/manager.c +++ b/input/manager.c @@ -43,6 +43,7 @@ #include "textfile.h" #include "device.h" +#include "server.h" #include "error.h" #include "manager.h" #include "storage.h" @@ -872,6 +873,8 @@ int input_init(DBusConnection *conn) /* Register well known HID devices */ register_stored_inputs(mgr); + server_start(connection); + return 0; fail: @@ -884,6 +887,8 @@ void input_exit(void) { dbus_connection_unregister_object_path(connection, INPUT_PATH); + server_stop(); + dbus_connection_unref(connection); connection = NULL; diff --git a/input/server.c b/input/server.c index 911fc8e7..e08bee22 100644 --- a/input/server.c +++ b/input/server.c @@ -40,6 +40,7 @@ #include #include "logging.h" +#include "dbus.h" #include "server.h" #include "storage.h" @@ -52,6 +53,7 @@ struct session_data { }; static GSList *sessions = NULL; +static DBusConnection *connection = NULL; static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst) { @@ -126,6 +128,68 @@ cleanup: g_free(session); } +static void authorization_callback(DBusPendingCall *pcall, void *data) +{ + struct session_data *session = data; + DBusMessage *reply = dbus_pending_call_steal_reply(pcall); + DBusError derr; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Access denied: %s", derr.message); + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { + debug("FIXME: Cancel authorization request"); + } + dbus_error_free(&derr); + + sessions = g_slist_remove(sessions, session); + + close(session->intr_sk); + close(session->ctrl_sk); + + g_free(session); + + goto failed; + } + + create_device(session); +failed: + dbus_message_unref(reply); + dbus_pending_call_unref(pcall); +} + +static int authorize_device(struct session_data *session) +{ + DBusMessage *msg; + DBusPendingCall *pending; + char addr[18]; + const char *paddr = addr; + const char *uuid = ""; /* FIXME: */ + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Database", "RequestAuthorization"); + if (!msg) { + error("Unable to allocat new RequestAuthorization method call"); + return -ENOMEM; + } + + memset(addr, 0, sizeof(addr)); + ba2str(&session->dst, addr); + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(connection, + msg, &pending, -1) == FALSE) + return -EACCES; + + dbus_pending_call_set_notify(pending, authorization_callback, session, NULL); + dbus_message_unref(msg); + + return 0; +} + static void create_watch(int sk, struct session_data *session) { GIOChannel *io; @@ -176,7 +240,18 @@ static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data if (session) { if (psm == 19) { session->intr_sk = nsk; - create_device(session); + if (authorize_device(session) < 0) { + error("Authorization request failed"); + sessions = g_slist_remove(sessions, session); + + close(session->intr_sk); + close(session->ctrl_sk); + + g_free(session); + + return TRUE; + } + debug("Waiting authorization ..."); } else { error("Control channel already established"); close(nsk); @@ -238,7 +313,7 @@ static GIOChannel *setup_l2cap(unsigned int psm) static GIOChannel *ctrl_io = NULL; static GIOChannel *intr_io = NULL; -int server_start(void) +int server_start(DBusConnection *conn) { ctrl_io = setup_l2cap(17); if (!ctrl_io) { @@ -253,6 +328,8 @@ int server_start(void) ctrl_io = NULL; } + connection = conn; + return 0; } diff --git a/input/server.h b/input/server.h index f0237d4f..ac2a073e 100644 --- a/input/server.h +++ b/input/server.h @@ -21,5 +21,5 @@ * */ -int server_start(void); +int server_start(DBusConnection *conn); void server_stop(void); -- cgit From 0eede007ad95a1d972b43e860164d32effcde9c9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 4 Apr 2007 21:45:43 +0000 Subject: input: send CancelAuthorizationRequest if there is a pending authorization --- input/server.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index e08bee22..b3bde829 100644 --- a/input/server.c +++ b/input/server.c @@ -128,6 +128,27 @@ cleanup: g_free(session); } +static void cancel_authorization(const char *addr) +{ + DBusMessage *msg; + const char *uuid = ""; + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Database", + "CancelAuthorizationRequest"); + if (!msg) { + error("Unable to allocate new method call"); + return; + } + + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID); + + send_message_and_unref(connection, msg); +} + static void authorization_callback(DBusPendingCall *pcall, void *data) { struct session_data *session = data; @@ -138,7 +159,10 @@ static void authorization_callback(DBusPendingCall *pcall, void *data) if (dbus_set_error_from_message(&derr, reply)) { error("Access denied: %s", derr.message); if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - debug("FIXME: Cancel authorization request"); + char addr[18]; + memset(addr, 0, sizeof(addr)); + ba2str(&session->dst, addr); + cancel_authorization(addr); } dbus_error_free(&derr); -- cgit From 3b97946c32b28af92a5a809bb690dc9be3af6eaf Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 5 Apr 2007 13:34:30 +0000 Subject: input: fixed GIOChannel problem(CPU usage and invalid file descriptor close warning) --- input/server.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index b3bde829..82895816 100644 --- a/input/server.c +++ b/input/server.c @@ -71,9 +71,14 @@ static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst) static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data) { - if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) + if (cond & G_IO_NVAL) return FALSE; + if (cond & (G_IO_HUP | G_IO_ERR)) { + g_io_channel_close(chan); + return FALSE; + } + return TRUE; } @@ -219,7 +224,6 @@ static void create_watch(int sk, struct session_data *session) GIOChannel *io; io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, TRUE); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, session_event, session); -- cgit From 7a2733b957f458e8bc4d33a37f3d60aa05af67fd Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 5 Apr 2007 13:51:58 +0000 Subject: input: missing close listen sockets(control/interrupt) --- input/server.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'input') diff --git a/input/server.c b/input/server.c index 82895816..d4bf977f 100644 --- a/input/server.c +++ b/input/server.c @@ -348,6 +348,7 @@ int server_start(DBusConnection *conn) error("Failed to listen on control channel"); return -1; } + g_io_channel_set_close_on_unref(ctrl_io, TRUE); intr_io = setup_l2cap(19); if (!intr_io) { @@ -355,6 +356,7 @@ int server_start(DBusConnection *conn) g_io_channel_unref(ctrl_io); ctrl_io = NULL; } + g_io_channel_set_close_on_unref(intr_io, TRUE); connection = conn; -- cgit From 15746ba2445be8a8952263d829d5363e27690ea4 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 11 Apr 2007 16:00:33 +0000 Subject: input manager: use the default adapter to create a new device. --- input/manager.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 567ea6ee..11aa65a4 100644 --- a/input/manager.c +++ b/input/manager.c @@ -619,8 +619,9 @@ static DBusHandlerResult create_device(DBusConnection *conn, DBusError derr; const char *addr; GSList *l; - bdaddr_t dst; + bdaddr_t src, dst; uint32_t cls = 0; + int dev_id; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -631,6 +632,18 @@ static DBusHandlerResult create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } + /* Get the default adapter */ + dev_id = hci_get_route(NULL); + if (dev_id < 0) { + error("Bluetooth adapter not available"); + return err_failed(conn, msg, "Adapter not available"); + } + + if (hci_devba(dev_id, &src) < 0) { + error("Can't get local adapter device info"); + return err_failed(conn, msg, "Adapter not available"); + } + str2ba(addr, &dst); l = g_slist_find_custom(mgr->paths, &dst, @@ -638,12 +651,12 @@ static DBusHandlerResult create_device(DBusConnection *conn, if (l) return err_already_exists(conn, msg, "Input Already exists"); - if (read_device_class(&mgr->src, &dst, &cls) < 0) { + if (read_device_class(&src, &dst, &cls) < 0) { error("Device class not available"); return err_not_supported(conn, msg); } - pr = pending_req_new(conn, msg, &mgr->src, &dst); + pr = pending_req_new(conn, msg, &src, &dst); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From 56943b11d7ab291467d8e7fa4551cd1f21b09402 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 11 Apr 2007 16:10:07 +0000 Subject: input manager: delete the stored input info based on the input device source/destination address --- input/manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 11aa65a4..075d82d1 100644 --- a/input/manager.c +++ b/input/manager.c @@ -715,7 +715,7 @@ static DBusHandlerResult remove_device(DBusConnection *conn, if (!dbus_connection_get_object_path_data(connection, path, (void *) &idev)) return err_does_not_exist(conn, msg, "Input doesn't exist"); - del_stored_device_info(&mgr->src, &idev->dst); + del_stored_device_info(&idev->src, &idev->dst); if (input_device_unregister(conn, path) < 0) { dbus_message_unref(reply); -- cgit From fcaa89e46ffa24f02bea8c5942733a3ab738457c Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 11 Apr 2007 18:39:15 +0000 Subject: input manager: read all /var/lib/bluetooth/*/input files when the service starts --- input/manager.c | 64 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 28 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 075d82d1..6053de65 100644 --- a/input/manager.c +++ b/input/manager.c @@ -25,6 +25,8 @@ #include #endif +#include +#include #include #include @@ -63,8 +65,8 @@ struct pending_req { }; struct manager { - bdaddr_t src; /* Local adapter BT address */ - GSList *paths; /* Input registered paths */ + bdaddr_t src; + GSList *paths; /* Input registered paths */ }; static DBusConnection *connection = NULL; @@ -826,31 +828,53 @@ static void stored_input(char *key, char *value, void *data) return; } + /* FIXME: Ignore already registered devices */ 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 manager *mgr) +static void register_stored_inputs(struct manager *mgr) { + char dirname[PATH_MAX + 1]; char filename[PATH_MAX + 1]; - char addr[18]; + struct dirent *de; + DIR *dir; + int dev_id; - ba2str(&mgr->src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "input"); - textfile_foreach(filename, stored_input, mgr); + dev_id = hci_get_route(BDADDR_ANY); + if (dev_id < 0) { + error("Bluetooth device not available"); + return; + } - return 0; + if (hci_devba(dev_id, &mgr->src) < 0) { + error("Can't get local adapter device info"); + return; + } + + snprintf(dirname, PATH_MAX, "%s", STORAGEDIR); + + dir = opendir(dirname); + if (!dir) + return; + + while ((de = readdir(dir)) != NULL) { + if (!isdigit(de->d_name[0])) + continue; + + create_name(filename, PATH_MAX, STORAGEDIR, + de->d_name, "input"); + textfile_foreach(filename, stored_input, mgr); + } + + closedir(dir); } int input_init(DBusConnection *conn) { struct manager *mgr; - bdaddr_t src; -#if 0 - int dev_id; -#endif connection = dbus_connection_ref(conn); @@ -867,22 +891,6 @@ int input_init(DBusConnection *conn) info("Registered input manager path:%s", INPUT_PATH); - /* Set the default adapter */ - bacpy(&src, BDADDR_ANY); -#if 0 - 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; - } -#endif - - bacpy(&mgr->src, &src); /* Register well known HID devices */ register_stored_inputs(mgr); -- cgit From b950614676315d8e180f02ad5eee8da505e18f44 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 11 Apr 2007 18:58:10 +0000 Subject: input manager: fixed code standard --- input/manager.c | 63 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 6053de65..61719c05 100644 --- a/input/manager.c +++ b/input/manager.c @@ -50,18 +50,18 @@ #include "manager.h" #include "storage.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"; +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; + 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 manager { @@ -71,8 +71,8 @@ struct manager { static DBusConnection *connection = NULL; -static struct pending_req *pending_req_new(DBusConnection *conn, DBusMessage *msg, - bdaddr_t *src, bdaddr_t *dst) +static struct pending_req *pending_req_new(DBusConnection *conn, + DBusMessage *msg, bdaddr_t *src, bdaddr_t *dst) { char adapter[18], adapter_path[32]; struct pending_req *pr; @@ -269,12 +269,14 @@ static void hid_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) err_connection_failed(pr->conn, pr->msg, derr.message); else err_not_supported(pr->conn, pr->msg); - error("GetRemoteServiceRecord failed: %s(%s)", derr.name, derr.message); + error("GetRemoteServiceRecord failed: %s(%s)", + derr.name, derr.message); goto fail; } @@ -336,12 +338,14 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) err_connection_failed(pr->conn, pr->msg, derr.message); else err_not_supported(pr->conn, pr->msg); - error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); + error("GetRemoteServiceHandles: %s(%s)", + derr.name, derr.message); goto fail; } @@ -385,12 +389,14 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) err_connection_failed(pr->conn, pr->msg, derr.message); else err_not_supported(pr->conn, pr->msg); - error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); + error("GetRemoteServiceRecord: %s(%s)", + derr.name, derr.message); goto fail; } @@ -436,12 +442,14 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) err_connection_failed(pr->conn, pr->msg, derr.message); else err_not_supported(pr->conn, pr->msg); - error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); + error("GetRemoteServiceHandles: %s(%s)", + derr.name, derr.message); goto fail; } @@ -496,12 +504,14 @@ static void headset_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) err_connection_failed(pr->conn, pr->msg, derr.message); else err_not_supported(pr->conn, pr->msg); - error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); + error("GetRemoteServiceRecord: %s(%s)", + derr.name, derr.message); goto fail; } @@ -574,12 +584,14 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) err_connection_failed(pr->conn, pr->msg, derr.message); else err_not_supported(pr->conn, pr->msg); - error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); + error("GetRemoteServiceHandles: %s(%s)", + derr.name, derr.message); goto fail; } @@ -714,7 +726,8 @@ static DBusHandlerResult remove_device(DBusConnection *conn, g_free(l->data); mgr->paths = g_slist_remove(mgr->paths, l->data); - if (!dbus_connection_get_object_path_data(connection, path, (void *) &idev)) + if (!dbus_connection_get_object_path_data(connection, + path, (void *) &idev)) return err_does_not_exist(conn, msg, "Input doesn't exist"); del_stored_device_info(&idev->src, &idev->dst); -- cgit From 94a49f14f2be23349b65f353daa1d20bb9cfc8cf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 11 Apr 2007 20:25:40 +0000 Subject: Use global device list for manager --- input/manager.c | 129 ++++++++++++++++++++++++-------------------------------- 1 file changed, 54 insertions(+), 75 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 61719c05..d55699ee 100644 --- a/input/manager.c +++ b/input/manager.c @@ -50,9 +50,9 @@ #include "manager.h" #include "storage.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"; +static const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; +static const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; +static const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct pending_req { char *adapter_path; /* Local adapter D-Bus path */ @@ -64,10 +64,7 @@ struct pending_req { sdp_record_t *hid_rec; }; -struct manager { - bdaddr_t src; - GSList *paths; /* Input registered paths */ -}; +static GSList *device_paths = NULL; /* Input registered paths */ static DBusConnection *connection = NULL; @@ -99,16 +96,22 @@ 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); } @@ -235,7 +238,8 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->rd_data = g_try_malloc0(pdlist->unitSize); if (req->rd_data) { - memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); + memcpy(req->rd_data, (unsigned char *) pdlist->val.str, + pdlist->unitSize); req->rd_size = pdlist->unitSize; } } @@ -259,7 +263,6 @@ static void hid_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusMessage *pr_reply; - struct manager *mgr; struct pending_req *pr = data; struct hidp_connadd_req hidp; DBusError derr; @@ -313,14 +316,16 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - dbus_connection_get_object_path_data(pr->conn, INPUT_PATH, (void *) &mgr); - mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); + device_paths = g_slist_append(device_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); + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + send_message_and_unref(pr->conn, pr_reply); + fail: dbus_error_free(&derr); pending_req_free(pr); @@ -371,9 +376,11 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) /* Wait record reply */ goto done; } + fail: dbus_error_free(&derr); pending_req_free(pr); + done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -427,6 +434,7 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) fail: dbus_error_free(&derr); pending_req_free(pr); + done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -483,6 +491,7 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) fail: dbus_error_free(&derr); pending_req_free(pr); + done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -493,7 +502,6 @@ static void headset_record_reply(DBusPendingCall *call, void *data) DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusMessage *pr_reply; DBusError derr; - struct manager *mgr; struct pending_req *pr = data; uint8_t *rec_bin; sdp_record_t *rec; @@ -541,7 +549,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) } ch = sdp_get_proto_port(protos, RFCOMM_UUID); - sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, NULL); + sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); sdp_record_free(rec); @@ -559,14 +567,16 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } - dbus_connection_get_object_path_data(pr->conn, INPUT_PATH, (void *) &mgr); - mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); + device_paths = g_slist_append(device_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); @@ -617,9 +627,11 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) /* Wait record reply */ goto done; } + fail: dbus_error_free(&derr); pending_req_free(pr); + done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -628,7 +640,6 @@ done: static DBusHandlerResult create_device(DBusConnection *conn, DBusMessage *msg, void *data) { - struct manager *mgr = data; struct pending_req *pr; DBusError derr; const char *addr; @@ -660,8 +671,8 @@ static DBusHandlerResult create_device(DBusConnection *conn, str2ba(addr, &dst); - l = g_slist_find_custom(mgr->paths, &dst, - (GCompareFunc) path_bdaddr_cmp); + l = g_slist_find_custom(device_paths, &dst, + (GCompareFunc) path_bdaddr_cmp); if (l) return err_already_exists(conn, msg, "Input Already exists"); @@ -699,7 +710,6 @@ static DBusHandlerResult create_device(DBusConnection *conn, static DBusHandlerResult remove_device(DBusConnection *conn, DBusMessage *msg, void *data) { - struct manager *mgr = data; struct device *idev; DBusMessage *reply; DBusError derr; @@ -715,7 +725,7 @@ static DBusHandlerResult remove_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - l = g_slist_find_custom(mgr->paths, path, (GCompareFunc) strcmp); + l = g_slist_find_custom(device_paths, path, (GCompareFunc) strcmp); if (!l) return err_does_not_exist(conn, msg, "Input doesn't exist"); @@ -724,7 +734,7 @@ static DBusHandlerResult remove_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; g_free(l->data); - mgr->paths = g_slist_remove(mgr->paths, l->data); + device_paths = g_slist_remove(device_paths, l->data); if (!dbus_connection_get_object_path_data(connection, path, (void *) &idev)) @@ -743,7 +753,6 @@ static DBusHandlerResult remove_device(DBusConnection *conn, static DBusHandlerResult list_devices(DBusConnection *conn, DBusMessage *msg, void *data) { - struct manager *mgr = data; DBusMessageIter iter, iter_array; DBusMessage *reply; GSList *paths; @@ -756,16 +765,17 @@ static DBusHandlerResult list_devices(DBusConnection *conn, 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) { + for (paths = device_paths; paths != NULL; paths = paths->next) { const char *ppath = paths->data; dbus_message_iter_append_basic(&iter_array, - DBUS_TYPE_STRING, &ppath); + 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) { @@ -795,26 +805,13 @@ static DBusHandlerResult manager_message(DBusConnection *conn, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -static void manager_free(struct 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 manager *mgr = data; - info("Unregistered manager path"); - manager_free(mgr); + g_slist_foreach(device_paths, (GFunc) free, NULL); + + g_slist_free(device_paths); } /* Virtual table to handle manager object path hierarchy */ @@ -829,43 +826,31 @@ static const DBusObjectPathVTable manager_table = { static void stored_input(char *key, char *value, void *data) { - struct manager *mgr = data; const char *path; struct hidp_connadd_req hidp; - bdaddr_t dst; + bdaddr_t dst, *src = data; str2ba(key, &dst); memset(&hidp, 0, sizeof(struct hidp_connadd_req)); - if (parse_stored_device_info(value, &hidp) < 0) { + + if (parse_stored_device_info(value, &hidp) < 0) return; - } /* FIXME: Ignore already registered devices */ - if (input_device_register(connection, &mgr->src, &dst, &hidp, &path) < 0) + if (input_device_register(connection, src, &dst, &hidp, &path) < 0) return; - mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); + device_paths = g_slist_append(device_paths, g_strdup(path)); } -static void register_stored_inputs(struct manager *mgr) +static void register_stored_inputs(void) { char dirname[PATH_MAX + 1]; char filename[PATH_MAX + 1]; struct dirent *de; DIR *dir; - int dev_id; - - dev_id = hci_get_route(BDADDR_ANY); - if (dev_id < 0) { - error("Bluetooth device not available"); - return; - } - - if (hci_devba(dev_id, &mgr->src) < 0) { - error("Can't get local adapter device info"); - return; - } + bdaddr_t src; snprintf(dirname, PATH_MAX, "%s", STORAGEDIR); @@ -878,8 +863,11 @@ static void register_stored_inputs(struct manager *mgr) continue; create_name(filename, PATH_MAX, STORAGEDIR, - de->d_name, "input"); - textfile_foreach(filename, stored_input, mgr); + de->d_name, "input"); + + str2ba(de->d_name, &src); + + textfile_foreach(filename, stored_input, &src); } closedir(dir); @@ -887,34 +875,25 @@ static void register_stored_inputs(struct manager *mgr) int input_init(DBusConnection *conn) { - struct manager *mgr; - connection = dbus_connection_ref(conn); dbus_connection_set_exit_on_disconnect(connection, TRUE); - mgr = g_new0(struct manager, 1); - /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, - &manager_table, mgr)) { + &manager_table, NULL)) { error("D-Bus failed to register %s path", INPUT_PATH); - goto fail; + return -1; } info("Registered input manager path:%s", INPUT_PATH); /* Register well known HID devices */ - register_stored_inputs(mgr); + register_stored_inputs(); server_start(connection); return 0; - -fail: - manager_free(mgr); - - return -1; } void input_exit(void) -- cgit From eca0800a92771ee23890fdf54a70629bcbca648c Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 11 Apr 2007 21:18:27 +0000 Subject: fixed commentary --- input/manager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index d55699ee..bd75dc5a 100644 --- a/input/manager.c +++ b/input/manager.c @@ -837,7 +837,10 @@ static void stored_input(char *key, char *value, void *data) if (parse_stored_device_info(value, &hidp) < 0) return; - /* FIXME: Ignore already registered devices */ + /* + * Repeated entries for the same remote device are + * acceptable since the source is different. + */ if (input_device_register(connection, src, &dst, &hidp, &path) < 0) return; -- cgit From e3aec1dd412fc0adb0587edf750979e4d18906b0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 12 Apr 2007 09:59:15 +0000 Subject: Keep the device structure local --- input/device.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ input/device.h | 26 +++----------------------- input/manager.c | 31 ++++++++++--------------------- 3 files changed, 61 insertions(+), 44 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 5ebeb1ec..a29cc095 100644 --- a/input/device.c +++ b/input/device.c @@ -61,6 +61,29 @@ #define UPDOWN_ENABLED 1 +struct pending_connect { + DBusConnection *conn; + DBusMessage *msg; +}; + +struct fake_input { + GIOChannel *io; + int rfcomm; /* RFCOMM socket */ + int uinput; /* uinput socket */ + uint8_t ch; /* RFCOMM channel number */ +}; + +struct device { + bdaddr_t src; + bdaddr_t dst; + char *name; + uint8_t major; + uint8_t minor; + struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + struct fake_input *fake; + struct pending_connect *pending_connect; +}; + static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; @@ -1086,6 +1109,13 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, int input_device_unregister(DBusConnection *conn, const char *path) { DBusMessage *msg; + struct device *idev; + + if (!dbus_connection_get_object_path_data(conn, + path, (void *) &idev)) + return -1; + + del_stored_device_info(&idev->src, &idev->dst); if (!dbus_connection_unregister_object_path(conn, path)) { error("Input device path unregister failed"); @@ -1105,3 +1135,21 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } + +int input_device_get_bdaddr(DBusConnection *conn, const char *path, + bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev; + + if (!dbus_connection_get_object_path_data(conn, path, + (void *) &idev)) + return -1; + + if (!idev) + return -1; + + bacpy(src, &idev->src); + bacpy(dst, &idev->dst); + + return 0; +} diff --git a/input/device.h b/input/device.h index 398e3751..b156b985 100644 --- a/input/device.h +++ b/input/device.h @@ -21,31 +21,11 @@ * */ -struct fake_input { - GIOChannel *io; - int rfcomm; /* RFCOMM socket */ - int uinput; /* uinput socket */ - uint8_t ch; /* RFCOMM channel number */ -}; - -struct pending_connect { - DBusConnection *conn; - DBusMessage *msg; -}; - -struct device { - bdaddr_t src; - bdaddr_t dst; - char *name; - uint8_t major; - uint8_t minor; - struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ - struct fake_input *fake; - struct pending_connect *pending_connect; -}; - int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hidp, const char **ppath); int fake_input_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, uint8_t ch, const char **ppath); int input_device_unregister(DBusConnection *conn, const char *path); + +int input_device_get_bdaddr(DBusConnection *conn, const char *path, + bdaddr_t *src, bdaddr_t *dst); diff --git a/input/manager.c b/input/manager.c index bd75dc5a..f74349df 100644 --- a/input/manager.c +++ b/input/manager.c @@ -115,20 +115,6 @@ static void pending_req_free(struct pending_req *pr) g_free(pr); } -static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) -{ - struct device *idev; - - if (!dbus_connection_get_object_path_data(connection, path, - (void *) &idev)) - return -1; - - if (!idev) - return -1; - - return bacmp(&idev->dst, bdaddr); -} - static int get_record(struct pending_req *pr, uint32_t handle, DBusPendingCallNotifyFunction cb) { @@ -637,6 +623,16 @@ done: dbus_pending_call_unref(call); } +static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) +{ + bdaddr_t src, dst; + + if (input_device_get_bdaddr(connection, path, &src, &dst) < 0) + return -1; + + return bacmp(&dst, bdaddr); +} + static DBusHandlerResult create_device(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -710,7 +706,6 @@ static DBusHandlerResult create_device(DBusConnection *conn, static DBusHandlerResult remove_device(DBusConnection *conn, DBusMessage *msg, void *data) { - struct device *idev; DBusMessage *reply; DBusError derr; GSList *l; @@ -736,12 +731,6 @@ static DBusHandlerResult remove_device(DBusConnection *conn, g_free(l->data); device_paths = g_slist_remove(device_paths, l->data); - if (!dbus_connection_get_object_path_data(connection, - path, (void *) &idev)) - return err_does_not_exist(conn, msg, "Input doesn't exist"); - - del_stored_device_info(&idev->src, &idev->dst); - if (input_device_unregister(conn, path) < 0) { dbus_message_unref(reply); return err_failed(conn, msg, "D-Bus path unregistration failed"); -- cgit From 4f32f865517ba5c6a65550d39504a44065b9d013 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 13:22:58 +0000 Subject: input: Connect/disconnect to the control and interrupt psm at the ending of CreateDevice --- input/device.c | 127 ++++++++++++++++++++--------------------- input/device.h | 4 ++ input/manager.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 218 insertions(+), 87 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index a29cc095..76049ec4 100644 --- a/input/device.c +++ b/input/device.c @@ -54,9 +54,6 @@ #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" -#define L2CAP_PSM_HIDP_CTRL 0x11 -#define L2CAP_PSM_HIDP_INTR 0x13 - #define BUF_SIZE 16 #define UPDOWN_ENABLED 1 @@ -515,63 +512,6 @@ failed: return -err; } -static int l2cap_connect(struct device *idev, - unsigned short psm, GIOFunc cb) -{ - GIOChannel *io; - struct sockaddr_l2 addr; - struct l2cap_options opts; - int sk, err; - - if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &idev->src); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) - goto failed; - - if (set_nonblocking(sk) < 0) - goto failed; - - memset(&opts, 0, sizeof(opts)); - opts.imtu = HIDP_DEFAULT_MTU; - opts.omtu = HIDP_DEFAULT_MTU; - opts.flush_to = 0xffff; - - if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) - goto failed; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &idev->dst); - addr.l2_psm = htobs(psm); - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, FALSE); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - if (!(errno == EAGAIN || errno == EINPROGRESS)) - goto failed; - - g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) cb, idev); - } else { - cb(io, G_IO_OUT, idev); - } - - return 0; - -failed: - err = errno; - close(sk); - errno = err; - - return -1; -} - static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { @@ -704,8 +644,8 @@ static gboolean control_connect_cb(GIOChannel *chan, } /* Connect to the HID interrupt channel */ - if (l2cap_connect(idev, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb) < 0) { + if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb, idev) < 0) { err = errno; error("L2CAP connect failed:%s (%d)", strerror(errno), errno); @@ -861,8 +801,9 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - if (l2cap_connect(idev, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb) < 0) { + if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb, idev) < 0) { + error("L2CAP connect failed: %s(%d)", strerror(errno), errno); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -1153,3 +1094,61 @@ int input_device_get_bdaddr(DBusConnection *conn, const char *path, return 0; } + +int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data) +{ + GIOChannel *io; + struct sockaddr_l2 addr; + struct l2cap_options opts; + int sk, err; + + if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, src); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) + goto failed; + + if (set_nonblocking(sk) < 0) + goto failed; + + memset(&opts, 0, sizeof(opts)); + opts.imtu = HIDP_DEFAULT_MTU; + opts.omtu = HIDP_DEFAULT_MTU; + opts.flush_to = 0xffff; + + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) + goto failed; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, dst); + addr.l2_psm = htobs(psm); + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, FALSE); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (!(errno == EAGAIN || errno == EINPROGRESS)) { + g_io_channel_unref(io); + goto failed; + } + + g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) cb, data); + } else { + cb(io, G_IO_OUT, data); + } + + return 0; + +failed: + err = errno; + close(sk); + errno = err; + + return -1; +} diff --git a/input/device.h b/input/device.h index b156b985..b3316841 100644 --- a/input/device.h +++ b/input/device.h @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ +#define L2CAP_PSM_HIDP_CTRL 0x11 +#define L2CAP_PSM_HIDP_INTR 0x13 int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hidp, const char **ppath); @@ -29,3 +31,5 @@ int input_device_unregister(DBusConnection *conn, const char *path); int input_device_get_bdaddr(DBusConnection *conn, const char *path, bdaddr_t *src, bdaddr_t *dst); +int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, + unsigned short psm, GIOFunc cb, void *data); diff --git a/input/manager.c b/input/manager.c index f74349df..d339c007 100644 --- a/input/manager.c +++ b/input/manager.c @@ -27,7 +27,9 @@ #include #include +#include #include +#include #include #include @@ -62,6 +64,7 @@ struct pending_req { DBusMessage *msg; sdp_record_t *pnp_rec; sdp_record_t *hid_rec; + int ctrl_sock; }; static GSList *device_paths = NULL; /* Input registered paths */ @@ -245,15 +248,151 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } +static gboolean interrupt_connect_cb(GIOChannel *chan, + GIOCondition cond, struct pending_req *pr) +{ + struct hidp_connadd_req hidp; + DBusMessage *reply; + const char *path; + int isk, ret, err; + socklen_t len; + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + isk = -1; + goto failed; + } + + if (cond & (G_IO_HUP | G_IO_ERR)) { + err = EINTR; + isk = -1; + error("Hangup or error on HIDP interrupt socket"); + goto failed; + + } + + isk = g_io_channel_unix_get_fd(chan); + + len = sizeof(ret); + if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + + 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, "path registration failed"); + goto cleanup; + } + + device_paths = g_slist_append(device_paths, g_strdup(path)); + + /* Replying to the requestor */ + reply = dbus_message_new_method_return(pr->msg); + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + send_message_and_unref(pr->conn, reply); + + goto cleanup; +failed: + err_connection_failed(pr->conn, pr->msg, strerror(err)); + +cleanup: + if (isk > 0) + close(isk); + + close(pr->ctrl_sock); + pending_req_free(pr); + g_io_channel_unref(chan); + + return FALSE; +} + +static gboolean control_connect_cb(GIOChannel *chan, + GIOCondition cond, struct pending_req *pr) +{ + int ret, csk, err; + socklen_t len; + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + csk = -1; + goto failed; + } + + if (cond & (G_IO_HUP | G_IO_ERR)) { + err = EINTR; + csk = -1; + error("Hangup or error on HIDP control socket"); + goto failed; + + } + + csk = g_io_channel_unix_get_fd(chan); + /* Set HID control channel */ + pr->ctrl_sock = csk; + + len = sizeof(ret); + if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + /* Connect to the HID interrupt channel */ + if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb, pr) < 0) { + + err = errno; + error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + goto failed; + } + + g_io_channel_unref(chan); + return FALSE; + +failed: + if (csk > 0) + close(csk); + + err_connection_failed(pr->conn, pr->msg, strerror(err)); + pending_req_free(pr); + + g_io_channel_unref(chan); + + return FALSE; +} + 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 hidp_connadd_req hidp; DBusError derr; uint8_t *rec_bin; - const char *path; int len, scanned; dbus_error_init(&derr); @@ -289,29 +428,18 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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"); + if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb, pr) < 0) { + int err = errno; + error("L2CAP connect failed:%s (%d)", strerror(err), err); + err_connection_failed(pr->conn, pr->msg, strerror(err)); goto fail; - } - - device_paths = g_slist_append(device_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); + } + dbus_message_unref(reply); + dbus_pending_call_unref(call); + return; fail: dbus_error_free(&derr); pending_req_free(pr); -- cgit From f9398eaf08b49c1e8af5bc87a4b19d862ab5a4de Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 19:36:28 +0000 Subject: input: fixed io channel unref and socket close --- input/device.c | 18 ++++++++---------- input/manager.c | 18 ++++++------------ 2 files changed, 14 insertions(+), 22 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 76049ec4..24540ca1 100644 --- a/input/device.c +++ b/input/device.c @@ -520,6 +520,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, const char *path; socklen_t len; + isk = g_io_channel_unix_get_fd(chan); + if (cond & G_IO_NVAL) { err = EHOSTDOWN; isk = -1; @@ -527,14 +529,12 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EINTR; - isk = -1; + err = EHOSTDOWN; error("Hangup or error on HIDP interrupt socket"); goto failed; } - isk = g_io_channel_unix_get_fd(chan); idev->hidp.intr_sock = isk; idev->hidp.idle_to = 30 * 60; /* 30 minutes */ @@ -601,7 +601,6 @@ cleanup: pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); return FALSE; } @@ -612,6 +611,8 @@ static gboolean control_connect_cb(GIOChannel *chan, int ret, csk, err; socklen_t len; + csk = g_io_channel_unix_get_fd(chan); + if (cond & G_IO_NVAL) { err = EHOSTDOWN; csk = -1; @@ -619,14 +620,11 @@ static gboolean control_connect_cb(GIOChannel *chan, } if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EINTR; - csk = -1; + err = EHOSTDOWN; error("Hangup or error on HIDP control socket"); goto failed; - } - csk = g_io_channel_unix_get_fd(chan); /* Set HID control channel */ idev->hidp.ctrl_sock = csk; @@ -652,7 +650,6 @@ static gboolean control_connect_cb(GIOChannel *chan, goto failed; } - g_io_channel_unref(chan); return FALSE; failed: @@ -664,7 +661,6 @@ failed: idev->pending_connect->msg, strerror(err)); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); return FALSE; } @@ -1143,6 +1139,8 @@ int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, cb(io, G_IO_OUT, data); } + g_io_channel_unref(io); + return 0; failed: diff --git a/input/manager.c b/input/manager.c index d339c007..b7cfc117 100644 --- a/input/manager.c +++ b/input/manager.c @@ -257,6 +257,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, int isk, ret, err; socklen_t len; + isk = g_io_channel_unix_get_fd(chan); + if (cond & G_IO_NVAL) { err = EHOSTDOWN; isk = -1; @@ -264,15 +266,12 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EINTR; - isk = -1; + err = EHOSTDOWN; error("Hangup or error on HIDP interrupt socket"); goto failed; } - isk = g_io_channel_unix_get_fd(chan); - len = sizeof(ret); if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { err = errno; @@ -286,7 +285,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } - memset(&hidp, 0, sizeof(struct hidp_connadd_req)); extract_hid_record(pr->hid_rec, &hidp); if (pr->pnp_rec) @@ -321,7 +319,6 @@ cleanup: close(pr->ctrl_sock); pending_req_free(pr); - g_io_channel_unref(chan); return FALSE; } @@ -332,6 +329,8 @@ static gboolean control_connect_cb(GIOChannel *chan, int ret, csk, err; socklen_t len; + csk = g_io_channel_unix_get_fd(chan); + if (cond & G_IO_NVAL) { err = EHOSTDOWN; csk = -1; @@ -339,14 +338,12 @@ static gboolean control_connect_cb(GIOChannel *chan, } if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EINTR; - csk = -1; + err = EHOSTDOWN; error("Hangup or error on HIDP control socket"); goto failed; } - csk = g_io_channel_unix_get_fd(chan); /* Set HID control channel */ pr->ctrl_sock = csk; @@ -372,7 +369,6 @@ static gboolean control_connect_cb(GIOChannel *chan, goto failed; } - g_io_channel_unref(chan); return FALSE; failed: @@ -382,8 +378,6 @@ failed: err_connection_failed(pr->conn, pr->msg, strerror(err)); pending_req_free(pr); - g_io_channel_unref(chan); - return FALSE; } -- cgit From 4136e617c4f8ab7dfc3488708c8ba129910dc597 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 20:39:39 +0000 Subject: input: code cleanup/standard --- input/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 24540ca1..10950785 100644 --- a/input/device.c +++ b/input/device.c @@ -800,10 +800,12 @@ static DBusHandlerResult device_connect(DBusConnection *conn, if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb, idev) < 0) { - error("L2CAP connect failed: %s(%d)", strerror(errno), errno); + int err = errno; + + error("L2CAP connect failed: %s(%d)", strerror(err), err); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - return err_connection_failed(conn, msg, strerror(errno)); + return err_connection_failed(conn, msg, strerror(err)); } return DBUS_HANDLER_RESULT_HANDLED; -- cgit From 5e225e3d197b9a02617153ac570755cc4d13226b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 20:40:45 +0000 Subject: input: dbus_pending_call_unref code standard --- input/manager.c | 9 ++------- input/server.c | 8 +++----- 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index b7cfc117..41bafd20 100644 --- a/input/manager.c +++ b/input/manager.c @@ -143,6 +143,7 @@ static int get_record(struct pending_req *pr, uint32_t handle, } dbus_pending_call_set_notify(pending, cb, pr, NULL); + dbus_pending_call_unref(pending); dbus_message_unref(msg); return 0; @@ -173,6 +174,7 @@ static int get_handles(struct pending_req *pr, const char *uuid, } dbus_pending_call_set_notify(pending, cb, pr, NULL); + dbus_pending_call_unref(pending); dbus_message_unref(msg); return 0; @@ -431,14 +433,12 @@ static void hid_record_reply(DBusPendingCall *call, void *data) } dbus_message_unref(reply); - dbus_pending_call_unref(call); return; 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) @@ -491,7 +491,6 @@ fail: done: dbus_message_unref(reply); - dbus_pending_call_unref(call); } static void pnp_record_reply(DBusPendingCall *call, void *data) @@ -545,7 +544,6 @@ fail: done: dbus_message_unref(reply); - dbus_pending_call_unref(call); } static void pnp_handle_reply(DBusPendingCall *call, void *data) @@ -602,7 +600,6 @@ fail: done: dbus_message_unref(reply); - dbus_pending_call_unref(call); } static void headset_record_reply(DBusPendingCall *call, void *data) @@ -689,7 +686,6 @@ 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) @@ -742,7 +738,6 @@ fail: done: dbus_message_unref(reply); - dbus_pending_call_unref(call); } static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) diff --git a/input/server.c b/input/server.c index d4bf977f..2fb4e68f 100644 --- a/input/server.c +++ b/input/server.c @@ -177,14 +177,11 @@ static void authorization_callback(DBusPendingCall *pcall, void *data) close(session->ctrl_sk); g_free(session); - - goto failed; + } else { + create_device(session); } - create_device(session); -failed: dbus_message_unref(reply); - dbus_pending_call_unref(pcall); } static int authorize_device(struct session_data *session) @@ -214,6 +211,7 @@ static int authorize_device(struct session_data *session) return -EACCES; dbus_pending_call_set_notify(pending, authorization_callback, session, NULL); + dbus_pending_call_unref(pending); dbus_message_unref(msg); return 0; -- cgit From 9cdd7162b4d1c999ad341f10ac5aba4215de4b22 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 18 Apr 2007 14:02:19 +0000 Subject: fake input: fixed GIOChannel unrefs --- input/device.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 10950785..ba827fb9 100644 --- a/input/device.c +++ b/input/device.c @@ -355,12 +355,11 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) return TRUE; failed: - /* FIXME: Missing clean/free fake io channel */ - g_io_channel_close(chan); - g_io_channel_unref(chan); ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); fake->uinput = -1; + g_io_channel_unref(fake->io); + return FALSE; } @@ -374,19 +373,16 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, int ret, err; fake = idev->fake; + fake->rfcomm = g_io_channel_unix_get_fd(chan); - if (cond & G_IO_NVAL) { - g_io_channel_unref(chan); + if (cond & G_IO_NVAL) return FALSE; - } if (cond & (G_IO_ERR | G_IO_HUP)) { err = EIO; goto failed; } - fake->rfcomm = g_io_channel_unix_get_fd(chan); - len = sizeof(ret); if (getsockopt(fake->rfcomm, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { err = errno; @@ -427,7 +423,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); + return FALSE; failed: @@ -435,7 +431,9 @@ failed: idev->pending_connect->msg, strerror(err)); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); + + g_io_channel_close(chan); + return FALSE; } @@ -452,15 +450,6 @@ static int rfcomm_connect(struct device *idev) return -err; } - io = g_io_channel_unix_new(sk); - if (!io) { - err = -EIO; - error("channel_unix_new failed in rfcomm connect"); - goto failed; - } - - g_io_channel_set_close_on_unref(io, FALSE); - memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, &idev->src); @@ -482,12 +471,17 @@ static int rfcomm_connect(struct device *idev) addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, &idev->dst); addr.rc_channel = idev->fake->ch; + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, FALSE); + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { char peer[18]; /* FIXME: debug purpose */ if (!(errno == EAGAIN || errno == EINPROGRESS)) { err = errno; error("connect() failed: %s (%d)", strerror(err), err); + g_io_channel_unref(io); goto failed; } @@ -500,12 +494,11 @@ static int rfcomm_connect(struct device *idev) rfcomm_connect_cb(io, G_IO_OUT, idev); } + g_io_channel_unref(io); + return 0; failed: - if (io) - g_io_channel_unref(io); - close(sk); errno = err; -- cgit From c506053c991016d372948a912201fdc8b03d175f Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 18 Apr 2007 19:33:34 +0000 Subject: input: fixed seg fault when RemoveDevice is called and there is a pending connection request --- input/device.c | 39 ++++++++++++++++++++++----------------- input/manager.c | 12 +++++++----- 2 files changed, 29 insertions(+), 22 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index ba827fb9..cd8662db 100644 --- a/input/device.c +++ b/input/device.c @@ -667,11 +667,13 @@ static int disconnect(struct device *idev, uint32_t flags) /* Fake input disconnect */ if (fake) { - if (fake->io) { - g_io_channel_close(fake->io); - g_io_channel_unref(fake->io); - fake->io = NULL; - } + if (!fake->io) + return -ENOTCONN; + + g_io_channel_close(fake->io); + g_io_channel_unref(fake->io); + fake->io = NULL; + if (fake->uinput >= 0) { ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); @@ -974,16 +976,17 @@ static const DBusObjectPathVTable device_table = { static int register_path(DBusConnection *conn, const char *path, struct device *idev) { DBusMessage *msg; + if (!dbus_connection_register_object_path(conn, path, &device_table, idev)) { error("Input device path registration failed"); - return -1; + return -EINVAL; } msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); if (!msg) - return -1; + return -ENOMEM; dbus_message_append_args(msg, DBUS_TYPE_STRING, &path, @@ -1001,6 +1004,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, { struct device *idev; const char *path; + int err; idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); @@ -1008,13 +1012,12 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, /* rd_data must not be deallocated since the memory address is copied */ memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); - if (register_path(conn, path, idev) < 0) - return -1; + err = register_path(conn, path, idev); if (*ppath) *ppath = path; - return 0; + return err; } int fake_input_register(DBusConnection *conn, bdaddr_t *src, @@ -1044,20 +1047,22 @@ int input_device_unregister(DBusConnection *conn, const char *path) struct device *idev; if (!dbus_connection_get_object_path_data(conn, - path, (void *) &idev)) - return -1; + path, (void *) &idev) || !idev) + return -EINVAL; + + if (idev->pending_connect) { + /* Pending connection running */ + return -EBUSY; + } del_stored_device_info(&idev->src, &idev->dst); - if (!dbus_connection_unregister_object_path(conn, path)) { - error("Input device path unregister failed"); - return -1; - } + dbus_connection_unregister_object_path(conn, path); msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved"); if (!msg) - return -1; + return -ENOMEM; dbus_message_append_args(msg, DBUS_TYPE_STRING, &path, diff --git a/input/manager.c b/input/manager.c index 41bafd20..f9c273fe 100644 --- a/input/manager.c +++ b/input/manager.c @@ -827,6 +827,7 @@ static DBusHandlerResult remove_device(DBusConnection *conn, DBusError derr; GSList *l; const char *path; + int err; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -845,14 +846,15 @@ static DBusHandlerResult remove_device(DBusConnection *conn, if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; - g_free(l->data); - device_paths = g_slist_remove(device_paths, l->data); - - if (input_device_unregister(conn, path) < 0) { + err = input_device_unregister(conn, path); + if (err < 0) { dbus_message_unref(reply); - return err_failed(conn, msg, "D-Bus path unregistration failed"); + return err_failed(conn, msg, strerror(-err)); } + g_free(l->data); + device_paths = g_slist_remove(device_paths, l->data); + return send_message_and_unref(conn, reply); } -- cgit From 319cc14e14afcce95aa9299fd3b357d8d4e596cd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 May 2007 09:55:29 +0000 Subject: Input Service support for phones --- input/device.c | 3 +++ input/manager.c | 1 + 2 files changed, 4 insertions(+) (limited to 'input') diff --git a/input/device.c b/input/device.c index cd8662db..edf8c475 100644 --- a/input/device.c +++ b/input/device.c @@ -195,6 +195,9 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static int next_id = 0; switch (major) { + case 0x02: /* Phone */ + strcpy(subpath, "phone"); + break; case 0x04: /* Audio */ switch (minor) { /* FIXME: Testing required */ diff --git a/input/manager.c b/input/manager.c index f9c273fe..de4ad0e3 100644 --- a/input/manager.c +++ b/input/manager.c @@ -800,6 +800,7 @@ static DBusHandlerResult create_device(DBusConnection *conn, switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ + case 0x0200: /* Phone */ if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); return err_not_supported(conn, msg); -- cgit From 8287b254023916e0fbe278895661aa22b789edba Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 8 May 2007 16:40:33 +0000 Subject: Add quirk for the PS3 controller --- input/server.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'input') diff --git a/input/server.c b/input/server.c index 2fb4e68f..9596178f 100644 --- a/input/server.c +++ b/input/server.c @@ -117,6 +117,11 @@ static void create_device(struct session_data *session) info("New input device %s (%s)", addr, req.name); + if (req.vendor == 0x054c && req.product == 0x0268) { + unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; + err = write(session->ctrl_sk, buf, sizeof(buf)); + } + err = ioctl(ctl, HIDPCONNADD, &req); close(ctl); -- cgit From 011badf1a19bb52052a0c5d3c7b77ce454a4ca25 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 9 May 2007 07:09:58 +0000 Subject: Add test script for input service --- input/Makefile.am | 2 +- input/test-input | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100755 input/test-input (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 576580f9..339a166d 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -22,6 +22,6 @@ AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ INCLUDES = -I$(top_srcdir)/common -EXTRA_DIST = input.service input-api.txt +EXTRA_DIST = input.service input-api.txt test-input MAINTAINERCLEANFILES = Makefile.in diff --git a/input/test-input b/input/test-input new file mode 100755 index 00000000..689e4723 --- /dev/null +++ b/input/test-input @@ -0,0 +1,22 @@ +#!/usr/bin/python + +import sys +import dbus + +bus = dbus.SystemBus() + +manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), + 'org.bluez.Manager') + +conn = manager.ActivateService('input') + +input = dbus.Interface(bus.get_object(conn, '/org/bluez/input'), + 'org.bluez.input.Manager') + +if (len(sys.argv) < 1): + print "Usage: %s
" % (sys.argv[0]) + sys.exit(1) + +address = sys.argv[1] + +device = input.CreateDevice(address) -- cgit From e4d113429614e120642e00e3a0a67c0ef62778ce Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 May 2007 10:05:28 +0000 Subject: Add support for FinishRemoteServiceTransaction --- input/manager.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index de4ad0e3..230740e2 100644 --- a/input/manager.c +++ b/input/manager.c @@ -383,6 +383,41 @@ failed: return FALSE; } +static void finish_sdp_transaction(bdaddr_t *dba) +{ + char address[18], *addr_ptr = address; + DBusMessage *msg, *reply; + DBusError derr; + + ba2str(dba, address); + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0", + "org.bluez.Adapter", + "FinishRemoteServiceTransaction"); + if (!msg) { + error("Unable to allocate new method call"); + return; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID); + + dbus_error_init(&derr); + reply = dbus_connection_send_with_reply_and_block(connection, msg, + -1, &derr); + + dbus_message_unref(msg); + + if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) { + error("FinishRemoteServiceTransaction(%s) failed: %s", + address, derr.message); + dbus_error_free(&derr); + return; + } + + dbus_message_unref(reply); +} + static void hid_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); @@ -404,6 +439,8 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } + finish_sdp_transaction(&pr->dst); + if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { -- cgit From 74416c5f12cc79cd0769220fa68b0f1bcaeb279e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 May 2007 14:53:34 +0000 Subject: Convert to using generic dbus message dispatching --- input/device.c | 76 +++++++++++++++++++++++---------------------------------- input/manager.c | 72 +++++++++++++++++++++++------------------------------- 2 files changed, 61 insertions(+), 87 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index edf8c475..4a76b786 100644 --- a/input/device.c +++ b/input/device.c @@ -43,6 +43,7 @@ #include #include "dbus.h" +#include "dbus-helper.h" #include "logging.h" #include "textfile.h" #include "uinput.h" @@ -922,42 +923,6 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, return send_message_and_unref(conn, reply); } -static DBusHandlerResult device_message(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *iface, *member; - - iface = dbus_message_get_interface(msg); - member = dbus_message_get_member(msg); - - /* Accept messages from the input interface only */ - if (strcmp(INPUT_DEVICE_INTERFACE, iface)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (strcmp(member, "Connect") == 0) - return device_connect(conn, msg, data); - - if (strcmp(member, "Disconnect") == 0) - return device_disconnect(conn, msg, data); - - if (strcmp(member, "IsConnected") == 0) - return device_is_connected(conn, msg, data); - - if (strcmp(member, "GetAddress") == 0) - return device_get_address(conn, msg, data); - - if (strcmp(member, "GetName") == 0) - return device_get_name(conn, msg, data); - - if (strcmp(member, "GetProductId") == 0) - return device_get_product_id(conn, msg, data); - - if (strcmp(member, "GetVendorId") == 0) - return device_get_vendor_id(conn, msg, data); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - static void device_unregister(DBusConnection *conn, void *data) { struct device *idev = data; @@ -967,10 +932,21 @@ static void device_unregister(DBusConnection *conn, void *data) device_free(idev); } -/* Virtual table to handle device object path hierarchy */ -static const DBusObjectPathVTable device_table = { - .message_function = device_message, - .unregister_function = device_unregister, +static DBusMethodVTable device_methods[] = { + { "Connect", device_connect, "", "" }, + { "Disconnect", device_disconnect, "", "" }, + { "IsConnected", device_is_connected, "", "b" }, + { "GetAddress", device_get_address, "", "s" }, + { "GetName", device_get_name, "", "s" }, + { "GetProductId", device_get_product_id, "", "q" }, + { "GetVendorId", device_get_vendor_id, "", "q" }, + { NULL, NULL, NULL, NULL } +}; + +static DBusSignalVTable device_signals[] = { + { "Connected", "" }, + { "Disconnected", "" }, + { NULL, NULL } }; /* @@ -980,12 +956,22 @@ static int register_path(DBusConnection *conn, const char *path, struct device * { DBusMessage *msg; - if (!dbus_connection_register_object_path(conn, path, - &device_table, idev)) { + if (!dbus_connection_create_object_path(conn, path, + NULL, device_unregister)) { error("Input device path registration failed"); return -EINVAL; } + if (!dbus_connection_register_interface(conn, path, + INPUT_DEVICE_INTERFACE, + device_methods, + device_signals, NULL)) { + error("Failed to register %s interface to %s", + INPUT_DEVICE_INTERFACE, path); + dbus_connection_destroy_object_path(conn, path); + return -1; + } + msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); if (!msg) @@ -1049,7 +1035,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) DBusMessage *msg; struct device *idev; - if (!dbus_connection_get_object_path_data(conn, + if (!dbus_connection_get_object_user_data(conn, path, (void *) &idev) || !idev) return -EINVAL; @@ -1060,7 +1046,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) del_stored_device_info(&idev->src, &idev->dst); - dbus_connection_unregister_object_path(conn, path); + dbus_connection_destroy_object_path(conn, path); msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved"); @@ -1081,7 +1067,7 @@ int input_device_get_bdaddr(DBusConnection *conn, const char *path, { struct device *idev; - if (!dbus_connection_get_object_path_data(conn, path, + if (!dbus_connection_get_object_user_data(conn, path, (void *) &idev)) return -1; diff --git a/input/manager.c b/input/manager.c index 230740e2..bd87c5fb 100644 --- a/input/manager.c +++ b/input/manager.c @@ -43,6 +43,7 @@ #include #include "dbus.h" +#include "dbus-helper.h" #include "logging.h" #include "textfile.h" @@ -922,35 +923,6 @@ static DBusHandlerResult list_devices(DBusConnection *conn, 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 list_devices(conn, msg, data); - - if (strcmp(member, "CreateDevice") == 0) - return create_device(conn, msg, data); - - if (strcmp(member, "RemoveDevice") == 0) - return remove_device(conn, msg, data); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - static void manager_unregister(DBusConnection *conn, void *data) { info("Unregistered manager path"); @@ -960,12 +932,6 @@ static void manager_unregister(DBusConnection *conn, void *data) g_slist_free(device_paths); } -/* 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 */ @@ -1022,19 +988,41 @@ static void register_stored_inputs(void) closedir(dir); } +static DBusMethodVTable manager_methods[] = { + { "ListDevices", list_devices, "", "as" }, + { "CreateDevice", create_device, "s", "s" }, + { "RemoveDevice", remove_device, "s", "" }, + { NULL, NULL, NULL, NULL }, +}; + +static DBusSignalVTable manager_signals[] = { + { "DeviceCreated", "s" }, + { "DeviceRemoved", "s" }, + { NULL, NULL } +}; + int input_init(DBusConnection *conn) { - connection = dbus_connection_ref(conn); - - dbus_connection_set_exit_on_disconnect(connection, TRUE); + dbus_connection_set_exit_on_disconnect(conn, TRUE); - /* Fallback to catch invalid device path */ - if (!dbus_connection_register_fallback(connection, INPUT_PATH, - &manager_table, NULL)) { + if (!dbus_connection_create_object_path(conn, INPUT_PATH, + NULL, manager_unregister)) { error("D-Bus failed to register %s path", INPUT_PATH); return -1; } + if (!dbus_connection_register_interface(conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, + manager_methods, + manager_signals, NULL)) { + error("Failed to register %s interface to %s", + INPUT_MANAGER_INTERFACE, INPUT_PATH); + dbus_connection_destroy_object_path(connection, INPUT_PATH); + return -1; + } + + connection = dbus_connection_ref(conn); + info("Registered input manager path:%s", INPUT_PATH); /* Register well known HID devices */ @@ -1047,7 +1035,7 @@ int input_init(DBusConnection *conn) void input_exit(void) { - dbus_connection_unregister_object_path(connection, INPUT_PATH); + dbus_connection_destroy_object_path(connection, INPUT_PATH); server_stop(); -- cgit From ea478e3120a4a2d777c5b828e96fde0e44fc897a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 May 2007 15:28:08 +0000 Subject: Fix device registration --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 4a76b786..7067133e 100644 --- a/input/device.c +++ b/input/device.c @@ -957,7 +957,7 @@ static int register_path(DBusConnection *conn, const char *path, struct device * DBusMessage *msg; if (!dbus_connection_create_object_path(conn, path, - NULL, device_unregister)) { + idev, device_unregister)) { error("Input device path registration failed"); return -EINVAL; } -- cgit From e8db465169591d3f77056294699c30113fe5206a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 9 May 2007 19:48:39 +0000 Subject: input: small code cleanup --- input/device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 7067133e..75c64621 100644 --- a/input/device.c +++ b/input/device.c @@ -1003,7 +1003,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, err = register_path(conn, path, idev); - if (*ppath) + if (!err && *ppath) *ppath = path; return err; @@ -1014,6 +1014,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, { struct device *idev; const char *path; + int err; idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); @@ -1021,13 +1022,12 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; - if (register_path(conn, path, idev) < 0) - return -1; + err = register_path(conn, path, idev); - if (*ppath) + if (!err && *ppath) *ppath = path; - return 0; + return err; } int input_device_unregister(DBusConnection *conn, const char *path) -- cgit From f0fe2c5ffb3741f4e6fdbe2d7aee01e66b2af4dd Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 9 May 2007 20:05:06 +0000 Subject: input: Use dbus_connection_emit_signal --- input/device.c | 51 ++++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 75c64621..d1c08190 100644 --- a/input/device.c +++ b/input/device.c @@ -371,7 +371,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { struct fake_input *fake; - DBusMessage *reply, *signal; + DBusMessage *reply; const char *path; socklen_t len; int ret, err; @@ -421,9 +421,9 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect->msg); - signal = dbus_message_new_signal(path, - INPUT_DEVICE_INTERFACE, "Connected"); - send_message_and_unref(idev->pending_connect->conn, signal); + dbus_connection_emit_signal(idev->pending_connect->conn, path, + INPUT_DEVICE_INTERFACE, "Connected", + DBUS_TYPE_INVALID); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -513,7 +513,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { int ctl, isk, ret, err; - DBusMessage *signal; const char *path; socklen_t len; @@ -577,9 +576,9 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect->msg); - signal = dbus_message_new_signal(path, - INPUT_DEVICE_INTERFACE, "Connected"); - send_message_and_unref(idev->pending_connect->conn, signal); + dbus_connection_emit_signal(idev->pending_connect->conn, path, + INPUT_DEVICE_INTERFACE, "Connected" , + DBUS_TYPE_INVALID); close (ctl); goto cleanup; @@ -814,7 +813,6 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *signal; const char *path; if (disconnect(idev, 0) < 0) @@ -826,9 +824,11 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, /* Sending the Disconnect signal */ path = dbus_message_get_path(msg); - signal = dbus_message_new_signal(path, - INPUT_DEVICE_INTERFACE, "Disconnected"); - return send_message_and_unref(conn, signal); + dbus_connection_emit_signal(conn, path, + INPUT_DEVICE_INTERFACE, "Disconnected", + DBUS_TYPE_INVALID); + + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult device_is_connected(DBusConnection *conn, @@ -954,8 +954,6 @@ static DBusSignalVTable device_signals[] = { */ static int register_path(DBusConnection *conn, const char *path, struct device *idev) { - DBusMessage *msg; - if (!dbus_connection_create_object_path(conn, path, idev, device_unregister)) { error("Input device path registration failed"); @@ -972,16 +970,10 @@ static int register_path(DBusConnection *conn, const char *path, struct device * return -1; } - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceCreated"); - if (!msg) - return -ENOMEM; - - dbus_message_append_args(msg, + dbus_connection_emit_signal(conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(conn, msg); + DBUS_TYPE_INVALID); info("Created input device: %s", path); @@ -1032,7 +1024,6 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, int input_device_unregister(DBusConnection *conn, const char *path) { - DBusMessage *msg; struct device *idev; if (!dbus_connection_get_object_user_data(conn, @@ -1048,16 +1039,10 @@ int input_device_unregister(DBusConnection *conn, const char *path) dbus_connection_destroy_object_path(conn, path); - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceRemoved"); - if (!msg) - return -ENOMEM; - - dbus_message_append_args(msg, + dbus_connection_emit_signal(conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(conn, msg); + DBUS_TYPE_INVALID); return 0; } -- cgit From 60709fc61959f4ead3e305a0de2cd2419c41e8b4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 May 2007 08:43:37 +0000 Subject: Fix unitialized memory access --- input/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index d1c08190..b79bbc45 100644 --- a/input/device.c +++ b/input/device.c @@ -995,7 +995,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, err = register_path(conn, path, idev); - if (!err && *ppath) + if (!err && ppath) *ppath = path; return err; @@ -1016,7 +1016,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, err = register_path(conn, path, idev); - if (!err && *ppath) + if (!err && ppath) *ppath = path; return err; -- cgit From 07958fc3612225ceeffcbbcbae320a2bedcd774d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 10 May 2007 08:45:28 +0000 Subject: Update API descriptions --- input/input-api.txt | 2 -- 1 file changed, 2 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index a4425914..60066eb9 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -86,5 +86,3 @@ Methods string GetAddress() Signals void Connected() void Disconnected() - - -- cgit From cc7ee42ddf28a602f3160fa024da36104eb925d1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 10 May 2007 13:57:15 +0000 Subject: input: skip auth/encrypt if the link is not available and allow connections --- input/device.c | 2 +- input/server.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index b79bbc45..d9f95c4e 100644 --- a/input/device.c +++ b/input/device.c @@ -557,7 +557,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (idev->hidp.subclass & 0x40) { int ret; ret = encrypt_link(&idev->src, &idev->dst); - if (ret < 0) { + if (ret < 0 && ret != -ENOKEY) { err = -ret; close(ctl); goto failed; diff --git a/input/server.c b/input/server.c index 9596178f..2a9e08d4 100644 --- a/input/server.c +++ b/input/server.c @@ -108,7 +108,8 @@ static void create_device(struct session_data *session) } if (req.subclass & 0x40) { - if (encrypt_link(&session->src, &session->dst) < 0) { + err = encrypt_link(&session->src, &session->dst); + if (err < 0 && err != -ENOKEY) { if (req.rd_data) free(req.rd_data); goto cleanup; -- cgit From 772f25e26e1d1c5982855eefd59b51c7e4aaab95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 May 2007 12:22:52 +0000 Subject: Add GetAdapter() method to retrieve the source address --- input/device.c | 22 ++++++++++++++++++++++ input/input-api.txt | 30 +++++++++++++++++------------- 2 files changed, 39 insertions(+), 13 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index d9f95c4e..d85aae55 100644 --- a/input/device.c +++ b/input/device.c @@ -850,6 +850,27 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, return send_message_and_unref(conn, reply); } +static DBusHandlerResult device_get_adapter(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct device *idev = data; + DBusMessage *reply; + char addr[18]; + const char *paddr = addr; + + ba2str(&idev->src, addr); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -936,6 +957,7 @@ static DBusMethodVTable device_methods[] = { { "Connect", device_connect, "", "" }, { "Disconnect", device_disconnect, "", "" }, { "IsConnected", device_is_connected, "", "b" }, + { "GetAdapter", device_get_adapter, "", "s" }, { "GetAddress", device_get_address, "", "s" }, { "GetName", device_get_name, "", "s" }, { "GetProductId", device_get_product_id, "", "q" }, diff --git a/input/input-api.txt b/input/input-api.txt index 60066eb9..13da80ba 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -7,7 +7,6 @@ Copyright (C) 2006-2007 Marcel Holtmann Input Manager hierarchy ======================= -Service org.bluez.input Interface org.bluez.input.Manager Object path /org/bluez/input @@ -24,14 +23,14 @@ Methods array{string} ListDevices() On success it will return the path of the newly created device object. - Possible errors:org.bluez.input.AlreadyExists - org.bluez.input.NotSupported - org.bluez.input.ConnectionAttemptFailed - org.bluez.input.Failed + Possible errors: org.bluez.input.AlreadyExists + org.bluez.input.NotSupported + org.bluez.input.ConnectionAttemptFailed + org.bluez.input.Failed void RemoveDevice(string path) - Remove the input device object for a given path. + Remove the input device object for a given path. Possible errors:org.bluez.input.DoesNotExist org.bluez.input.Failed @@ -44,11 +43,16 @@ Signals void DeviceCreated(string path) Input Device hierarchy ====================== -Service org.bluez.input Interface org.bluez.input.Device Object path /org/bluez/input/{keyboard*|mouse*|...} -Methods string GetAddress() +Methods string GetAdapter() + + Returns the adapter address. + + Example: "00:11:22:33:44:55" + + string GetAddress() Returns the device address. @@ -71,18 +75,18 @@ Methods string GetAddress() Returns the connection status. void Connect() - + Connect to the input device. - Possible errors:org.bluez.input.AlreadyConnected - org.bluez.input.ConnectionAttemptFailed + Possible errors: org.bluez.input.AlreadyConnected + org.bluez.input.ConnectionAttemptFailed void Disconnect() Disconnect from the input device. - Possible errors:org.bluez.input.Failed + Possible errors: org.bluez.input.Failed -Signals void Connected() +Signals void Connected() void Disconnected() -- cgit From 6de268e32d69d08a9cf50c41f4a3ee67ade3ec99 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 29 May 2007 03:58:10 +0000 Subject: Don't set MTU value to 48 --- input/device.c | 12 +++++++----- input/device.h | 9 +++++---- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index d85aae55..1310b7fb 100644 --- a/input/device.c +++ b/input/device.c @@ -797,7 +797,6 @@ static DBusHandlerResult device_connect(DBusConnection *conn, /* HID devices */ if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb, idev) < 0) { - int err = errno; error("L2CAP connect failed: %s(%d)", strerror(err), err); @@ -1087,14 +1086,16 @@ int input_device_get_bdaddr(DBusConnection *conn, const char *path, return 0; } -int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data) +int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, + GIOFunc cb, void *data) { GIOChannel *io; struct sockaddr_l2 addr; struct l2cap_options opts; int sk, err; - if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (sk < 0) return -1; memset(&addr, 0, sizeof(addr)); @@ -1108,12 +1109,14 @@ int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, goto failed; memset(&opts, 0, sizeof(opts)); +#if 0 opts.imtu = HIDP_DEFAULT_MTU; opts.omtu = HIDP_DEFAULT_MTU; opts.flush_to = 0xffff; if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) goto failed; +#endif memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; @@ -1131,9 +1134,8 @@ int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) cb, data); - } else { + } else cb(io, G_IO_OUT, data); - } g_io_channel_unref(io); diff --git a/input/device.h b/input/device.h index b3316841..5501d3b9 100644 --- a/input/device.h +++ b/input/device.h @@ -20,11 +20,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ -#define L2CAP_PSM_HIDP_CTRL 0x11 -#define L2CAP_PSM_HIDP_INTR 0x13 + +#define L2CAP_PSM_HIDP_CTRL 0x11 +#define L2CAP_PSM_HIDP_INTR 0x13 int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, - struct hidp_connadd_req *hidp, const char **ppath); + struct hidp_connadd_req *hidp, const char **ppath); int fake_input_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, uint8_t ch, const char **ppath); int input_device_unregister(DBusConnection *conn, const char *path); @@ -32,4 +33,4 @@ int input_device_unregister(DBusConnection *conn, const char *path); int input_device_get_bdaddr(DBusConnection *conn, const char *path, bdaddr_t *src, bdaddr_t *dst); int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, - unsigned short psm, GIOFunc cb, void *data); + unsigned short psm, GIOFunc cb, void *data); -- cgit From 0bf3861da5ad7f4f2310029e2b42ae964a9e3aa5 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 21 Jun 2007 22:06:33 +0000 Subject: input: removed session_data structure and added watch for Disconnect signal --- input/device.c | 295 ++++++++++++++++++++++++++++++++++++++++++-------------- input/device.h | 7 ++ input/manager.c | 5 +- input/server.c | 200 +++++++------------------------------- 4 files changed, 271 insertions(+), 236 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 1310b7fb..d3f07cf5 100644 --- a/input/device.c +++ b/input/device.c @@ -77,11 +77,18 @@ struct device { char *name; uint8_t major; uint8_t minor; - struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + uint16_t product; + uint16_t vendor; struct fake_input *fake; - struct pending_connect *pending_connect; + struct pending_connect *pending_connect; /* FIXME: use only the msg */ + DBusConnection *conn; + char *path; + int ctrl_sk; + int intr_sk; }; +GSList *devices = NULL; + static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; @@ -95,11 +102,10 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) read_device_name(src, dst, &idev->name); read_device_class(src, dst, &cls); - idev->major = (cls >> 8) & 0x1f; - idev->minor = (cls >> 2) & 0x3f; - - /* FIXME: hidp could be alloc dynamically */ - snprintf(idev->hidp.name, 128, "%s", idev->name); + idev->major = (cls >> 8) & 0x1f; + idev->minor = (cls >> 2) & 0x3f; + idev->ctrl_sk = -1; + idev->intr_sk = -1; return idev; } @@ -121,12 +127,13 @@ static void device_free(struct device *idev) return; if (idev->name) g_free(idev->name); - if (idev->hidp.rd_data) - g_free(idev->hidp.rd_data); if (idev->fake) g_free(idev->fake); - if (idev->pending_connect) + if (idev->pending_connect) pending_connect_free(idev->pending_connect); + if (idev->path) + g_free(idev->path); + dbus_connection_unref(idev->conn); g_free(idev); } @@ -509,11 +516,95 @@ failed: return -err; } +static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct device *idev = data; + gboolean ret = TRUE; + + if (cond & G_IO_NVAL) + ret = FALSE; + + if (cond & (G_IO_HUP | G_IO_ERR)) { + g_io_channel_close(chan); + ret = FALSE; + } + + if (ret == FALSE) + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + + return ret; +} + +static void create_watch(int sk, struct device *idev) +{ + GIOChannel *io; + + io = g_io_channel_unix_new(sk); + g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + connection_event, idev); + g_io_channel_unref(io); +} + +static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name) +{ + struct hidp_connadd_req req; + char addr[18]; + int ctl, err, timeout = 30; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP interface"); + return -errno; + } + + ba2str(dst, addr); + + memset(&req, 0, sizeof(req)); + req.ctrl_sock = ctrl_sk; + req.intr_sock = intr_sk; + req.flags = 0; + req.idle_to = timeout * 60; + + err = get_stored_device_info(src, dst, &req); + if (err < 0) { + error("Rejected connection from unknown device %s", addr); + goto cleanup; + } + + if (req.subclass & 0x40) { + err = encrypt_link(src, dst); + if (err < 0 && err != -ENOKEY) + goto cleanup; + } + + if (name) + strncpy(req.name, name, 128); + + info("New input device %s (%s)", addr, req.name); + + if (req.vendor == 0x054c && req.product == 0x0268) { + unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; + err = write(ctrl_sk, buf, sizeof(buf)); + } + + err = ioctl(ctl, HIDPCONNADD, &req); +cleanup: + close(ctl); + + if (req.rd_data) + free(req.rd_data); + + return err; +} + static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { - int ctl, isk, ret, err; - const char *path; + int isk, ret, err; socklen_t len; isk = g_io_channel_unix_get_fd(chan); @@ -531,9 +622,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } - idev->hidp.intr_sock = isk; - idev->hidp.idle_to = 30 * 60; /* 30 minutes */ - len = sizeof(ret); if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { err = errno; @@ -547,54 +635,33 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - err = errno; - error("Can't open HIDP control socket"); + idev->intr_sk = isk; + err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); + if (err < 0) goto failed; - } - - if (idev->hidp.subclass & 0x40) { - int ret; - ret = encrypt_link(&idev->src, &idev->dst); - if (ret < 0 && ret != -ENOKEY) { - err = -ret; - close(ctl); - goto failed; - } - } - if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { - err = errno; - close(ctl); - goto failed; - } + create_watch(idev->ctrl_sk, idev); + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Connected", + DBUS_TYPE_INVALID); /* Replying to the requestor */ send_message_and_unref(idev->pending_connect->conn, dbus_message_new_method_return(idev->pending_connect->msg)); - /* Sending the Connected signal */ - path = dbus_message_get_path(idev->pending_connect->msg); - dbus_connection_emit_signal(idev->pending_connect->conn, path, - INPUT_DEVICE_INTERFACE, "Connected" , - DBUS_TYPE_INVALID); - - close (ctl); goto cleanup; failed: err_connection_failed(idev->pending_connect->conn, idev->pending_connect->msg, strerror(err)); - -cleanup: if (isk > 0) close(isk); + close(idev->ctrl_sk); + idev->intr_sk = -1; + idev->ctrl_sk = -1; - close(idev->hidp.ctrl_sock); - - idev->hidp.intr_sock = -1; - idev->hidp.ctrl_sock = -1; - +cleanup: pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -622,7 +689,7 @@ static gboolean control_connect_cb(GIOChannel *chan, } /* Set HID control channel */ - idev->hidp.ctrl_sock = csk; + idev->ctrl_sk = csk; len = sizeof(ret); if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { @@ -652,7 +719,7 @@ failed: if (csk > 0) close(csk); - idev->hidp.ctrl_sock = -1; + idev->ctrl_sk = -1; err_connection_failed(idev->pending_connect->conn, idev->pending_connect->msg, strerror(err)); pending_connect_free(idev->pending_connect); @@ -687,6 +754,14 @@ static int disconnect(struct device *idev, uint32_t flags) } /* Standard HID disconnect */ + if (idev->ctrl_sk >= 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; + } + if (idev->intr_sk >= 0) { + close(idev->intr_sk); + idev->intr_sk = -1; + } ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { @@ -719,8 +794,8 @@ fail: close(ctl); errno = err; - idev->hidp.intr_sock = -1; - idev->hidp.ctrl_sock = -1; + idev->intr_sk = -1; + idev->ctrl_sk = -1; return -err; } @@ -812,22 +887,13 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - const char *path; if (disconnect(idev, 0) < 0) return err_failed(conn, msg, strerror(errno)); /* Replying to the requestor */ - send_message_and_unref(conn, + return send_message_and_unref(conn, dbus_message_new_method_return(msg)); - - /* Sending the Disconnect signal */ - path = dbus_message_get_path(msg); - dbus_connection_emit_signal(conn, path, - INPUT_DEVICE_INTERFACE, "Disconnected", - DBUS_TYPE_INVALID); - - return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult device_is_connected(DBusConnection *conn, @@ -896,7 +962,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, { struct device *idev = data; DBusMessage *reply; - const char *pname = idev->hidp.name; + const char *pname = idev->name; reply = dbus_message_new_method_return(msg); if (!reply) @@ -920,7 +986,7 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->hidp.product, + DBUS_TYPE_UINT16, &idev->product, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply); @@ -937,7 +1003,7 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->hidp.vendor, + DBUS_TYPE_UINT16, &idev->vendor, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply); @@ -994,7 +1060,9 @@ static int register_path(DBusConnection *conn, const char *path, struct device * dbus_connection_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID); + + devices = g_slist_append(devices, idev); info("Created input device: %s", path); @@ -1010,9 +1078,10 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); - - /* rd_data must not be deallocated since the memory address is copied */ - memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); + idev->path = g_strdup(path); + idev->product = hid->product; + idev->vendor = hid->vendor; + idev->conn = dbus_connection_ref(conn); err = register_path(conn, path, idev); @@ -1031,6 +1100,10 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); + idev->path = g_strdup(path); + idev->conn = dbus_connection_ref(conn); + + /* FIXME: Missing set product and vendor */ idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; @@ -1058,6 +1131,8 @@ int input_device_unregister(DBusConnection *conn, const char *path) del_stored_device_info(&idev->src, &idev->dst); + devices = g_slist_remove(devices, idev); + dbus_connection_destroy_object_path(conn, path); dbus_connection_emit_signal(conn, INPUT_PATH, @@ -1148,3 +1223,83 @@ failed: return -1; } + +static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev; + GSList *list; + + for (list = devices; list != NULL; list = list->next) { + idev = list->data; + + if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) + return idev; + } + + return NULL; +} + +int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) +{ + struct device *idev = find_device(src, dst); + if (!idev) + return -ENOENT; + + switch (psm) { + case L2CAP_PSM_HIDP_CTRL: + idev->ctrl_sk = nsk; + break; + case L2CAP_PSM_HIDP_INTR: + idev->intr_sk = nsk; + break; + } + + return 0; +} + +int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev = find_device(src, dst); + if (!idev) + return -ENOENT; + + if (idev->ctrl_sk >= 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; + } + + if (idev->intr_sk >= 0) { + close(idev->intr_sk); + idev->intr_sk = -1; + } + + return 0; +} + +int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev; + int err; + + idev = find_device(src, dst); + if (!idev) + return -ENOENT; + + err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); + if (err < 0) { + close(idev->ctrl_sk); + close(idev->intr_sk); + idev->ctrl_sk = -1; + idev->intr_sk = -1; + + return err; + } + + create_watch(idev->ctrl_sk, idev); + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Connected", + DBUS_TYPE_INVALID); + return 0; +} diff --git a/input/device.h b/input/device.h index 5501d3b9..fdf7f90f 100644 --- a/input/device.h +++ b/input/device.h @@ -32,5 +32,12 @@ int input_device_unregister(DBusConnection *conn, const char *path); int input_device_get_bdaddr(DBusConnection *conn, const char *path, bdaddr_t *src, bdaddr_t *dst); + +int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk); + +int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst); + +int input_device_connadd(bdaddr_t *src, bdaddr_t *dst); + int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data); diff --git a/input/manager.c b/input/manager.c index bd87c5fb..03c914ee 100644 --- a/input/manager.c +++ b/input/manager.c @@ -954,9 +954,12 @@ static void stored_input(char *key, char *value, void *data) * acceptable since the source is different. */ if (input_device_register(connection, src, &dst, &hidp, &path) < 0) - return; + goto cleanup; device_paths = g_slist_append(device_paths, g_strdup(path)); +cleanup: + if (hidp.rd_data) + g_free(hidp.rd_data); } static void register_stored_inputs(void) diff --git a/input/server.c b/input/server.c index 2a9e08d4..0f04b06a 100644 --- a/input/server.c +++ b/input/server.c @@ -42,103 +42,12 @@ #include "logging.h" #include "dbus.h" +#include "device.h" #include "server.h" #include "storage.h" -struct session_data { - bdaddr_t src; - bdaddr_t dst; - int ctrl_sk; - int intr_sk; -}; - -static GSList *sessions = NULL; static DBusConnection *connection = NULL; -static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst) -{ - GSList *list; - - for (list = sessions; list != NULL; list = list->next) { - struct session_data *session = list->data; - - if (!bacmp(&session->src, src) && !bacmp(&session->dst, dst)) - return session; - } - - return NULL; -} - -static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - if (cond & G_IO_NVAL) - return FALSE; - - if (cond & (G_IO_HUP | G_IO_ERR)) { - g_io_channel_close(chan); - return FALSE; - } - - return TRUE; -} - -static void create_device(struct session_data *session) -{ - struct hidp_connadd_req req; - char addr[18]; - int ctl, err, timeout = 30; - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - error("Can't open HIDP interface"); - goto cleanup; - } - - ba2str(&session->dst, addr); - - memset(&req, 0, sizeof(req)); - req.ctrl_sock = session->ctrl_sk; - req.intr_sock = session->intr_sk; - req.flags = 0; - req.idle_to = timeout * 60; - - if (get_stored_device_info(&session->src, &session->dst, &req) < 0) { - error("Rejected connection from unknown device %s", addr); - goto cleanup; - } - - if (req.subclass & 0x40) { - err = encrypt_link(&session->src, &session->dst); - if (err < 0 && err != -ENOKEY) { - if (req.rd_data) - free(req.rd_data); - goto cleanup; - } - } - - info("New input device %s (%s)", addr, req.name); - - if (req.vendor == 0x054c && req.product == 0x0268) { - unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; - err = write(session->ctrl_sk, buf, sizeof(buf)); - } - - err = ioctl(ctl, HIDPCONNADD, &req); - - close(ctl); - - if (req.rd_data) - free(req.rd_data); - -cleanup: - sessions = g_slist_remove(sessions, session); - - close(session->intr_sk); - close(session->ctrl_sk); - - g_free(session); -} - static void cancel_authorization(const char *addr) { DBusMessage *msg; @@ -160,38 +69,39 @@ static void cancel_authorization(const char *addr) send_message_and_unref(connection, msg); } +struct authorization_data { + bdaddr_t src; + bdaddr_t dst; +}; + static void authorization_callback(DBusPendingCall *pcall, void *data) { - struct session_data *session = data; + struct authorization_data *auth = data; DBusMessage *reply = dbus_pending_call_steal_reply(pcall); DBusError derr; dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("Access denied: %s", derr.message); - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - char addr[18]; - memset(addr, 0, sizeof(addr)); - ba2str(&session->dst, addr); - cancel_authorization(addr); - } - dbus_error_free(&derr); - - sessions = g_slist_remove(sessions, session); - - close(session->intr_sk); - close(session->ctrl_sk); - - g_free(session); - } else { - create_device(session); + if (dbus_set_error_from_message(&derr, reply) != TRUE) { + dbus_message_unref(reply); + input_device_connadd(&auth->src, &auth->dst); + return; + } + + error("Authorization denied: %s", derr.message); + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { + char addr[18]; + memset(addr, 0, sizeof(addr)); + ba2str(&auth->dst, addr); + cancel_authorization(addr); } + dbus_error_free(&derr); dbus_message_unref(reply); } -static int authorize_device(struct session_data *session) +static int authorize_device(bdaddr_t *src, bdaddr_t *dst) { + struct authorization_data *auth; DBusMessage *msg; DBusPendingCall *pending; char addr[18]; @@ -206,7 +116,7 @@ static int authorize_device(struct session_data *session) } memset(addr, 0, sizeof(addr)); - ba2str(&session->dst, addr); + ba2str(dst, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_STRING, &uuid, @@ -216,28 +126,18 @@ static int authorize_device(struct session_data *session) msg, &pending, -1) == FALSE) return -EACCES; - dbus_pending_call_set_notify(pending, authorization_callback, session, NULL); + auth = g_new0(struct authorization_data, 1); + bacpy(&auth->src, src); + bacpy(&auth->dst, dst); + dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free); dbus_pending_call_unref(pending); dbus_message_unref(msg); return 0; } -static void create_watch(int sk, struct session_data *session) -{ - GIOChannel *io; - - io = g_io_channel_unix_new(sk); - - g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - session_event, session); - - g_io_channel_unref(io); -} - static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) { - struct session_data *session; struct sockaddr_l2 addr; socklen_t addrlen; bdaddr_t src, dst; @@ -268,44 +168,14 @@ static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data debug("Incoming connection on PSM %d", psm); - session = find_session(&src, &dst); - if (session) { - if (psm == 19) { - session->intr_sk = nsk; - if (authorize_device(session) < 0) { - error("Authorization request failed"); - sessions = g_slist_remove(sessions, session); - - close(session->intr_sk); - close(session->ctrl_sk); - - g_free(session); - - return TRUE; - } - debug("Waiting authorization ..."); - } else { - error("Control channel already established"); - close(nsk); - } - } else { - if (psm == 17) { - session = g_new0(struct session_data, 1); - - bacpy(&session->src, &src); - bacpy(&session->dst, &dst); - session->ctrl_sk = nsk; - session->intr_sk = -1; - - sessions = g_slist_append(sessions, session); - - create_watch(nsk, session); - } else { - error("No control channel available"); - close(nsk); - } + if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { + input_device_close_channels(&src, &dst); + return TRUE; } + if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(&src, &dst) < 0)) + input_device_close_channels(&src, &dst); + return TRUE; } @@ -347,14 +217,14 @@ static GIOChannel *intr_io = NULL; int server_start(DBusConnection *conn) { - ctrl_io = setup_l2cap(17); + ctrl_io = setup_l2cap(L2CAP_PSM_HIDP_CTRL); if (!ctrl_io) { error("Failed to listen on control channel"); return -1; } g_io_channel_set_close_on_unref(ctrl_io, TRUE); - intr_io = setup_l2cap(19); + intr_io = setup_l2cap(L2CAP_PSM_HIDP_INTR); if (!intr_io) { error("Failed to listen on interrupt channel"); g_io_channel_unref(ctrl_io); -- cgit From 51386028973220d84b6a7e59735fa1fce98621b3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 14:25:16 +0000 Subject: input: pending_connect struct is not necessary anymore(replaced by DBusMessage pointer) --- input/device.c | 68 +++++++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index d3f07cf5..99c462c8 100644 --- a/input/device.c +++ b/input/device.c @@ -59,11 +59,6 @@ #define UPDOWN_ENABLED 1 -struct pending_connect { - DBusConnection *conn; - DBusMessage *msg; -}; - struct fake_input { GIOChannel *io; int rfcomm; /* RFCOMM socket */ @@ -80,7 +75,7 @@ struct device { uint16_t product; uint16_t vendor; struct fake_input *fake; - struct pending_connect *pending_connect; /* FIXME: use only the msg */ + DBusMessage *pending_connect; DBusConnection *conn; char *path; int ctrl_sk; @@ -110,17 +105,6 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) return idev; } -static void pending_connect_free(struct pending_connect *pc) -{ - if (!pc) - return; - if (pc->conn) - dbus_connection_unref(pc->conn); - if (pc->msg) - dbus_message_unref(pc->msg); - g_free(pc); -} - static void device_free(struct device *idev) { if (!idev) @@ -129,12 +113,11 @@ static void device_free(struct device *idev) g_free(idev->name); if (idev->fake) g_free(idev->fake); - if (idev->pending_connect) - pending_connect_free(idev->pending_connect); if (idev->path) g_free(idev->path); + if (idev->pending_connect) + dbus_message_unref(idev->pending_connect); dbus_connection_unref(idev->conn); - g_free(idev); } @@ -423,24 +406,24 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, (GIOFunc) rfcomm_io_cb, fake); /* Replying to the requestor */ - reply = dbus_message_new_method_return(idev->pending_connect->msg); - send_message_and_unref(idev->pending_connect->conn, reply); + reply = dbus_message_new_method_return(idev->pending_connect); + send_message_and_unref(idev->conn, reply); /* Sending the Connected signal */ - path = dbus_message_get_path(idev->pending_connect->msg); - dbus_connection_emit_signal(idev->pending_connect->conn, path, + path = dbus_message_get_path(idev->pending_connect); + dbus_connection_emit_signal(idev->conn, path, INPUT_DEVICE_INTERFACE, "Connected", DBUS_TYPE_INVALID); - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return FALSE; failed: - err_connection_failed(idev->pending_connect->conn, - idev->pending_connect->msg, strerror(err)); - pending_connect_free(idev->pending_connect); + err_connection_failed(idev->conn, + idev->pending_connect, strerror(err)); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; g_io_channel_close(chan); @@ -648,13 +631,13 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, DBUS_TYPE_INVALID); /* Replying to the requestor */ - send_message_and_unref(idev->pending_connect->conn, - dbus_message_new_method_return(idev->pending_connect->msg)); + send_message_and_unref(idev->conn, + dbus_message_new_method_return(idev->pending_connect)); goto cleanup; failed: - err_connection_failed(idev->pending_connect->conn, - idev->pending_connect->msg, strerror(err)); + err_connection_failed(idev->conn, + idev->pending_connect, strerror(err)); if (isk > 0) close(isk); close(idev->ctrl_sk); @@ -662,7 +645,7 @@ failed: idev->ctrl_sk = -1; cleanup: - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return FALSE; @@ -720,9 +703,9 @@ failed: close(csk); idev->ctrl_sk = -1; - err_connection_failed(idev->pending_connect->conn, - idev->pending_connect->msg, strerror(err)); - pending_connect_free(idev->pending_connect); + err_connection_failed(idev->conn, + idev->pending_connect, strerror(err)); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return FALSE; @@ -848,21 +831,14 @@ static DBusHandlerResult device_connect(DBusConnection *conn, if (is_connected(idev)) return err_already_connected(conn, msg); - idev->pending_connect = g_try_new0(struct pending_connect, 1); - if (!idev->pending_connect) { - error("Out of memory when allocating new struct pending_connect"); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - idev->pending_connect->conn = dbus_connection_ref(conn); - idev->pending_connect->msg = dbus_message_ref(msg); + idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ if (idev->fake) { if (rfcomm_connect(idev) < 0) { const char *str = strerror(errno); error("RFCOMM connect failed: %s(%d)", str, errno); - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return err_connection_failed(conn, msg, str); } @@ -875,7 +851,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, int err = errno; error("L2CAP connect failed: %s(%d)", strerror(err), err); - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return err_connection_failed(conn, msg, strerror(err)); } -- cgit From 0762886602369f99a473dc95cc288def7b6e363c Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 17:11:10 +0000 Subject: input: convert hidd to input --- input/manager.c | 38 ++++++++++++++++++++++++++++++++++++-- input/storage.c | 42 ++++++++++++++++++++++++++++++++++++++++++ input/storage.h | 1 + 3 files changed, 79 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 03c914ee..666c0e44 100644 --- a/input/manager.c +++ b/input/manager.c @@ -962,6 +962,34 @@ cleanup: g_free(hidp.rd_data); } +/* hidd to input transition function */ +static void stored_hidd(char *key, char *value, void *data) +{ + struct hidp_connadd_req hidp; + char *str, filename[PATH_MAX + 1], addr[18]; + bdaddr_t dst, *src = data; + + ba2str(src, addr); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "input"); + + str = textfile_get(filename, key); + if (str) { + /* Skip: entry found in input file */ + free(str); + return; + } + + memset(&hidp, 0, sizeof(struct hidp_connadd_req)); + + if (parse_stored_hidd(value, &hidp) < 0) + return; + + str2ba(key, &dst); + store_device_info(src, &dst, &hidp); + if (hidp.rd_data) + g_free(hidp.rd_data); +} + static void register_stored_inputs(void) { char dirname[PATH_MAX + 1]; @@ -980,10 +1008,16 @@ static void register_stored_inputs(void) if (!isdigit(de->d_name[0])) continue; + str2ba(de->d_name, &src); + + /* move the hidd entries to the input storage */ create_name(filename, PATH_MAX, STORAGEDIR, - de->d_name, "input"); + de->d_name, "hidd"); + textfile_foreach(filename, stored_hidd, &src); - str2ba(de->d_name, &src); + /* load the input stored devices */ + create_name(filename, PATH_MAX, STORAGEDIR, + de->d_name, "input"); textfile_foreach(filename, stored_input, &src); } diff --git a/input/storage.c b/input/storage.c index 3793a275..7da536b3 100644 --- a/input/storage.c +++ b/input/storage.c @@ -59,6 +59,48 @@ static inline int create_filename(char *buf, size_t size, return create_name(buf, size, STORAGEDIR, addr, name); } +int parse_stored_hidd(const char *str, struct hidp_connadd_req *req) +{ + char tmp[3]; + char *desc; + unsigned int vendor, product, version, subclass, country, parser, pos; + int i; + + desc = malloc(4096); + if (!desc) + return -ENOMEM; + + memset(desc, 0, 4096); + + sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", + &vendor, &product, &version, &subclass, &country, + &parser, desc, &req->flags, &pos); + + req->vendor = vendor; + req->product = product; + req->version = version; + req->subclass = subclass; + req->country = country; + req->parser = parser; + + req->rd_size = strlen(desc) / 2; + req->rd_data = g_try_malloc0(req->rd_size); + if (!req->rd_data) { + g_free(desc); + return -ENOMEM; + } + + memset(tmp, 0, sizeof(tmp)); + for (i = 0; i < req->rd_size; i++) { + memcpy(tmp, desc + (i * 2), 2); + req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); + } + + g_free(desc); + + return 0; +} + int parse_stored_device_info(const char *str, struct hidp_connadd_req *req) { char tmp[3]; diff --git a/input/storage.h b/input/storage.h index 81ad2599..a5462561 100644 --- a/input/storage.h +++ b/input/storage.h @@ -29,6 +29,7 @@ int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst); int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req); +int parse_stored_hidd(const char *str, struct hidp_connadd_req *req); int parse_stored_device_info(const char *str, struct hidp_connadd_req *req); -- cgit From b4427e24489d4aaf6768041cbb3b90353a285cfe Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 18:39:50 +0000 Subject: input: missing Disconnected signal when RemoveDevice is called --- input/device.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 99c462c8..69b7a482 100644 --- a/input/device.c +++ b/input/device.c @@ -80,6 +80,7 @@ struct device { char *path; int ctrl_sk; int intr_sk; + guint watch; }; GSList *devices = NULL; @@ -512,24 +513,29 @@ static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer d ret = FALSE; } - if (ret == FALSE) + if (ret == FALSE) { dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); + idev->watch = 0; + } return ret; } -static void create_watch(int sk, struct device *idev) +static guint create_watch(int sk, struct device *idev) { + guint id; GIOChannel *io; io = g_io_channel_unix_new(sk); - g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - connection_event, idev); + id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + connection_event, idev); g_io_channel_unref(io); + + return id; } static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name) @@ -623,7 +629,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (err < 0) goto failed; - create_watch(idev->ctrl_sk, idev); + idev->watch = create_watch(idev->ctrl_sk, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, @@ -1109,6 +1115,21 @@ int input_device_unregister(DBusConnection *conn, const char *path) devices = g_slist_remove(devices, idev); + /* + * Workaround: if connected, the watch will not be able + * to access the D-Bus data assigned to this path + * because the object path data was destroyed. + */ + if (idev->watch) { + g_source_remove(idev->watch); + idev->watch = 0; + dbus_connection_emit_signal(conn, + path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + } + dbus_connection_destroy_object_path(conn, path); dbus_connection_emit_signal(conn, INPUT_PATH, @@ -1271,7 +1292,7 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) return err; } - create_watch(idev->ctrl_sk, idev); + idev->watch = create_watch(idev->ctrl_sk, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, -- cgit From c6f486bcd46834a523bc5ee3fdcfc32ff1143943 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 18:43:13 +0000 Subject: input: missing close the channels(control/interrupt) when the auth fails --- input/server.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'input') diff --git a/input/server.c b/input/server.c index 0f04b06a..19f5378c 100644 --- a/input/server.c +++ b/input/server.c @@ -95,6 +95,8 @@ static void authorization_callback(DBusPendingCall *pcall, void *data) cancel_authorization(addr); } + input_device_close_channels(&auth->src, &auth->dst); + dbus_error_free(&derr); dbus_message_unref(reply); } -- cgit From 7fb02908be38aaa273643ac6b78c5d72e40ae545 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 19:14:38 +0000 Subject: input: fixed CreateDevice - verify the src and the dst address to discover if the device already exists --- input/device.c | 27 +++++++++------------------ input/device.h | 3 +-- input/manager.c | 16 +--------------- 3 files changed, 11 insertions(+), 35 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 69b7a482..d9dfbec4 100644 --- a/input/device.c +++ b/input/device.c @@ -1140,24 +1140,6 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } -int input_device_get_bdaddr(DBusConnection *conn, const char *path, - bdaddr_t *src, bdaddr_t *dst) -{ - struct device *idev; - - if (!dbus_connection_get_object_user_data(conn, path, - (void *) &idev)) - return -1; - - if (!idev) - return -1; - - bacpy(src, &idev->src); - bacpy(dst, &idev->dst); - - return 0; -} - int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data) { @@ -1236,6 +1218,15 @@ static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) return NULL; } +gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev = find_device(src, dst); + if (!idev) + return FALSE; + else + return TRUE; +} + int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) { struct device *idev = find_device(src, dst); diff --git a/input/device.h b/input/device.h index fdf7f90f..86b593f5 100644 --- a/input/device.h +++ b/input/device.h @@ -30,8 +30,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, uint8_t ch, const char **ppath); int input_device_unregister(DBusConnection *conn, const char *path); -int input_device_get_bdaddr(DBusConnection *conn, const char *path, - bdaddr_t *src, bdaddr_t *dst); +gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst); int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk); diff --git a/input/manager.c b/input/manager.c index 666c0e44..74654893 100644 --- a/input/manager.c +++ b/input/manager.c @@ -778,23 +778,12 @@ done: dbus_message_unref(reply); } -static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) -{ - bdaddr_t src, dst; - - if (input_device_get_bdaddr(connection, path, &src, &dst) < 0) - return -1; - - return bacmp(&dst, bdaddr); -} - static DBusHandlerResult create_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct pending_req *pr; DBusError derr; const char *addr; - GSList *l; bdaddr_t src, dst; uint32_t cls = 0; int dev_id; @@ -821,10 +810,7 @@ static DBusHandlerResult create_device(DBusConnection *conn, } str2ba(addr, &dst); - - l = g_slist_find_custom(device_paths, &dst, - (GCompareFunc) path_bdaddr_cmp); - if (l) + if (input_device_is_registered(&src, &dst)) return err_already_exists(conn, msg, "Input Already exists"); if (read_device_class(&src, &dst, &cls) < 0) { -- cgit From 79a65bbbe4d711bb7eb78ff9744fe33ef46082aa Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 19:55:06 +0000 Subject: input: remove the device entry from the hidd file when RemoveDevice is called --- input/storage.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/storage.c b/input/storage.c index 7da536b3..0ba49027 100644 --- a/input/storage.c +++ b/input/storage.c @@ -166,10 +166,12 @@ int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst) char filename[PATH_MAX + 1]; char addr[18]; - create_filename(filename, PATH_MAX, src, "input"); - ba2str(dst, addr); + create_filename(filename, PATH_MAX, src, "hidd"); + textfile_del(filename, addr); + + create_filename(filename, PATH_MAX, src, "input"); return textfile_del(filename, addr); } -- cgit From 1c98e7cad6bf2665457455c04dcb9758a3011606 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sat, 23 Jun 2007 16:28:24 +0000 Subject: input: can't call input_device_close_channels if the device path doesn't exist --- input/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index 19f5378c..c8e171f1 100644 --- a/input/server.c +++ b/input/server.c @@ -171,7 +171,7 @@ static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data debug("Incoming connection on PSM %d", psm); if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { - input_device_close_channels(&src, &dst); + close(nsk); return TRUE; } -- cgit From 5c95755a67bc8653af44996bb2fe9263a3137131 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sat, 23 Jun 2007 17:37:58 +0000 Subject: input: cleanup - removed useless code --- input/device.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index d9dfbec4..5c022ae6 100644 --- a/input/device.c +++ b/input/device.c @@ -783,9 +783,6 @@ fail: close(ctl); errno = err; - idev->intr_sk = -1; - idev->ctrl_sk = -1; - return -err; } -- cgit From cdfb78757572a7726711489371c77604d06f3b44 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sat, 23 Jun 2007 19:25:46 +0000 Subject: input: send unplug virtual cable to unknown devices --- input/server.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'input') diff --git a/input/server.c b/input/server.c index c8e171f1..394fada3 100644 --- a/input/server.c +++ b/input/server.c @@ -171,6 +171,12 @@ static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data debug("Incoming connection on PSM %d", psm); if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { + /* Send unplug virtual cable to unknown devices */ + if (psm == L2CAP_PSM_HIDP_CTRL) { + int err; + unsigned char unplug = 0x15; + err = write(nsk, &unplug, sizeof(unplug)); + } close(nsk); return TRUE; } -- cgit From b82eea72c2b643929b62f0613bf5748d60328e2d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sat, 23 Jun 2007 19:45:13 +0000 Subject: input: code cleanup --- input/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index 394fada3..0fa2bc82 100644 --- a/input/server.c +++ b/input/server.c @@ -173,9 +173,9 @@ static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { /* Send unplug virtual cable to unknown devices */ if (psm == L2CAP_PSM_HIDP_CTRL) { + unsigned char unplug[] = { 0x15 }; int err; - unsigned char unplug = 0x15; - err = write(nsk, &unplug, sizeof(unplug)); + err = write(nsk, unplug, sizeof(unplug)); } close(nsk); return TRUE; -- cgit From 0ffdac3e37977d4db9fb42832b95a6fd1f3a4100 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 3 Aug 2007 13:03:53 +0000 Subject: input: fixed missing byte(HID descriptor field) in the input file --- input/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/storage.c b/input/storage.c index 0ba49027..b20524d9 100644 --- a/input/storage.c +++ b/input/storage.c @@ -183,7 +183,7 @@ int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req create_filename(filename, PATH_MAX, src, "input"); - size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9; + size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 2 + 9; str = g_try_malloc0(size); if (!str) return -ENOMEM; -- cgit From ebd3c8b3a8fe0ec8050077e7739dba0b25aec2a1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 3 Aug 2007 13:32:58 +0000 Subject: input: fixed invalid D-Bus path when the remote device class is unknown --- input/device.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 5c022ae6..4f983d99 100644 --- a/input/device.c +++ b/input/device.c @@ -85,10 +85,22 @@ struct device { GSList *devices = NULL; -static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) +static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) { struct device *idev; uint32_t cls; + uint8_t major, minor; + + if (!subclass) { + if (read_device_class(src, dst, &cls) < 0) + return NULL; + + major = (cls >> 8) & 0x1f; + minor = (cls >> 2) & 0x3f; + } else { + major = 0x05; /* Peripheral */ + minor = (subclass >> 2) & 0x3f; + } idev = g_new0(struct device, 1); @@ -96,10 +108,9 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) 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; + idev->major = major; + idev->minor = minor; idev->ctrl_sk = -1; idev->intr_sk = -1; @@ -1055,8 +1066,16 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, const char *path; int err; - idev = device_new(src, dst); + idev = device_new(src, dst, hid->subclass); + if (!idev) + return -EINVAL; + path = create_input_path(idev->major, idev->minor); + if (!path) { + device_free(idev); + return -EINVAL; + } + idev->path = g_strdup(path); idev->product = hid->product; idev->vendor = hid->vendor; @@ -1077,8 +1096,16 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, const char *path; int err; - idev = device_new(src, dst); + idev = device_new(src, dst, 0); + if (!idev) + return -EINVAL; + path = create_input_path(idev->major, idev->minor); + if (!path) { + device_free(idev); + return -EINVAL; + } + idev->path = g_strdup(path); idev->conn = dbus_connection_ref(conn); -- cgit From 2639da11e06cc2d91c7c3416068333587f2b5df1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 3 Aug 2007 13:43:24 +0000 Subject: input: added epox_endian_quirk function --- input/manager.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 74654893..75ab1c15 100644 --- a/input/manager.c +++ b/input/manager.c @@ -181,6 +181,31 @@ static int get_handles(struct pending_req *pr, const char *uuid, return 0; } +static void epox_endian_quirk(unsigned char *data, int size) +{ + /* USAGE_PAGE (Keyboard) 05 07 + * USAGE_MINIMUM (0) 19 00 + * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00 + * LOGICAL_MINIMUM (0) 15 00 + * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00 + */ + unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff, + 0x15, 0x00, 0x26, 0x00, 0xff }; + int i; + + if (!data) + return; + + for (i = 0; i < size - sizeof(pattern); i++) { + if (!memcmp(data + i, pattern, sizeof(pattern))) { + data[i + 5] = 0xff; + data[i + 6] = 0x00; + data[i + 10] = 0xff; + data[i + 11] = 0x00; + } + } +} + static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist, *pdlist2; @@ -233,6 +258,7 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); req->rd_size = pdlist->unitSize; + epox_endian_quirk(req->rd_data, req->rd_size); } } } -- cgit From 309dbb1060ee24785b06ceb49a75d42c69d02f8a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 3 Aug 2007 14:18:54 +0000 Subject: input: GetName - fixed seg fault when the remote name is unknown --- input/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 4f983d99..6bf3da9a 100644 --- a/input/device.c +++ b/input/device.c @@ -952,8 +952,8 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, { struct device *idev = data; DBusMessage *reply; - const char *pname = idev->name; - + const char *pname = (idev->name ? idev->name : ""); + reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From 5aef8f33ebb1fb537e13ffeb336eb1d886a7adca Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 27 Aug 2007 13:50:32 +0000 Subject: input: don't send DeviceCreated signal when the daemon starts --- input/device.c | 5 ----- input/manager.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 6bf3da9a..3e019a44 100644 --- a/input/device.c +++ b/input/device.c @@ -1047,11 +1047,6 @@ static int register_path(DBusConnection *conn, const char *path, struct device * return -1; } - dbus_connection_emit_signal(conn, INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceCreated", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - devices = g_slist_append(devices, idev); info("Created input device: %s", path); diff --git a/input/manager.c b/input/manager.c index 75ab1c15..47638278 100644 --- a/input/manager.c +++ b/input/manager.c @@ -327,6 +327,11 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; } + dbus_connection_emit_signal(pr->conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceCreated", + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + device_paths = g_slist_append(device_paths, g_strdup(path)); /* Replying to the requestor */ @@ -736,6 +741,11 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } + dbus_connection_emit_signal(pr->conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceCreated", + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + device_paths = g_slist_append(device_paths, g_strdup(path)); pr_reply = dbus_message_new_method_return(pr->msg); -- cgit From 56e8f3fc3c15ceb035cda16d9dada129674cfeff Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Aug 2007 13:45:58 +0000 Subject: Fix socket validity checks --- input/manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 47638278..5dfb0641 100644 --- a/input/manager.c +++ b/input/manager.c @@ -348,7 +348,7 @@ failed: err_connection_failed(pr->conn, pr->msg, strerror(err)); cleanup: - if (isk > 0) + if (isk >= 0) close(isk); close(pr->ctrl_sock); @@ -406,7 +406,7 @@ static gboolean control_connect_cb(GIOChannel *chan, return FALSE; failed: - if (csk > 0) + if (csk >= 0) close(csk); err_connection_failed(pr->conn, pr->msg, strerror(err)); -- cgit From 2450e5e214398dc9d70fd28dcde9c2ac31bf8a29 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 30 Aug 2007 20:27:47 +0000 Subject: input: don't track POLLIN event --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 3e019a44..e137c28f 100644 --- a/input/device.c +++ b/input/device.c @@ -542,7 +542,7 @@ static guint create_watch(int sk, struct device *idev) GIOChannel *io; io = g_io_channel_unix_new(sk); - id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + id = g_io_add_watch(G_IO_HUP | G_IO_ERR | G_IO_NVAL, connection_event, idev); g_io_channel_unref(io); -- cgit From 0ad9f50ac3cfb1885fec839d6ac0be5fdc5aabd1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 30 Aug 2007 21:58:03 +0000 Subject: input: fixed last commit --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index e137c28f..3f78d15a 100644 --- a/input/device.c +++ b/input/device.c @@ -542,7 +542,7 @@ static guint create_watch(int sk, struct device *idev) GIOChannel *io; io = g_io_channel_unix_new(sk); - id = g_io_add_watch(G_IO_HUP | G_IO_ERR | G_IO_NVAL, + id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, connection_event, idev); g_io_channel_unref(io); -- cgit From a6da15f222255a207a33a67b32e16eb6cf9f61af Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 31 Aug 2007 16:36:33 +0000 Subject: input: added interrupt and control channels watches --- input/device.c | 91 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 29 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 3f78d15a..4c485736 100644 --- a/input/device.c +++ b/input/device.c @@ -32,7 +32,7 @@ #include #include #include - + #include #include #include @@ -80,7 +80,8 @@ struct device { char *path; int ctrl_sk; int intr_sk; - guint watch; + guint ctrl_watch; + guint intr_watch; }; GSList *devices = NULL; @@ -402,7 +403,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, goto failed; } - /* + /* * FIXME: Some headsets required a sco connection * first to report volume gain key events */ @@ -425,7 +426,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, path = dbus_message_get_path(idev->pending_connect); dbus_connection_emit_signal(idev->conn, path, INPUT_DEVICE_INTERFACE, "Connected", - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; @@ -511,45 +512,73 @@ failed: return -err; } -static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer data) +static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct device *idev = data; - gboolean ret = TRUE; - - if (cond & G_IO_NVAL) - ret = FALSE; - if (cond & (G_IO_HUP | G_IO_ERR)) { + if (cond & (G_IO_HUP | G_IO_ERR)) g_io_channel_close(chan); - ret = FALSE; + + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + + g_source_remove(idev->ctrl_watch); + idev->ctrl_watch = 0; + idev->intr_watch = 0; + + /* Close control channel */ + if (idev->ctrl_sk > 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; } - if (ret == FALSE) { - dbus_connection_emit_signal(idev->conn, - idev->path, - INPUT_DEVICE_INTERFACE, - "Disconnected", - DBUS_TYPE_INVALID); - idev->watch = 0; + return FALSE; + +} + +static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct device *idev = data; + + if (cond & (G_IO_HUP | G_IO_ERR)) + g_io_channel_close(chan); + + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + + g_source_remove(idev->intr_watch); + idev->intr_watch = 0; + idev->ctrl_watch = 0; + + /* Close interrupt channel */ + if (idev->intr_sk > 0) { + close(idev->intr_sk); + idev->intr_sk = -1; } - return ret; + return FALSE; } -static guint create_watch(int sk, struct device *idev) +static guint create_watch(int sk, GIOFunc cb, struct device *idev) { guint id; GIOChannel *io; io = g_io_channel_unix_new(sk); - id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, - connection_event, idev); + id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, cb, idev); g_io_channel_unref(io); return id; } -static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name) +static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, + int ctrl_sk, int intr_sk, const char *name) { struct hidp_connadd_req req; char addr[18]; @@ -640,7 +669,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (err < 0) goto failed; - idev->watch = create_watch(idev->ctrl_sk, idev); + idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); + idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, @@ -1139,9 +1169,11 @@ int input_device_unregister(DBusConnection *conn, const char *path) * to access the D-Bus data assigned to this path * because the object path data was destroyed. */ - if (idev->watch) { - g_source_remove(idev->watch); - idev->watch = 0; + if (idev->ctrl_watch) + g_source_remove(idev->ctrl_watch); + + if (idev->intr_watch) { + g_source_remove(idev->intr_watch); dbus_connection_emit_signal(conn, path, INPUT_DEVICE_INTERFACE, @@ -1154,7 +1186,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) dbus_connection_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID); return 0; } @@ -1302,7 +1334,8 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) return err; } - idev->watch = create_watch(idev->ctrl_sk, idev); + idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); + idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, -- cgit From 4e7fe8b13bd4cd3c82da00e812e812898a366b3b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 2 Oct 2007 17:54:40 +0000 Subject: input: minor leak and code standard --- input/device.c | 3 ++- input/manager.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 4c485736..59dbc5bb 100644 --- a/input/device.c +++ b/input/device.c @@ -665,7 +665,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } idev->intr_sk = isk; - err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); + err = hidp_connadd(&idev->src, &idev->dst, + idev->ctrl_sk, idev->intr_sk, idev->name); if (err < 0) goto failed; diff --git a/input/manager.c b/input/manager.c index 5dfb0641..1468b910 100644 --- a/input/manager.c +++ b/input/manager.c @@ -140,6 +140,7 @@ static int get_record(struct pending_req *pr, uint32_t handle, if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { error("Can't send D-Bus message."); + dbus_message_unref(msg); return -1; } @@ -158,7 +159,7 @@ static int get_handles(struct pending_req *pr, const char *uuid, char addr[18]; const char *paddr = addr; - msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, + msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, "org.bluez.Adapter", "GetRemoteServiceHandles"); if (!msg) return -1; @@ -171,6 +172,7 @@ static int get_handles(struct pending_req *pr, const char *uuid, if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { error("Can't send D-Bus message."); + dbus_message_unref(msg); return -1; } -- cgit From 09616172377cf146517c1eb821cb5f5d9cb2a188 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 2 Oct 2007 18:20:44 +0000 Subject: input: removed mem leak(HID desc list attribute) --- input/manager.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 1468b910..dc209a44 100644 --- a/input/manager.c +++ b/input/manager.c @@ -356,6 +356,9 @@ cleanup: close(pr->ctrl_sock); pending_req_free(pr); + if (hidp.rd_data) + g_free(hidp.rd_data); + return FALSE; } -- cgit From 07ebeadd853277fa7b7fae80abb84c17bf1d303b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 4 Oct 2007 15:48:32 +0000 Subject: input: added CreateSecureDevice --- input/error.c | 9 +++++ input/error.h | 3 ++ input/input-api.txt | 18 ++++++++-- input/manager.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++------ input/storage.c | 18 ++++++++++ input/storage.h | 2 ++ 6 files changed, 132 insertions(+), 13 deletions(-) (limited to 'input') diff --git a/input/error.c b/input/error.c index 3049b47f..983cb10d 100644 --- a/input/error.c +++ b/input/error.c @@ -66,6 +66,15 @@ DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg) "Already connected to this device")); } +DBusHandlerResult err_authentication_failed(DBusConnection *conn, + DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE".AuthenticationFailed", + "Authentication failed")); +} + DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str) { diff --git a/input/error.h b/input/error.h index 32f080fb..7bfdd78a 100644 --- a/input/error.h +++ b/input/error.h @@ -32,6 +32,9 @@ DBusHandlerResult err_connection_failed(DBusConnection *conn, DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg); +DBusHandlerResult err_authentication_failed(DBusConnection *conn, + DBusMessage *msg); + DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str); diff --git a/input/input-api.txt b/input/input-api.txt index 13da80ba..1d9fec1f 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -16,9 +16,7 @@ Methods array{string} ListDevices() string CreateDevice(string address) - Create an input device object. The HID service - record will be retrieved and the pairing will - be initiated if needed. + Create an input device object. On success it will return the path of the newly created device object. @@ -28,6 +26,20 @@ Methods array{string} ListDevices() org.bluez.input.ConnectionAttemptFailed org.bluez.input.Failed + string CreateSecureDevice(string address) + + Create an input device object. Pairing will + be initiated if needed(keyboard/combo devices). + + On success it will return the path of the + newly created device object. + + Possible errors: org.bluez.input.AlreadyExists + org.bluez.input.NotSupported + org.bluez.input.ConnectionAttemptFailed + org.bluez.input.AuthenticationFailed + org.bluez.input.Failed + void RemoveDevice(string path) Remove the input device object for a given path. diff --git a/input/manager.c b/input/manager.c index dc209a44..cd2e8a1d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -229,10 +229,10 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) 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; @@ -420,7 +420,35 @@ failed: return FALSE; } -static void finish_sdp_transaction(bdaddr_t *dba) +static void create_bonding_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct pending_req *pr = data; + DBusError derr; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("CreateBonding failed: %s(%s)", + derr.name, derr.message); + err_authentication_failed(pr->conn, pr->msg); + dbus_error_free(&derr); + dbus_message_unref(reply); + pending_req_free(pr); + return; + } + + dbus_message_unref(reply); + + if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb, pr) < 0) { + int err = errno; + err_connection_failed(pr->conn, pr->msg, strerror(err)); + error("L2CAP connect failed:%s (%d)", strerror(err), err); + pending_req_free(pr); + } +} + +static void finish_sdp_transaction(bdaddr_t *dba) { char address[18], *addr_ptr = address; DBusMessage *msg, *reply; @@ -455,6 +483,32 @@ static void finish_sdp_transaction(bdaddr_t *dba) dbus_message_unref(reply); } +static int create_bonding(struct pending_req *pr) +{ + DBusPendingCall *pending; + DBusMessage *msg; + char address[18], *addr_ptr = address; + + msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, + "org.bluez.Adapter", "CreateBonding"); + if (!msg) { + error("Unable to allocate new method call"); + return -1; + } + + ba2str(&pr->dst, address); + dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, DBUS_TYPE_INVALID); + if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { + error("Can't send D-Bus message."); + dbus_message_unref(msg); + return -1; + } + dbus_pending_call_set_notify(pending, create_bonding_reply, pr, NULL); + dbus_pending_call_unref(pending); + dbus_message_unref(msg); + return 0; +} + static void hid_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); @@ -498,16 +552,36 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } + dbus_message_unref(reply); + + if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) { + sdp_data_t *d; + + /* Pairing mandatory for keyboard and combo */ + d = sdp_data_get(pr->hid_rec, SDP_ATTR_HID_DEVICE_SUBCLASS); + if (d && (d->val.uint8 & 0x40) && + !has_bonding(&pr->src, &pr->dst)) { + if (create_bonding(pr) < 0) { + err_authentication_failed(pr->conn, pr->msg); + goto fail; + } + /* Wait bonding reply */ + return; + } + + /* Otherwise proceede L2CAP connection */ + } + + /* No encryption or link key already exists -- connect control channel */ if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb, pr) < 0) { int err = errno; error("L2CAP connect failed:%s (%d)", strerror(err), err); err_connection_failed(pr->conn, pr->msg, strerror(err)); goto fail; - } - dbus_message_unref(reply); + /* Wait L2CAP connect */ return; fail: dbus_error_free(&derr); @@ -966,7 +1040,7 @@ static void manager_unregister(DBusConnection *conn, void *data) static void stored_input(char *key, char *value, void *data) { const char *path; - struct hidp_connadd_req hidp; + struct hidp_connadd_req hidp; bdaddr_t dst, *src = data; str2ba(key, &dst); @@ -992,7 +1066,7 @@ cleanup: /* hidd to input transition function */ static void stored_hidd(char *key, char *value, void *data) { - struct hidp_connadd_req hidp; + struct hidp_connadd_req hidp; char *str, filename[PATH_MAX + 1], addr[18]; bdaddr_t dst, *src = data; @@ -1053,9 +1127,10 @@ static void register_stored_inputs(void) } static DBusMethodVTable manager_methods[] = { - { "ListDevices", list_devices, "", "as" }, - { "CreateDevice", create_device, "s", "s" }, - { "RemoveDevice", remove_device, "s", "" }, + { "ListDevices", list_devices, "", "as" }, + { "CreateDevice", create_device, "s", "s" }, + { "CreateSecureDevice", create_device, "s", "s" }, + { "RemoveDevice", remove_device, "s", "" }, { NULL, NULL, NULL, NULL }, }; diff --git a/input/storage.c b/input/storage.c index b20524d9..fe0469e6 100644 --- a/input/storage.c +++ b/input/storage.c @@ -344,3 +344,21 @@ fail: return -err; } + +gboolean has_bonding(bdaddr_t *src, bdaddr_t *dst) +{ + char filename[PATH_MAX + 1]; + char addr[18], *str; + + create_filename(filename, PATH_MAX, src, "linkkeys"); + + ba2str(dst, addr); + + str = textfile_get(filename, addr); + if (!str) + return FALSE; + + free(str); + + return TRUE; +} diff --git a/input/storage.h b/input/storage.h index a5462561..890e14e9 100644 --- a/input/storage.h +++ b/input/storage.h @@ -37,3 +37,5 @@ 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); + +gboolean has_bonding(bdaddr_t *src, bdaddr_t *dst); -- cgit From 90ca244669504fe6a1a6a2760da9ce71c8742f4c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 8 Oct 2007 11:14:20 +0000 Subject: Use the CreateSecureDevice method --- input/test-input | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/test-input b/input/test-input index 689e4723..a5fe9605 100755 --- a/input/test-input +++ b/input/test-input @@ -19,4 +19,4 @@ if (len(sys.argv) < 1): address = sys.argv[1] -device = input.CreateDevice(address) +device = input.CreateSecureDevice(address) -- cgit From 3571ae843629585caf996c73200bbbfd05c260a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 12 Oct 2007 11:00:32 +0000 Subject: Fix hidp_connad_req usage --- input/device.c | 6 +++--- input/manager.c | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 59dbc5bb..33a00f7e 100644 --- a/input/device.c +++ b/input/device.c @@ -800,7 +800,7 @@ static int disconnect(struct device *idev, uint32_t flags) return -errno; } - memset(&ci, 0, sizeof(struct hidp_conninfo)); + memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || (ci.state != BT_CONNECTED)) { @@ -808,7 +808,7 @@ static int disconnect(struct device *idev, uint32_t flags) goto fail; } - memset(&req, 0, sizeof(struct hidp_conndel_req)); + memset(&req, 0, sizeof(req)); bacpy(&req.bdaddr, &idev->dst); req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { @@ -847,7 +847,7 @@ static int is_connected(struct device *idev) if (ctl < 0) return 0; - memset(&ci, 0, sizeof(struct hidp_conninfo)); + memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); diff --git a/input/manager.c b/input/manager.c index cd2e8a1d..13e5cdba 100644 --- a/input/manager.c +++ b/input/manager.c @@ -288,6 +288,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, int isk, ret, err; socklen_t len; + memset(&hidp, 0, sizeof(hidp)); + isk = g_io_channel_unix_get_fd(chan); if (cond & G_IO_NVAL) { @@ -316,7 +318,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } - 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); @@ -1045,7 +1046,7 @@ static void stored_input(char *key, char *value, void *data) str2ba(key, &dst); - memset(&hidp, 0, sizeof(struct hidp_connadd_req)); + memset(&hidp, 0, sizeof(hidp)); if (parse_stored_device_info(value, &hidp) < 0) return; @@ -1080,7 +1081,7 @@ static void stored_hidd(char *key, char *value, void *data) return; } - memset(&hidp, 0, sizeof(struct hidp_connadd_req)); + memset(&hidp, 0, sizeof(hidp)); if (parse_stored_hidd(value, &hidp) < 0) return; -- cgit From 4392fbd3d96e2eea0d91f0eb9fd059ab38255986 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 26 Nov 2007 13:41:36 +0000 Subject: Update API descriptions to match new error codes --- input/input-api.txt | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'input') diff --git a/input/input-api.txt b/input/input-api.txt index 1d9fec1f..8eb13126 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -21,10 +21,10 @@ Methods array{string} ListDevices() On success it will return the path of the newly created device object. - Possible errors: org.bluez.input.AlreadyExists - org.bluez.input.NotSupported - org.bluez.input.ConnectionAttemptFailed - org.bluez.input.Failed + Possible errors: org.bluez.Error.AlreadyExists + org.bluez.Error.NotSupported + org.bluez.Error.ConnectionAttemptFailed + org.bluez.Error.Failed string CreateSecureDevice(string address) @@ -34,18 +34,17 @@ Methods array{string} ListDevices() On success it will return the path of the newly created device object. - Possible errors: org.bluez.input.AlreadyExists - org.bluez.input.NotSupported - org.bluez.input.ConnectionAttemptFailed - org.bluez.input.AuthenticationFailed - org.bluez.input.Failed + Possible errors: org.bluez.Error.AlreadyExists + org.bluez.Error.NotSupported + org.bluez.Error.ConnectionAttemptFailed + org.bluez.Error.Failed void RemoveDevice(string path) Remove the input device object for a given path. - Possible errors:org.bluez.input.DoesNotExist - org.bluez.input.Failed + Possible errors:org.bluez.Error.DoesNotExist + org.bluez.Error.Failed Signals void DeviceCreated(string path) @@ -90,14 +89,14 @@ Methods string GetAdapter() Connect to the input device. - Possible errors: org.bluez.input.AlreadyConnected - org.bluez.input.ConnectionAttemptFailed + Possible errors: org.bluez.Error.AlreadyConnected + org.bluez.Error.ConnectionAttemptFailed void Disconnect() Disconnect from the input device. - Possible errors: org.bluez.input.Failed + Possible errors: org.bluez.Error.Failed Signals void Connected() -- cgit From 7e88afe4f8307c092172ff3c3b76c2f95ab00293 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 26 Nov 2007 13:43:17 +0000 Subject: Update services to new error codes and helper functions --- input/Makefile.am | 2 +- input/device.c | 29 +++++++------ input/error.c | 108 ------------------------------------------------ input/error.h | 47 --------------------- input/manager.c | 121 +++++++++++++++++++++++++++++++----------------------- 5 files changed, 87 insertions(+), 220 deletions(-) delete mode 100644 input/error.c delete mode 100644 input/error.h (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 339a166d..958e4acc 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -11,7 +11,7 @@ servicedir = $(libdir)/bluetooth service_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = main.c \ - manager.h manager.c error.h error.c \ + manager.h manager.c \ server.h server.c device.h device.c storage.h storage.c LDADD = $(top_builddir)/common/libhelper.a \ diff --git a/input/device.c b/input/device.c index 33a00f7e..66712be2 100644 --- a/input/device.c +++ b/input/device.c @@ -434,8 +434,8 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, return FALSE; failed: - err_connection_failed(idev->conn, - idev->pending_connect, strerror(err)); + error_connection_attempt_failed(idev->conn, + idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; @@ -684,8 +684,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; failed: - err_connection_failed(idev->conn, - idev->pending_connect, strerror(err)); + error_connection_attempt_failed(idev->conn, + idev->pending_connect, err); if (isk > 0) close(isk); close(idev->ctrl_sk); @@ -751,8 +751,8 @@ failed: close(csk); idev->ctrl_sk = -1; - err_connection_failed(idev->conn, - idev->pending_connect, strerror(err)); + error_connection_attempt_failed(idev->conn, + idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; @@ -871,21 +871,24 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct device *idev = data; if (idev->pending_connect) - return err_connection_failed(conn, msg, "Connection in progress"); + return error_in_progress(conn, msg, + "Device connection already in progress"); if (is_connected(idev)) - return err_already_connected(conn, msg); + return error_already_connected(conn, msg); idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ if (idev->fake) { if (rfcomm_connect(idev) < 0) { - const char *str = strerror(errno); - error("RFCOMM connect failed: %s(%d)", str, errno); + int err = errno; + const char *str = strerror(err); + error("RFCOMM connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return err_connection_failed(conn, msg, str); + return error_connection_attempt_failed(conn, + msg, err); } return DBUS_HANDLER_RESULT_HANDLED; } @@ -898,7 +901,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, error("L2CAP connect failed: %s(%d)", strerror(err), err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return err_connection_failed(conn, msg, strerror(err)); + return error_connection_attempt_failed(conn, msg, err); } return DBUS_HANDLER_RESULT_HANDLED; @@ -910,7 +913,7 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, struct device *idev = data; if (disconnect(idev, 0) < 0) - return err_failed(conn, msg, strerror(errno)); + return error_failed_errno(conn, msg, errno); /* Replying to the requestor */ return send_message_and_unref(conn, diff --git a/input/error.c b/input/error.c deleted file mode 100644 index 983cb10d..00000000 --- a/input/error.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2007 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#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_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_connected(DBusConnection *conn, DBusMessage *msg) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".AlreadyConnected", - "Already connected to this device")); -} - -DBusHandlerResult err_authentication_failed(DBusConnection *conn, - DBusMessage *msg) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE".AuthenticationFailed", - "Authentication failed")); -} - -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")); -} - -DBusHandlerResult err_invalid_args(DBusConnection *conn, - DBusMessage *msg, const char *str) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".InvalidArguments", str)); -} diff --git a/input/error.h b/input/error.h deleted file mode 100644 index 7bfdd78a..00000000 --- a/input/error.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2007 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -DBusHandlerResult err_unknown_device(DBusConnection *conn, - DBusMessage *msg); - -DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, - const char *str); - -DBusHandlerResult err_connection_failed(DBusConnection *conn, - DBusMessage *msg, const char *str); - -DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg); - -DBusHandlerResult err_authentication_failed(DBusConnection *conn, - DBusMessage *msg); - -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); - -DBusHandlerResult err_invalid_args(DBusConnection *conn, - DBusMessage *msg, const char *str); diff --git a/input/manager.c b/input/manager.c index 13e5cdba..7bdf6d30 100644 --- a/input/manager.c +++ b/input/manager.c @@ -326,7 +326,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (input_device_register(pr->conn, &pr->src, &pr->dst, &hidp, &path) < 0) { - err_failed(pr->conn, pr->msg, "path registration failed"); + error_failed(pr->conn, pr->msg, "path registration failed"); goto cleanup; } @@ -348,7 +348,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; failed: - err_connection_failed(pr->conn, pr->msg, strerror(err)); + error_connection_attempt_failed(pr->conn, pr->msg, err); cleanup: if (isk >= 0) @@ -415,7 +415,7 @@ failed: if (csk >= 0) close(csk); - err_connection_failed(pr->conn, pr->msg, strerror(err)); + error_connection_attempt_failed(pr->conn, pr->msg, err); pending_req_free(pr); return FALSE; @@ -431,7 +431,7 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) if (dbus_set_error_from_message(&derr, reply)) { error("CreateBonding failed: %s(%s)", derr.name, derr.message); - err_authentication_failed(pr->conn, pr->msg); + error_failed(pr->conn, pr->msg, "Authentication failed (CreateBonding)"); dbus_error_free(&derr); dbus_message_unref(reply); pending_req_free(pr); @@ -443,7 +443,7 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb, pr) < 0) { int err = errno; - err_connection_failed(pr->conn, pr->msg, strerror(err)); + error_connection_attempt_failed(pr->conn, pr->msg, err); error("L2CAP connect failed:%s (%d)", strerror(err), err); pending_req_free(pr); } @@ -520,11 +520,14 @@ static void hid_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + /* FIXME : to not try to be clever about + hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) - err_connection_failed(pr->conn, pr->msg, derr.message); + error_connection_attempt_failed(pr->conn, + pr->msg, EIO); else - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceRecord failed: %s(%s)", derr.name, derr.message); @@ -536,20 +539,20 @@ static void hid_record_reply(DBusPendingCall *call, void *data) 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_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_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); + error_not_supported(pr->conn, pr->msg); goto fail; } @@ -563,7 +566,8 @@ static void hid_record_reply(DBusPendingCall *call, void *data) if (d && (d->val.uint8 & 0x40) && !has_bonding(&pr->src, &pr->dst)) { if (create_bonding(pr) < 0) { - err_authentication_failed(pr->conn, pr->msg); + error_failed(pr->conn, pr->msg, + "Unable to initialize bonding process"); goto fail; } /* Wait bonding reply */ @@ -578,7 +582,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) (GIOFunc) control_connect_cb, pr) < 0) { int err = errno; error("L2CAP connect failed:%s (%d)", strerror(err), err); - err_connection_failed(pr->conn, pr->msg, strerror(err)); + error_connection_attempt_failed(pr->conn, pr->msg, err); goto fail; } @@ -600,11 +604,14 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + /* FIXME : to not try to be clever about + hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) - err_connection_failed(pr->conn, pr->msg, derr.message); + error_connection_attempt_failed(pr->conn, + pr->msg, EIO); else - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); @@ -614,19 +621,19 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) 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_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_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_not_supported(pr->conn, pr->msg); error("HID service attribute request failed"); goto fail; } else { @@ -652,11 +659,14 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + /* FIXME : to not try to be clever about + hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) - err_connection_failed(pr->conn, pr->msg, derr.message); + error_connection_attempt_failed(pr->conn, pr->msg, + EIO); else - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); @@ -666,20 +676,20 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) 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_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_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_not_supported(pr->conn, pr->msg); error("HID service search request failed"); goto fail; } else { @@ -705,11 +715,14 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + /* FIXME : to not try to be clever about + hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) - err_connection_failed(pr->conn, pr->msg, derr.message); + error_connection_attempt_failed(pr->conn, pr->msg, + EIO); else - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); @@ -719,7 +732,7 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) 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_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); goto fail; } @@ -727,14 +740,14 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) 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_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_not_supported(pr->conn, pr->msg); error("PnP service attribute request failed"); goto fail; } @@ -766,11 +779,14 @@ static void headset_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + /* FIXME : to not try to be clever about + hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) - err_connection_failed(pr->conn, pr->msg, derr.message); + error_connection_attempt_failed(pr->conn, pr->msg, + EIO); else - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); @@ -780,25 +796,25 @@ static void headset_record_reply(DBusPendingCall *call, void *data) 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_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_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); + error_not_supported(pr->conn, pr->msg); goto fail; } if (sdp_get_access_protos(rec, &protos) < 0) { - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); goto fail; } @@ -808,7 +824,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) sdp_record_free(rec); if (ch <= 0) { - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("Invalid RFCOMM channel"); goto fail; } @@ -817,7 +833,7 @@ static void headset_record_reply(DBusPendingCall *call, void *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"); + error_failed(pr->conn, pr->msg, "Path registration failed"); goto fail; } @@ -852,11 +868,14 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + /* FIXME : to not try to be clever about + hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) - err_connection_failed(pr->conn, pr->msg, derr.message); + error_connection_attempt_failed(pr->conn, pr->msg, + EIO); else - err_not_supported(pr->conn, pr->msg); + error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); @@ -866,19 +885,19 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) 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_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_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_not_supported(pr->conn, pr->msg); error("Headset service attribute request failed"); goto fail; } else { @@ -908,7 +927,7 @@ static DBusHandlerResult create_device(DBusConnection *conn, if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &addr, DBUS_TYPE_INVALID)) { - err_invalid_args(conn, msg, derr.message); + error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } @@ -917,21 +936,21 @@ static DBusHandlerResult create_device(DBusConnection *conn, dev_id = hci_get_route(NULL); if (dev_id < 0) { error("Bluetooth adapter not available"); - return err_failed(conn, msg, "Adapter not available"); + return error_failed(conn, msg, "Adapter not available"); } if (hci_devba(dev_id, &src) < 0) { error("Can't get local adapter device info"); - return err_failed(conn, msg, "Adapter not available"); + return error_failed(conn, msg, "Adapter not available"); } str2ba(addr, &dst); if (input_device_is_registered(&src, &dst)) - return err_already_exists(conn, msg, "Input Already exists"); + return error_already_exists(conn, msg, "Input Already exists"); if (read_device_class(&src, &dst, &cls) < 0) { error("Device class not available"); - return err_not_supported(conn, msg); + return error_not_supported(conn, msg); } pr = pending_req_new(conn, msg, &src, &dst); @@ -943,19 +962,19 @@ static DBusHandlerResult create_device(DBusConnection *conn, case 0x0200: /* Phone */ if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); - return err_not_supported(conn, msg); + return error_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); + return error_not_supported(conn, msg); } break; default: pending_req_free(pr); - return err_not_supported(conn, msg); + return error_not_supported(conn, msg); } return DBUS_HANDLER_RESULT_HANDLED; @@ -974,14 +993,14 @@ static DBusHandlerResult remove_device(DBusConnection *conn, if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) { - err_invalid_args(conn, msg, derr.message); + error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } l = g_slist_find_custom(device_paths, path, (GCompareFunc) strcmp); if (!l) - return err_does_not_exist(conn, msg, "Input doesn't exist"); + return error_does_not_exist(conn, msg, "Input doesn't exist"); reply = dbus_message_new_method_return(msg); if (!reply) @@ -990,7 +1009,7 @@ static DBusHandlerResult remove_device(DBusConnection *conn, err = input_device_unregister(conn, path); if (err < 0) { dbus_message_unref(reply); - return err_failed(conn, msg, strerror(-err)); + return error_failed_errno(conn, msg, -err); } g_free(l->data); -- cgit From ba255beb79afb9c00ae5b71821f84f911aa8d1fe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Jan 2008 10:38:40 +0000 Subject: Whitespace cleanup --- input/device.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 66712be2..07ed7d9c 100644 --- a/input/device.c +++ b/input/device.c @@ -96,11 +96,11 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) if (read_device_class(src, dst, &cls) < 0) return NULL; - major = (cls >> 8) & 0x1f; - minor = (cls >> 2) & 0x3f; + major = (cls >> 8) & 0x1f; + minor = (cls >> 2) & 0x3f; } else { - major = 0x05; /* Peripheral */ - minor = (subclass >> 2) & 0x3f; + major = 0x05; /* Peripheral */ + minor = (subclass >> 2) & 0x3f; } idev = g_new0(struct device, 1); @@ -199,8 +199,8 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static int next_id = 0; switch (major) { - case 0x02: /* Phone */ - strcpy(subpath, "phone"); + case 0x02: /* Phone */ + strcpy(subpath, "phone"); break; case 0x04: /* Audio */ switch (minor) { @@ -274,7 +274,7 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static int decode_key(const char *str) { static int mode = UPDOWN_ENABLED, gain = 0; - + uint16_t key; int new_gain; @@ -335,7 +335,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) if (cond & G_IO_NVAL) return FALSE; - + if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on rfcomm server socket"); goto failed; @@ -871,7 +871,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct device *idev = data; if (idev->pending_connect) - return error_in_progress(conn, msg, + return error_in_progress(conn, msg, "Device connection already in progress"); if (is_connected(idev)) @@ -887,7 +887,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, error("RFCOMM connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, + return error_connection_attempt_failed(conn, msg, err); } return DBUS_HANDLER_RESULT_HANDLED; @@ -987,7 +987,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, struct device *idev = data; DBusMessage *reply; const char *pname = (idev->name ? idev->name : ""); - + reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From e823c15e43a6f924779e466d434c51157002d9ee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 Feb 2008 03:37:05 +0000 Subject: Update copyright information --- input/device.c | 2 +- input/device.h | 2 +- input/main.c | 2 +- input/manager.c | 2 +- input/manager.h | 2 +- input/server.c | 2 +- input/server.h | 2 +- input/storage.c | 2 +- input/storage.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 07ed7d9c..a8daa945 100644 --- a/input/device.c +++ b/input/device.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/device.h b/input/device.h index 86b593f5..92ca6896 100644 --- a/input/device.h +++ b/input/device.h @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/main.c b/input/main.c index cfe31b56..a3d83ff6 100644 --- a/input/main.c +++ b/input/main.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/manager.c b/input/manager.c index 7bdf6d30..a717c909 100644 --- a/input/manager.c +++ b/input/manager.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/manager.h b/input/manager.h index 7fc6f162..d55bb191 100644 --- a/input/manager.h +++ b/input/manager.h @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/server.c b/input/server.c index 0fa2bc82..f17caf21 100644 --- a/input/server.c +++ b/input/server.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/server.h b/input/server.h index ac2a073e..355406aa 100644 --- a/input/server.h +++ b/input/server.h @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/storage.c b/input/storage.c index fe0469e6..25894a5b 100644 --- a/input/storage.c +++ b/input/storage.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify diff --git a/input/storage.h b/input/storage.h index 890e14e9..90ba4a87 100644 --- a/input/storage.h +++ b/input/storage.h @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify -- cgit From fe4d95e06d3de9c917c689963d2894611e82d8ce Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 12 Feb 2008 04:44:53 +0000 Subject: Add support for connect/disconnect callbacks --- input/device.c | 61 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index a8daa945..290ad369 100644 --- a/input/device.c +++ b/input/device.c @@ -59,11 +59,16 @@ #define UPDOWN_ENABLED 1 +#define FI_FLAG_CONNECTED 1 + struct fake_input { + int flags; GIOChannel *io; int rfcomm; /* RFCOMM socket */ int uinput; /* uinput socket */ uint8_t ch; /* RFCOMM channel number */ + gboolean (*connect)(struct device *idev); + int (*disconnect)(struct device *idev); }; struct device { @@ -759,6 +764,26 @@ failed: return FALSE; } +static int fake_disconnect(struct device *idev) +{ + struct fake_input *fake = idev->fake; + + if (!fake->io) + return -ENOTCONN; + + g_io_channel_close(fake->io); + g_io_channel_unref(fake->io); + fake->io = NULL; + + if (fake->uinput >= 0) { + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + } + + return 0; +} + static int disconnect(struct device *idev, uint32_t flags) { struct fake_input *fake = idev->fake; @@ -768,20 +793,10 @@ static int disconnect(struct device *idev, uint32_t flags) /* Fake input disconnect */ if (fake) { - if (!fake->io) - return -ENOTCONN; - - g_io_channel_close(fake->io); - g_io_channel_unref(fake->io); - fake->io = NULL; - - if (fake->uinput >= 0) { - ioctl(fake->uinput, UI_DEV_DESTROY); - close(fake->uinput); - fake->uinput = -1; - } - - return 0; + err = fake->disconnect(idev); + if (err == 0) + fake->flags &= ~FI_FLAG_CONNECTED; + return err; } /* Standard HID disconnect */ @@ -835,12 +850,8 @@ static int is_connected(struct device *idev) int ctl; /* Fake input */ - if (fake) { - if (fake->io) - return 1; - else - return 0; - } + if (fake) + return fake->flags & FI_FLAG_CONNECTED; /* Standard HID */ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); @@ -869,6 +880,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; + struct fake_input *fake = idev->fake; if (idev->pending_connect) return error_in_progress(conn, msg, @@ -880,16 +892,17 @@ static DBusHandlerResult device_connect(DBusConnection *conn, idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ - if (idev->fake) { - if (rfcomm_connect(idev) < 0) { + if (fake) { + if (fake->connect(idev) < 0) { int err = errno; const char *str = strerror(err); - error("RFCOMM connect failed: %s(%d)", str, err); + error("Connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return error_connection_attempt_failed(conn, msg, err); } + fake->flags |= FI_FLAG_CONNECTED; return DBUS_HANDLER_RESULT_HANDLED; } @@ -1142,6 +1155,8 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; + idev->fake->connect = rfcomm_connect; + idev->fake->disconnect = fake_disconnect; err = register_path(conn, path, idev); -- cgit From 465696fda58ed0902157cb537c067a5d1c82ff27 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 12 Feb 2008 04:47:02 +0000 Subject: Fix build problem --- input/device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'input') diff --git a/input/device.c b/input/device.c index 290ad369..9eee6e5a 100644 --- a/input/device.c +++ b/input/device.c @@ -61,6 +61,8 @@ #define FI_FLAG_CONNECTED 1 +struct device; + struct fake_input { int flags; GIOChannel *io; -- cgit From f53dce601c8b8ee28bc8b5d354aaa56b454b1a71 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 14 Mar 2008 18:44:00 +0000 Subject: Add basic fake HID infrastructure support --- input/Makefile.am | 3 ++- input/device.c | 58 ++++++++++++++++++++++++++++++++++++++----------------- input/device.h | 15 ++++++++++++-- 3 files changed, 55 insertions(+), 21 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 958e4acc..cb56f812 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -12,7 +12,8 @@ service_PROGRAMS = bluetoothd-service-input bluetoothd_service_input_SOURCES = main.c \ manager.h manager.c \ - server.h server.c device.h device.c storage.h storage.c + server.h server.c device.h device.c storage.h storage.c \ + fakehid.c fakehid.h LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ diff --git a/input/device.c b/input/device.c index 9eee6e5a..46214217 100644 --- a/input/device.c +++ b/input/device.c @@ -52,6 +52,7 @@ #include "error.h" #include "manager.h" #include "storage.h" +#include "fakehid.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -63,16 +64,6 @@ struct device; -struct fake_input { - int flags; - GIOChannel *io; - int rfcomm; /* RFCOMM socket */ - int uinput; /* uinput socket */ - uint8_t ch; /* RFCOMM channel number */ - gboolean (*connect)(struct device *idev); - int (*disconnect)(struct device *idev); -}; - struct device { bdaddr_t src; bdaddr_t dst; @@ -1336,24 +1327,47 @@ int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst) return 0; } +static gboolean fake_hid_connect(struct device *dev) +{ + struct fake_hid *fhid = dev->fake->priv; + + return fhid->connect(dev->fake); +} + +static int fake_hid_disconnect(struct device *dev) +{ + struct fake_hid *fhid = dev->fake->priv; + + return fhid->disconnect(dev->fake); +} + int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; + struct fake_hid *fake_hid; + struct fake_input *fake = NULL; int err; idev = find_device(src, dst); if (!idev) return -ENOENT; - err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); - if (err < 0) { - close(idev->ctrl_sk); - close(idev->intr_sk); - idev->ctrl_sk = -1; - idev->intr_sk = -1; + fake_hid = get_fake_hid(idev->vendor, idev->product); + if (fake_hid) { + fake = g_try_new0(struct fake_input, 1); + if (!fake) { + err = -ENOMEM; + goto error; + } - return err; - } + fake->connect = fake_hid_connect; + fake->disconnect = fake_hid_disconnect; + fake->priv = fake_hid; + err = fake_hid_connadd(fake, idev->intr_sk, fake_hid); + } else + err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); + if (err < 0) + goto error; idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); @@ -1363,4 +1377,12 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) "Connected", DBUS_TYPE_INVALID); return 0; + +error: + close(idev->ctrl_sk); + close(idev->intr_sk); + idev->ctrl_sk = -1; + idev->intr_sk = -1; + g_free(fake); + return err; } diff --git a/input/device.h b/input/device.h index 92ca6896..aef4a915 100644 --- a/input/device.h +++ b/input/device.h @@ -24,6 +24,19 @@ #define L2CAP_PSM_HIDP_CTRL 0x11 #define L2CAP_PSM_HIDP_INTR 0x13 +struct device; + +struct fake_input { + int flags; + GIOChannel *io; + int uinput; /* uinput socket */ + int rfcomm; /* RFCOMM socket */ + uint8_t ch; /* RFCOMM channel number */ + gboolean (*connect) (struct device *dev); + int (*disconnect) (struct device *dev); + void *priv; +}; + int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hidp, const char **ppath); int fake_input_register(DBusConnection *conn, bdaddr_t *src, @@ -33,9 +46,7 @@ int input_device_unregister(DBusConnection *conn, const char *path); gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst); int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk); - int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst); - int input_device_connadd(bdaddr_t *src, bdaddr_t *dst); int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, -- cgit From 763087507a0b8e3df8b186c74ec35036e313b8a3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 14 Mar 2008 19:50:56 +0000 Subject: Add missing fakehid.[ch] files --- input/fakehid.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ input/fakehid.h | 39 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 input/fakehid.c create mode 100644 input/fakehid.h (limited to 'input') diff --git a/input/fakehid.c b/input/fakehid.c new file mode 100644 index 00000000..84c8e9ee --- /dev/null +++ b/input/fakehid.c @@ -0,0 +1,79 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2008 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "logging.h" +#include "device.h" +#include "fakehid.h" + +static struct fake_hid fake_hid_table[] = { + { }, +}; + +static inline int fake_hid_match_device(uint16_t vendor, uint16_t product, + struct fake_hid *fhid) +{ + return vendor == fhid->vendor && product == fhid->product; +} + +struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product) +{ + int i; + + for (i = 0; fake_hid_table[i].vendor != 0; i++) + if (fake_hid_match_device(vendor, product, &fake_hid_table[i])) + return &fake_hid_table[i]; + + return NULL; +} + +int fake_hid_connadd(struct fake_input *fake, int intr_sk, + struct fake_hid *fake_hid) +{ + if (fake_hid->setup_uinput(fake, fake_hid)) { + error("Error setting up uinput"); + return ENOMEM; + } + + fake->io = g_io_channel_unix_new(intr_sk); + g_io_channel_set_close_on_unref(fake->io, TRUE); + g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) fake_hid->event, fake); + + return 0; +} diff --git a/input/fakehid.h b/input/fakehid.h new file mode 100644 index 00000000..3bc2f3d6 --- /dev/null +++ b/input/fakehid.h @@ -0,0 +1,39 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2008 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +struct fake_hid; +struct fake_input; + +struct fake_hid { + uint16_t vendor; + uint16_t product; + gboolean (*connect) (struct fake_input *fake_input); + int (*disconnect) (struct fake_input *fake_input); + gboolean (*event) (GIOChannel *chan, GIOCondition cond, gpointer data); + int (*setup_uinput) (struct fake_input *fake, struct fake_hid *fake_hid); +}; + +struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product); + +int fake_hid_connadd(struct fake_input *fake, int intr_sk, + struct fake_hid *fake_hid); -- cgit From 835dd438bc43c1483480aaee08b7a5bfa49a21b6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 20 Mar 2008 14:45:32 +0000 Subject: Add support for PS3 remote devices --- input/fakehid.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 335 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/fakehid.c b/input/fakehid.c index 84c8e9ee..44c3ff6d 100644 --- a/input/fakehid.c +++ b/input/fakehid.c @@ -26,13 +26,15 @@ #endif #include -#include #include +#include +#include +#include #include #include -#include #include +#include #include #include @@ -40,8 +42,338 @@ #include "logging.h" #include "device.h" #include "fakehid.h" +#include "uinput.h" + +#ifndef KEY_REMOTE_1 +#define KEY_REMOTE_1 0x1b6 +#endif +#ifndef KEY_REMOTE_2 +#define KEY_REMOTE_2 0x1b7 +#endif +#ifndef KEY_REMOTE_3 +#define KEY_REMOTE_3 0x1b8 +#endif +#ifndef KEY_REMOTE_4 +#define KEY_REMOTE_4 0x1b9 +#endif +#ifndef KEY_REMOTE_5 +#define KEY_REMOTE_5 0x1ba +#endif +#ifndef KEY_REMOTE_6 +#define KEY_REMOTE_6 0x1bb +#endif +#ifndef KEY_REMOTE_7 +#define KEY_REMOTE_7 0x1bc +#endif +#ifndef KEY_REMOTE_8 +#define KEY_REMOTE_8 0x1bd +#endif +#ifndef KEY_REMOTE_9 +#define KEY_REMOTE_9 0x1be +#endif +#ifndef KEY_REMOTE_0 +#define KEY_REMOTE_0 0x1bf +#endif + +#define PS3_FLAGS_MASK 0xFFFFFF00 + +enum ps3remote_special_keys { + PS3R_BIT_PS = 0, + PS3R_BIT_ENTER = 3, + PS3R_BIT_L2 = 8, + PS3R_BIT_R2 = 9, + PS3R_BIT_L1 = 10, + PS3R_BIT_R1 = 11, + PS3R_BIT_TRIANGLE = 12, + PS3R_BIT_CIRCLE = 13, + PS3R_BIT_CROSS = 14, + PS3R_BIT_SQUARE = 15, + PS3R_BIT_SELECT = 16, + PS3R_BIT_L3 = 17, + PS3R_BIT_R3 = 18, + PS3R_BIT_START = 19, + PS3R_BIT_UP = 20, + PS3R_BIT_RIGHT = 21, + PS3R_BIT_DOWN = 22, + PS3R_BIT_LEFT = 23, +}; + +static unsigned int ps3remote_bits[] = { + [PS3R_BIT_ENTER] = 0x0b, + [PS3R_BIT_PS] = 0x43, + [PS3R_BIT_SQUARE] = 0x5f, + [PS3R_BIT_CROSS] = 0x5e, + [PS3R_BIT_CIRCLE] = 0x5d, + [PS3R_BIT_TRIANGLE] = 0x5c, + [PS3R_BIT_R1] = 0x5b, + [PS3R_BIT_L1] = 0x5a, + [PS3R_BIT_R2] = 0x59, + [PS3R_BIT_L2] = 0x58, + [PS3R_BIT_LEFT] = 0x57, + [PS3R_BIT_DOWN] = 0x56, + [PS3R_BIT_RIGHT] = 0x55, + [PS3R_BIT_UP] = 0x54, + [PS3R_BIT_START] = 0x53, + [PS3R_BIT_R3] = 0x52, + [PS3R_BIT_L3] = 0x51, + [PS3R_BIT_SELECT] = 0x50, +}; + +static unsigned int ps3remote_keymap[] = { + [0x16] = KEY_EJECTCD, + [0x64] = KEY_AUDIO, + [0x65] = KEY_ANGLE, + [0x63] = KEY_SUBTITLE, + [0x0f] = KEY_CLEAR, + [0x28] = KEY_TIME, + [0x00] = KEY_REMOTE_1, + [0x01] = KEY_REMOTE_2, + [0x02] = KEY_REMOTE_3, + [0x03] = KEY_REMOTE_4, + [0x04] = KEY_REMOTE_5, + [0x05] = KEY_REMOTE_6, + [0x06] = KEY_REMOTE_7, + [0x07] = KEY_REMOTE_8, + [0x08] = KEY_REMOTE_9, + [0x09] = KEY_REMOTE_0, + [0x81] = KEY_RED, + [0x82] = KEY_GREEN, + [0x80] = KEY_BLUE, + [0x83] = KEY_YELLOW, + [0x70] = KEY_INFO, /* display */ + [0x1a] = KEY_MENU, /* top menu */ + [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */ + [0x0e] = KEY_ESC, /* return */ + [0x5c] = KEY_OPTION, /* options/triangle */ + [0x5d] = KEY_BACK, /* back/circle */ + [0x5f] = KEY_SCREEN, /* view/square */ + [0x5e] = BTN_0, /* cross */ + [0x54] = KEY_UP, + [0x56] = KEY_DOWN, + [0x57] = KEY_LEFT, + [0x55] = KEY_RIGHT, + [0x0b] = KEY_ENTER, + [0x5a] = BTN_TL, /* L1 */ + [0x58] = BTN_TL2, /* L2 */ + [0x51] = BTN_THUMBL, /* L3 */ + [0x5b] = BTN_TR, /* R1 */ + [0x59] = BTN_TR2, /* R2 */ + [0x52] = BTN_THUMBR, /* R3 */ + [0x43] = KEY_HOMEPAGE, /* PS button */ + [0x50] = KEY_SELECT, + [0x53] = BTN_START, + [0x33] = KEY_REWIND, /* scan back */ + [0x32] = KEY_PLAY, + [0x34] = KEY_FORWARD, /* scan forward */ + [0x30] = KEY_PREVIOUS, + [0x38] = KEY_STOP, + [0x31] = KEY_NEXT, + [0x60] = KEY_FRAMEBACK, /* slow/step back */ + [0x39] = KEY_PAUSE, + [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */ + [0xff] = KEY_MAX, +}; + +static int ps3remote_decode(char *buff, int size, unsigned int *value) +{ + static unsigned int lastkey = 0; + static unsigned int lastmask = 0; + int retval, mask, key, i; + + if (size < 12) { + error("Got a shorter packet! (size %i)\n", size); + return KEY_RESERVED; + } + + mask = (buff[2] << 16) + (buff[3] << 8) + buff[4]; + key = buff[5]; + + /* first, check flags */ + for (i = 0; i < 24; i++) { + if ((lastmask & (1 << i)) == (mask & (1 << i))) + continue; + if (ps3remote_bits[i] == 0) + goto error; + retval = ps3remote_keymap[ps3remote_bits[i]]; + if (mask & (1 << i)) + /* key pressed */ + *value = 1; + else + /* key released */ + *value = 0; + + goto out; + } + + *value = buff[11]; + if (buff[11] == 1) { + retval = ps3remote_keymap[key]; + } else + retval = lastkey; + + if (retval == KEY_RESERVED) + goto error; + if (retval == KEY_MAX) + return retval; + + lastkey = retval; + +out: + fflush(stdout); + + lastmask = mask; + + return retval; + +error: + error("ps3remote: unrecognized sequence [%#x][%#x][%#x][%#x] [%#x]," + "last: [%#x][%#x][%#x][%#x]", + buff[2], buff[3], buff[4], buff[5], buff[11], + lastmask >> 16, lastmask >> 8 & 0xff, + lastmask & 0xff, lastkey); + return -1; +} + +static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond, + gpointer data) +{ + struct fake_input *fake = data; + struct uinput_event event; + unsigned int key, value = 0; + gsize size; + char buff[50]; + + if (cond & G_IO_NVAL) + return FALSE; + + if (cond & (G_IO_HUP | G_IO_ERR)) { + error("Hangup or error on rfcomm server socket"); + goto failed; + } + + memset(buff, 0, sizeof(buff)); + + if (g_io_channel_read(chan, buff, sizeof(buff), &size) != + G_IO_ERROR_NONE) { + error("IO Channel read error"); + goto failed; + } + + key = ps3remote_decode(buff, size, &value); + if (key == KEY_RESERVED) { + error("Got invalid key from decode"); + goto failed; + } else if (key == KEY_MAX) + return TRUE; + + memset(&event, 0, sizeof(event)); + gettimeofday(&event.time, NULL); + event.type = EV_KEY; + event.code = key; + event.value = value; + if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) { + error("Error writing to uinput device"); + goto failed; + } + + memset(&event, 0, sizeof(event)); + gettimeofday(&event.time, NULL); + event.type = EV_SYN; + event.code = SYN_REPORT; + if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) { + error("Error writing to uinput device"); + goto failed; + } + + return TRUE; + +failed: + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + g_io_channel_unref(fake->io); + + return FALSE; +} + +static int ps3remote_setup_uinput(struct fake_input *fake, + struct fake_hid *fake_hid) +{ + struct uinput_dev dev; + int i; + + fake->uinput = open("/dev/input/uinput", O_RDWR); + if (fake->uinput < 0) { + fake->uinput = open("/dev/uinput", O_RDWR); + if (fake->uinput < 0) + fake->uinput = open("/dev/misc/uinput", O_RDWR); + if (fake->uinput < 0) { + error("Error opening uinput device file"); + return 1; + } + } + + memset(&dev, 0, sizeof(dev)); + snprintf(dev.name, sizeof(dev.name), "%s", "PS3 Remote Controller"); + dev.id.bustype = BUS_BLUETOOTH; + dev.id.vendor = fake_hid->vendor; + dev.id.product = fake_hid->product; + + if (write(fake->uinput, &dev, sizeof(dev)) != sizeof(dev)) { + error("Error creating uinput device"); + goto err; + } + + /* enabling key events */ + if (ioctl(fake->uinput, UI_SET_EVBIT, EV_KEY) < 0) { + error("Error enabling uinput device key events"); + goto err; + } + + /* enabling keys */ + for (i = 0; i < 256; i++) + if (ps3remote_keymap[i] != KEY_RESERVED) + if (ioctl(fake->uinput, UI_SET_KEYBIT, + ps3remote_keymap[i]) < 0) { + error("Error enabling uinput key %i", + ps3remote_keymap[i]); + goto err; + } + + /* creating the device */ + if (ioctl(fake->uinput, UI_DEV_CREATE) < 0) { + error("Error creating uinput device"); + goto err; + } + + return 0; + +err: + close(fake->uinput); + return 1; +} + +static gboolean fake_hid_common_connect(struct fake_input *fake) +{ + return TRUE; +} + +static int fake_hid_common_disconnect(struct fake_input *fake) +{ + return 0; +} static struct fake_hid fake_hid_table[] = { + /* Sony PS3 remote device */ + { + .vendor = 0x054c, + .product = 0x0306, + .connect = fake_hid_common_connect, + .disconnect = fake_hid_common_disconnect, + .event = ps3remote_event, + .setup_uinput = ps3remote_setup_uinput, + }, + { }, }; @@ -73,7 +405,7 @@ int fake_hid_connadd(struct fake_input *fake, int intr_sk, fake->io = g_io_channel_unix_new(intr_sk); g_io_channel_set_close_on_unref(fake->io, TRUE); g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) fake_hid->event, fake); + (GIOFunc) fake_hid->event, fake); return 0; } -- cgit From 957ead88e8a90526631f1a767ba1006bc03b8084 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 22 Mar 2008 15:27:02 +0000 Subject: Update test script for input service --- input/test-input | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/test-input b/input/test-input index a5fe9605..7f41b6f6 100755 --- a/input/test-input +++ b/input/test-input @@ -13,10 +13,33 @@ conn = manager.ActivateService('input') input = dbus.Interface(bus.get_object(conn, '/org/bluez/input'), 'org.bluez.input.Manager') -if (len(sys.argv) < 1): - print "Usage: %s
" % (sys.argv[0]) +if (len(sys.argv) < 2): + print "Usage: %s " % (sys.argv[0]) + print "" + print " list" + print " create
" + print " remove " sys.exit(1) -address = sys.argv[1] - -device = input.CreateSecureDevice(address) +if (sys.argv[1] == "list"): + list = input.ListDevices() + print list + sys.exit(0) + +if (sys.argv[1] == "create"): + if (len(sys.argv) < 3): + print "Need address parameter" + else: + device = input.CreateSecureDevice(sys.argv[2]) + print device + sys.exit(0) + +if (sys.argv[1] == "remove"): + if (len(sys.argv) < 3): + print "Need object path parameter" + else: + input.RemoveDevice(sys.argv[2]) + sys.exit(0) + +print "Unknown command" +sys.exit(1) -- cgit From 29efa57d5a27b0cf5997381053be9cc48b2c2e80 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 22 Mar 2008 15:37:36 +0000 Subject: Convert input service into a plugin --- input/Makefile.am | 18 ++++++-------- input/input.service | 5 ---- input/main.c | 71 ++++++++++++----------------------------------------- input/manager.c | 4 +-- input/manager.h | 4 +-- 5 files changed, 27 insertions(+), 75 deletions(-) delete mode 100644 input/input.service (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index cb56f812..52a46a74 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -1,16 +1,10 @@ if INPUTSERVICE -if CONFIGFILES -confdir = $(sysconfdir)/bluetooth +plugindir = $(libdir)/bluetooth/plugins -conf_DATA = input.service -endif - -servicedir = $(libdir)/bluetooth +plugin_LTLIBRARIES = libinput.la -service_PROGRAMS = bluetoothd-service-input - -bluetoothd_service_input_SOURCES = main.c \ +libinput_la_SOURCES = main.c \ manager.h manager.c \ server.h server.c device.h device.c storage.h storage.c \ fakehid.c fakehid.h @@ -19,10 +13,12 @@ LDADD = $(top_builddir)/common/libhelper.a \ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ endif +AM_LDFLAGS = -module -avoid-version -export-symbols-regex bluetooth_plugin_desc + AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ -INCLUDES = -I$(top_srcdir)/common +INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -EXTRA_DIST = input.service input-api.txt test-input +EXTRA_DIST = input-api.txt test-input MAINTAINERCLEANFILES = Makefile.in diff --git a/input/input.service b/input/input.service deleted file mode 100644 index f5a105f8..00000000 --- a/input/input.service +++ /dev/null @@ -1,5 +0,0 @@ -[Bluetooth Service] -Identifier=input -Name=Input service -Description=Bluetooth HID based Input service -Autostart=true diff --git a/input/main.c b/input/main.c index a3d83ff6..4589cc33 100644 --- a/input/main.c +++ b/input/main.c @@ -25,76 +25,37 @@ #include #endif -#include -#include -#include -#include #include -#include #include -#include - +#include "plugin.h" #include "dbus.h" -#include "logging.h" - #include "manager.h" -static GMainLoop *main_loop; - -static void sig_term(int sig) -{ - g_main_loop_quit(main_loop); -} +static DBusConnection *conn; -int main(int argc, char *argv[]) +static int input_init(void) { - DBusConnection *conn; - struct sigaction sa; - - start_logging("input", "Bluetooth Input daemon"); + conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (conn == NULL) + return -EIO; - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_NOCLDSTOP; - sa.sa_handler = sig_term; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - - enable_debug(); - - main_loop = g_main_loop_new(NULL, FALSE); - - conn = dbus_bus_system_setup_with_main_loop(NULL, NULL, NULL); - if (!conn) { - g_main_loop_unref(main_loop); - exit(1); - } - - if (input_init(conn) < 0) { + if (input_manager_init(conn) < 0) { dbus_connection_unref(conn); - g_main_loop_unref(main_loop); - exit(1); + return -EIO; } - if (argc > 1 && !strcmp(argv[1], "-s")) - register_external_service(conn, "input", "Input service", ""); + register_external_service(conn, "input", "Input service", ""); - g_main_loop_run(main_loop); + return 0; +} - input_exit(); +static void input_exit(void) +{ + input_manager_exit(); dbus_connection_unref(conn); - - g_main_loop_unref(main_loop); - - info("Exit"); - - stop_logging(); - - return 0; } + +BLUETOOTH_PLUGIN_DEFINE("input", input_init, input_exit) diff --git a/input/manager.c b/input/manager.c index a717c909..953b44ac 100644 --- a/input/manager.c +++ b/input/manager.c @@ -1160,7 +1160,7 @@ static DBusSignalVTable manager_signals[] = { { NULL, NULL } }; -int input_init(DBusConnection *conn) +int input_manager_init(DBusConnection *conn) { dbus_connection_set_exit_on_disconnect(conn, TRUE); @@ -1192,7 +1192,7 @@ int input_init(DBusConnection *conn) return 0; } -void input_exit(void) +void input_manager_exit(void) { dbus_connection_destroy_object_path(connection, INPUT_PATH); diff --git a/input/manager.h b/input/manager.h index d55bb191..cccff683 100644 --- a/input/manager.h +++ b/input/manager.h @@ -24,5 +24,5 @@ #define INPUT_PATH "/org/bluez/input" #define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" -int input_init(DBusConnection *conn); -void input_exit(void); +int input_manager_init(DBusConnection *conn); +void input_manager_exit(void); -- cgit From 1152fc72d35de616d5d2d3a29525fd6aacb852f9 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 27 Mar 2008 14:05:37 +0000 Subject: Remove blocking call of FinishRemoteServiceTransaction. --- input/manager.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 953b44ac..2e138c6b 100644 --- a/input/manager.c +++ b/input/manager.c @@ -452,8 +452,7 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) static void finish_sdp_transaction(bdaddr_t *dba) { char address[18], *addr_ptr = address; - DBusMessage *msg, *reply; - DBusError derr; + DBusMessage *msg; ba2str(dba, address); @@ -468,20 +467,7 @@ static void finish_sdp_transaction(bdaddr_t *dba) dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, DBUS_TYPE_INVALID); - dbus_error_init(&derr); - reply = dbus_connection_send_with_reply_and_block(connection, msg, - -1, &derr); - - dbus_message_unref(msg); - - if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) { - error("FinishRemoteServiceTransaction(%s) failed: %s", - address, derr.message); - dbus_error_free(&derr); - return; - } - - dbus_message_unref(reply); + send_message_and_unref(connection, msg); } static int create_bonding(struct pending_req *pr) -- cgit From 60202f31c998cc68c14f57c91e4b40d2c39f95f2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 9 Apr 2008 22:00:34 +0000 Subject: Broken build: missing headers --- input/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'input') diff --git a/input/main.c b/input/main.c index 4589cc33..2e5cb1cf 100644 --- a/input/main.c +++ b/input/main.c @@ -27,6 +27,7 @@ #include +#include #include #include "plugin.h" -- cgit From 66327fddf82d027fbc98daefab771c23d5c3c1c9 Mon Sep 17 00:00:00 2001 From: Vinicius Gomes Date: Thu, 17 Apr 2008 14:54:30 +0000 Subject: input: adding the new plugin authorization --- input/server.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index f17caf21..b999748d 100644 --- a/input/server.c +++ b/input/server.c @@ -46,6 +46,10 @@ #include "server.h" #include "storage.h" +#include "plugin.h" + +static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; + static DBusConnection *connection = NULL; static void cancel_authorization(const char *addr) @@ -101,6 +105,22 @@ static void authorization_callback(DBusPendingCall *pcall, void *data) dbus_message_unref(reply); } +static void auth_callback(DBusError *derr, void *user_data) +{ + struct authorization_data *auth = user_data; + + if (derr) { + error("Access denied: %s", derr->message); + if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) + plugin_cancel_auth(&auth->dst); + + input_device_close_channels(&auth->src, &auth->dst); + } else + input_device_connadd(&auth->src, &auth->dst); + + g_free(auth); +} + static int authorize_device(bdaddr_t *src, bdaddr_t *dst) { struct authorization_data *auth; @@ -108,12 +128,24 @@ static int authorize_device(bdaddr_t *src, bdaddr_t *dst) DBusPendingCall *pending; char addr[18]; const char *paddr = addr; - const char *uuid = ""; /* FIXME: */ + int retval; + auth = g_new0(struct authorization_data, 1); + bacpy(&auth->src, src); + bacpy(&auth->dst, dst); + + retval = plugin_req_auth(src, dst, HID_UUID, + auth_callback, auth); + if (retval < 0) + goto fallback; + + return retval; + +fallback: msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", "RequestAuthorization"); if (!msg) { - error("Unable to allocat new RequestAuthorization method call"); + error("Unable to allocate new RequestAuthorization method call"); return -ENOMEM; } @@ -121,16 +153,13 @@ static int authorize_device(bdaddr_t *src, bdaddr_t *dst) ba2str(dst, addr); dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_STRING, &HID_UUID, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, msg, &pending, -1) == FALSE) return -EACCES; - auth = g_new0(struct authorization_data, 1); - bacpy(&auth->src, src); - bacpy(&auth->dst, dst); dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free); dbus_pending_call_unref(pending); dbus_message_unref(msg); -- cgit From 279e85d6da77c74f04e5fc605dd8074bfe56b5a5 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 25 Apr 2008 20:01:09 +0000 Subject: Make input service to use libbluetooth-glib convenient functions. --- input/device.c | 206 ++++------------------ input/manager.c | 532 ++++++++------------------------------------------------ 2 files changed, 103 insertions(+), 635 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 46214217..08a1c089 100644 --- a/input/device.c +++ b/input/device.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -53,6 +54,7 @@ #include "manager.h" #include "storage.h" #include "fakehid.h" +#include "glib-helper.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -368,38 +370,18 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void rfcomm_connect_cb(GIOChannel *chan, int err, gpointer user_data) { + struct device *idev = user_data; struct fake_input *fake; DBusMessage *reply; const char *path; - socklen_t len; - int ret, err; fake = idev->fake; fake->rfcomm = g_io_channel_unix_get_fd(chan); - if (cond & G_IO_NVAL) - return FALSE; - - if (cond & (G_IO_ERR | G_IO_HUP)) { - err = EIO; - goto failed; - } - - len = sizeof(ret); - if (getsockopt(fake->rfcomm, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(err), err); + if (err < 0) goto failed; - } /* * FIXME: Some headsets required a sco connection @@ -429,85 +411,27 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return FALSE; + return; failed: error_connection_attempt_failed(idev->conn, idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - g_io_channel_close(chan); - - return FALSE; } static int rfcomm_connect(struct device *idev) { - struct sockaddr_rc addr; - GIOChannel *io; - int sk, err; - - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) { - err = errno; - error("socket: %s (%d)", strerror(err), err); - return -err; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &idev->src); - addr.rc_channel = 0; - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - err = errno; - error("bind: %s (%d)", strerror(err), err); - goto failed; - } - - if (set_nonblocking(sk) < 0) { - err = errno; - error("Set non blocking: %s (%d)", strerror(err), err); - goto failed; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &idev->dst); - addr.rc_channel = idev->fake->ch; - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, FALSE); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - char peer[18]; /* FIXME: debug purpose */ - if (!(errno == EAGAIN || errno == EINPROGRESS)) { - err = errno; - error("connect() failed: %s (%d)", - strerror(err), err); - g_io_channel_unref(io); - goto failed; - } + int err; - ba2str(&idev->dst, peer); - debug("RFCOMM connection in progress: %s channel:%d", peer, idev->fake->ch); - g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, idev); - } else { - debug("Connect succeeded with first try"); - rfcomm_connect_cb(io, G_IO_OUT, idev); + err = bt_rfcomm_connect(&idev->src, &idev->dst, idev->fake->ch, + rfcomm_connect_cb, idev); + if (err < 0) { + error("connect() failed: %s (%d)", strerror(-err), -err); + return err; } - g_io_channel_unref(io); - return 0; - -failed: - close(sk); - errno = err; - - return -err; } static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) @@ -628,41 +552,16 @@ cleanup: return err; } -static gboolean interrupt_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int isk, ret, err; - socklen_t len; - - isk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - isk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP interrupt socket"); - goto failed; - - } - - len = sizeof(ret); - if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } + struct device *idev = user_data; - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } - idev->intr_sk = isk; + idev->intr_sk = g_io_channel_unix_get_fd(chan); err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); if (err < 0) @@ -683,78 +582,43 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; failed: error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); - if (isk > 0) - close(isk); - close(idev->ctrl_sk); + idev->pending_connect, -err); idev->intr_sk = -1; idev->ctrl_sk = -1; cleanup: dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int ret, csk, err; - socklen_t len; + struct device *idev = user_data; - csk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - csk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP control socket"); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } /* Set HID control channel */ - idev->ctrl_sk = csk; - - len = sizeof(ret); - if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); - goto failed; - } + idev->ctrl_sk = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb, idev) < 0) { - - err = errno; - error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + interrupt_connect_cb, idev); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); goto failed; } - return FALSE; + return; failed: - if (csk > 0) - close(csk); - idev->ctrl_sk = -1; error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); + idev->pending_connect, -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - return FALSE; } static int fake_disconnect(struct device *idev) @@ -874,6 +738,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, { struct device *idev = data; struct fake_input *fake = idev->fake; + int err; if (idev->pending_connect) return error_in_progress(conn, msg, @@ -900,14 +765,13 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, idev) < 0) { - int err = errno; - - error("L2CAP connect failed: %s(%d)", strerror(err), err); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, idev); + if (err < 0) { + error("L2CAP connect failed: %s(%d)", strerror(-err), -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, msg, err); + return error_connection_attempt_failed(conn, msg, -err); } return DBUS_HANDLER_RESULT_HANDLED; diff --git a/input/manager.c b/input/manager.c index 2e138c6b..4b25843d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -52,10 +52,7 @@ #include "error.h" #include "manager.h" #include "storage.h" - -static const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; -static const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; -static const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; +#include "glib-helper.h" struct pending_req { char *adapter_path; /* Local adapter D-Bus path */ @@ -119,70 +116,6 @@ static void pending_req_free(struct pending_req *pr) g_free(pr); } -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."); - dbus_message_unref(msg); - return -1; - } - - dbus_pending_call_set_notify(pending, cb, pr, NULL); - dbus_pending_call_unref(pending); - 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."); - dbus_message_unref(msg); - return -1; - } - - dbus_pending_call_set_notify(pending, cb, pr, NULL); - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - - return 0; -} - static void epox_endian_quirk(unsigned char *data, int size) { /* USAGE_PAGE (Keyboard) 05 07 @@ -279,42 +212,17 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -static gboolean interrupt_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_req *pr) +static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) { + struct pending_req *pr = user_data; struct hidp_connadd_req hidp; DBusMessage *reply; const char *path; - int isk, ret, err; - socklen_t len; memset(&hidp, 0, sizeof(hidp)); - isk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - isk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP interrupt socket"); - goto failed; - - } - - len = sizeof(ret); - if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } @@ -351,74 +259,38 @@ failed: error_connection_attempt_failed(pr->conn, pr->msg, err); cleanup: - if (isk >= 0) - close(isk); - close(pr->ctrl_sock); pending_req_free(pr); if (hidp.rd_data) g_free(hidp.rd_data); - - return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_req *pr) +static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int ret, csk, err; - socklen_t len; - - csk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - csk = -1; - goto failed; - } + struct pending_req *pr = user_data; - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP control socket"); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; - } /* Set HID control channel */ - pr->ctrl_sock = csk; - - len = sizeof(ret); - if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); - goto failed; - } + pr->ctrl_sock = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb, pr) < 0) { - - err = errno; - error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, + interrupt_connect_cb, pr); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); goto failed; } - return FALSE; + return; failed: - if (csk >= 0) - close(csk); - - error_connection_attempt_failed(pr->conn, pr->msg, err); + error_connection_attempt_failed(pr->conn, pr->msg, -err); pending_req_free(pr); - - return FALSE; } static void create_bonding_reply(DBusPendingCall *call, void *data) @@ -426,6 +298,7 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; DBusError derr; + int err; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { @@ -440,36 +313,15 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) dbus_message_unref(reply); - if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, pr) < 0) { - int err = errno; - error_connection_attempt_failed(pr->conn, pr->msg, err); - error("L2CAP connect failed:%s (%d)", strerror(err), err); + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, pr); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); + error_connection_attempt_failed(pr->conn, pr->msg, -err); pending_req_free(pr); } } -static void finish_sdp_transaction(bdaddr_t *dba) -{ - char address[18], *addr_ptr = address; - DBusMessage *msg; - - ba2str(dba, address); - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0", - "org.bluez.Adapter", - "FinishRemoteServiceTransaction"); - if (!msg) { - error("Unable to allocate new method call"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID); - - send_message_and_unref(connection, msg); -} - static int create_bonding(struct pending_req *pr) { DBusPendingCall *pending; @@ -496,53 +348,23 @@ static int create_bonding(struct pending_req *pr) return 0; } -static void hid_record_reply(DBusPendingCall *call, void *data) +static void hid_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint8_t *rec_bin; - int len, scanned; + struct pending_req *pr = user_data; - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, - pr->msg, EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceRecord failed: %s(%s)", - derr.name, derr.message); - goto fail; - } - - finish_sdp_transaction(&pr->dst); - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { + if (err < 0) { error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); + error("SDP search error: %s (%d)", strerror(-err), -err); goto fail; } - if (len == 0) { + if (!recs || !recs->data) { error_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) { - error_not_supported(pr->conn, pr->msg); - goto fail; - } - - dbus_message_unref(reply); + pr->hid_rec = recs->data; if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) { sdp_data_t *d; @@ -564,240 +386,76 @@ static void hid_record_reply(DBusPendingCall *call, void *data) } /* No encryption or link key already exists -- connect control channel */ - if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, pr) < 0) { - int err = errno; - error("L2CAP connect failed:%s (%d)", strerror(err), err); - error_connection_attempt_failed(pr->conn, pr->msg, err); + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, pr); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); + error_connection_attempt_failed(pr->conn, pr->msg, -err); goto fail; } /* Wait L2CAP connect */ return; -fail: - dbus_error_free(&derr); - pending_req_free(pr); - dbus_message_unref(reply); -} - -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)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, - pr->msg, EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceHandles: %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)) { - error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - error_not_supported(pr->conn, pr->msg); - error("HID record handle not found"); - goto fail; - } - - if (get_record(pr, *phandle, hid_record_reply) < 0) { - error_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); } -static void pnp_record_reply(DBusPendingCall *call, void *data) +static void pnp_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint8_t *rec_bin; - int len, scanned; + struct pending_req *pr = user_data; + uuid_t uuid; - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceRecord: %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)) { + if (err < 0) { error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); + error("SDP search error: %s (%d)", strerror(-err), -err); goto fail; } - if (len == 0) { + if (!recs || !recs->data) { error_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) { + pr->pnp_rec = recs->data; + sdp_uuid16_create(&uuid, HID_SVCLASS_ID); + err = bt_search_service(&pr->src, &pr->dst, &uuid, hid_record_cb, + pr, NULL); + if (err < 0) { error_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); -} - -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)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceHandles: %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)) { - error_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) { - error_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) { - error_not_supported(pr->conn, pr->msg); - error("PnP service attribute request failed"); - goto fail; - } - } - - /* Wait HID handle reply or PnP record reply */ - goto done; + return; fail: - dbus_error_free(&derr); pending_req_free(pr); - -done: - dbus_message_unref(reply); } -static void headset_record_reply(DBusPendingCall *call, void *data) +static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusMessage *pr_reply; - DBusError derr; - struct pending_req *pr = data; - uint8_t *rec_bin; + struct pending_req *pr = user_data; + DBusMessage *reply; 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)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceRecord: %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)) { + if (err < 0) { error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); + error("SDP search error: %s (%d)", strerror(-err), -err); goto fail; } - if (len == 0) { + if (!recs || !recs->data) { error_not_supported(pr->conn, pr->msg); error("Invalid headset service record length"); goto fail; } - rec = sdp_extract_pdu(rec_bin, &scanned); - if (!rec) { - error_not_supported(pr->conn, pr->msg); - goto fail; - } + rec = recs->data; if (sdp_get_access_protos(rec, &protos) < 0) { error_not_supported(pr->conn, pr->msg); @@ -830,73 +488,16 @@ static void headset_record_reply(DBusPendingCall *call, void *data) device_paths = g_slist_append(device_paths, g_strdup(path)); - pr_reply = dbus_message_new_method_return(pr->msg); + reply = dbus_message_new_method_return(pr->msg); - dbus_message_append_args(pr_reply, + dbus_message_append_args(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); -} - -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)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceHandles: %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)) { - error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - error_not_supported(pr->conn, pr->msg); - error("Headset record handle not found"); - goto fail; - } - - if (get_record(pr, *phandle, headset_record_reply) < 0) { - error_not_supported(pr->conn, pr->msg); - error("Headset service attribute request failed"); - goto fail; - } else { - /* Wait record reply */ - goto done; - } + send_message_and_unref(pr->conn, reply); fail: - dbus_error_free(&derr); pending_req_free(pr); - -done: - dbus_message_unref(reply); } static DBusHandlerResult create_device(DBusConnection *conn, @@ -907,7 +508,9 @@ static DBusHandlerResult create_device(DBusConnection *conn, const char *addr; bdaddr_t src, dst; uint32_t cls = 0; - int dev_id; + int dev_id, err; + uuid_t uuid; + bt_callback_t cb; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -946,23 +549,24 @@ static DBusHandlerResult create_device(DBusConnection *conn, switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ case 0x0200: /* Phone */ - if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { - pending_req_free(pr); - return error_not_supported(conn, msg); - } + sdp_uuid16_create(&uuid, PNP_INFO_SVCLASS_ID); + cb = pnp_record_cb; break; case 0x0400: /* Fake input */ - if (get_handles(pr, headset_uuid, - headset_handle_reply) < 0) { - pending_req_free(pr); - return error_not_supported(conn, msg); - } + sdp_uuid16_create(&uuid, HEADSET_SVCLASS_ID); + cb = headset_record_cb; break; default: pending_req_free(pr); return error_not_supported(conn, msg); } + err = bt_search_service(&src, &dst, &uuid, cb, pr, NULL); + if (err < 0) { + pending_req_free(pr); + return error_not_supported(conn, msg); + } + return DBUS_HANDLER_RESULT_HANDLED; } -- cgit From 0c5239ae4bd876e113ecc78ae383bac9483c2a83 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 29 Apr 2008 20:35:57 +0000 Subject: Fix possible memory leak where the records lists were not freed. --- input/manager.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 4b25843d..8d0a9160 100644 --- a/input/manager.c +++ b/input/manager.c @@ -60,8 +60,8 @@ struct pending_req { bdaddr_t dst; /* Peer BT address */ DBusConnection *conn; DBusMessage *msg; - sdp_record_t *pnp_rec; - sdp_record_t *hid_rec; + sdp_list_t *pnp_recs; + sdp_list_t *hid_recs; int ctrl_sock; }; @@ -107,11 +107,11 @@ static void pending_req_free(struct pending_req *pr) if (pr->msg) dbus_message_unref(pr->msg); - if (pr->pnp_rec) - sdp_record_free(pr->pnp_rec); + if (pr->pnp_recs) + sdp_list_free(pr->pnp_recs, (sdp_free_func_t) sdp_record_free); - if (pr->hid_rec) - sdp_record_free(pr->hid_rec); + if (pr->hid_recs) + sdp_list_free(pr->hid_recs, (sdp_free_func_t) sdp_record_free); g_free(pr); } @@ -226,9 +226,9 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) goto failed; } - extract_hid_record(pr->hid_rec, &hidp); - if (pr->pnp_rec) - extract_pnp_record(pr->pnp_rec, &hidp); + extract_hid_record(pr->hid_recs->data, &hidp); + if (pr->pnp_recs) + extract_pnp_record(pr->pnp_recs->data, &hidp); store_device_info(&pr->src, &pr->dst, &hidp); @@ -364,13 +364,14 @@ static void hid_record_cb(sdp_list_t *recs, int err, gpointer user_data) goto fail; } - pr->hid_rec = recs->data; + pr->hid_recs = recs; if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) { sdp_data_t *d; /* Pairing mandatory for keyboard and combo */ - d = sdp_data_get(pr->hid_rec, SDP_ATTR_HID_DEVICE_SUBCLASS); + d = sdp_data_get(pr->hid_recs->data, + SDP_ATTR_HID_DEVICE_SUBCLASS); if (d && (d->val.uint8 & 0x40) && !has_bonding(&pr->src, &pr->dst)) { if (create_bonding(pr) < 0) { @@ -418,7 +419,7 @@ static void pnp_record_cb(sdp_list_t *recs, int err, gpointer user_data) goto fail; } - pr->pnp_rec = recs->data; + pr->pnp_recs = recs; sdp_uuid16_create(&uuid, HID_SVCLASS_ID); err = bt_search_service(&pr->src, &pr->dst, &uuid, hid_record_cb, pr, NULL); -- cgit From c13abd60b0fd396820fe8160b893e95df7ed286b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 30 Apr 2008 18:46:19 +0000 Subject: input: close interrupt channel after CreateDevice has been called --- input/manager.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 8d0a9160..d7476cd7 100644 --- a/input/manager.c +++ b/input/manager.c @@ -260,6 +260,8 @@ failed: cleanup: close(pr->ctrl_sock); + g_io_channel_close(chan); + g_io_channel_unref(chan); pending_req_free(pr); if (hidp.rd_data) -- cgit From 2d5441331d402a0d78c4b84a028df076f6aab8cf Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 30 Apr 2008 19:37:46 +0000 Subject: Fix possible memory leak when closing control channel. --- input/device.c | 1 + input/manager.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 08a1c089..348622e6 100644 --- a/input/device.c +++ b/input/device.c @@ -580,6 +580,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) dbus_message_new_method_return(idev->pending_connect)); goto cleanup; + failed: error_connection_attempt_failed(idev->conn, idev->pending_connect, -err); diff --git a/input/manager.c b/input/manager.c index d7476cd7..9f8dcf66 100644 --- a/input/manager.c +++ b/input/manager.c @@ -62,7 +62,7 @@ struct pending_req { DBusMessage *msg; sdp_list_t *pnp_recs; sdp_list_t *hid_recs; - int ctrl_sock; + GIOChannel *ctrl_channel; }; static GSList *device_paths = NULL; /* Input registered paths */ @@ -259,7 +259,8 @@ failed: error_connection_attempt_failed(pr->conn, pr->msg, err); cleanup: - close(pr->ctrl_sock); + g_io_channel_close(pr->ctrl_channel); + g_io_channel_unref(pr->ctrl_channel); g_io_channel_close(chan); g_io_channel_unref(chan); pending_req_free(pr); @@ -278,7 +279,7 @@ static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) } /* Set HID control channel */ - pr->ctrl_sock = g_io_channel_unix_get_fd(chan); + pr->ctrl_channel = chan; /* Connect to the HID interrupt channel */ err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, -- cgit From 098cd10838193272c669348c5ffd0410218e1bcc Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 May 2008 01:05:46 +0000 Subject: fixed service authorization --- input/main.c | 9 +++++++++ input/server.c | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 2e5cb1cf..19f2f422 100644 --- a/input/main.c +++ b/input/main.c @@ -34,6 +34,13 @@ #include "dbus.h" #include "manager.h" +#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" + +static const char *uuids[] = { + HID_UUID, + NULL +}; + static DBusConnection *conn; static int input_init(void) @@ -47,6 +54,8 @@ static int input_init(void) return -EIO; } + register_uuids("input", &uuids); + register_external_service(conn, "input", "Input service", ""); return 0; diff --git a/input/server.c b/input/server.c index b999748d..6cfd0d37 100644 --- a/input/server.c +++ b/input/server.c @@ -55,7 +55,6 @@ static DBusConnection *connection = NULL; static void cancel_authorization(const char *addr) { DBusMessage *msg; - const char *uuid = ""; msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", @@ -67,7 +66,7 @@ static void cancel_authorization(const char *addr) dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr, - DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_STRING, &HID_UUID, DBUS_TYPE_INVALID); send_message_and_unref(connection, msg); -- cgit From 3f8860031e5241fbb145fdd71e1a46c2c28f393e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 May 2008 01:23:02 +0000 Subject: fixed build warnings --- input/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 19f2f422..dab730b7 100644 --- a/input/main.c +++ b/input/main.c @@ -28,9 +28,11 @@ #include #include +#include #include #include "plugin.h" +#include "dbus-service.h" #include "dbus.h" #include "manager.h" @@ -54,7 +56,7 @@ static int input_init(void) return -EIO; } - register_uuids("input", &uuids); + register_uuids("input", uuids); register_external_service(conn, "input", "Input service", ""); -- cgit From 9491a544f622e40453265c30f24ce44a61440cc1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 May 2008 13:52:26 +0000 Subject: Moving authorization code to dbus-service.c --- input/main.c | 5 ++--- input/server.c | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index dab730b7..d8236ada 100644 --- a/input/main.c +++ b/input/main.c @@ -28,12 +28,11 @@ #include #include -#include -#include + +#include "dbus.h" #include "plugin.h" #include "dbus-service.h" -#include "dbus.h" #include "manager.h" #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" diff --git a/input/server.c b/input/server.c index 6cfd0d37..ff7cdbfd 100644 --- a/input/server.c +++ b/input/server.c @@ -45,8 +45,7 @@ #include "device.h" #include "server.h" #include "storage.h" - -#include "plugin.h" +#include "dbus-service.h" static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; @@ -111,7 +110,7 @@ static void auth_callback(DBusError *derr, void *user_data) if (derr) { error("Access denied: %s", derr->message); if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) - plugin_cancel_auth(&auth->dst); + service_cancel_auth(&auth->dst); input_device_close_channels(&auth->src, &auth->dst); } else @@ -133,7 +132,7 @@ static int authorize_device(bdaddr_t *src, bdaddr_t *dst) bacpy(&auth->src, src); bacpy(&auth->dst, dst); - retval = plugin_req_auth(src, dst, HID_UUID, + retval = service_req_auth(src, dst, HID_UUID, auth_callback, auth); if (retval < 0) goto fallback; -- cgit From fd18cec597d56cb2ad322ba04c5ed1b5516f7df3 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 5 May 2008 17:55:29 +0000 Subject: Fix possible double free in case of connecting to interrupt psm fails. --- input/manager.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 9f8dcf66..51085279 100644 --- a/input/manager.c +++ b/input/manager.c @@ -226,6 +226,9 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) goto failed; } + g_io_channel_close(chan); + g_io_channel_unref(chan); + extract_hid_record(pr->hid_recs->data, &hidp); if (pr->pnp_recs) extract_pnp_record(pr->pnp_recs->data, &hidp); @@ -261,8 +264,6 @@ failed: cleanup: g_io_channel_close(pr->ctrl_channel); g_io_channel_unref(pr->ctrl_channel); - g_io_channel_close(chan); - g_io_channel_unref(chan); pending_req_free(pr); if (hidp.rd_data) -- cgit From f85b9560ece47c94ec82466cba9c44da715591d9 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 7 May 2008 18:39:36 +0000 Subject: Make bt_l2cap_connect to take mtu as paramter. --- input/device.c | 4 ++-- input/manager.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 348622e6..b27800e4 100644 --- a/input/device.c +++ b/input/device.c @@ -605,7 +605,7 @@ static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) idev->ctrl_sk = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, 0, interrupt_connect_cb, idev); if (err < 0) { error("L2CAP connect failed:%s (%d)", strerror(-err), -err); @@ -766,7 +766,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, 0, control_connect_cb, idev); if (err < 0) { error("L2CAP connect failed: %s(%d)", strerror(-err), -err); diff --git a/input/manager.c b/input/manager.c index 51085279..1c024c9c 100644 --- a/input/manager.c +++ b/input/manager.c @@ -283,7 +283,7 @@ static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) pr->ctrl_channel = chan; /* Connect to the HID interrupt channel */ - err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, 0, interrupt_connect_cb, pr); if (err < 0) { error("L2CAP connect failed:%s (%d)", strerror(-err), -err); @@ -317,7 +317,7 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) dbus_message_unref(reply); - err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, 0, control_connect_cb, pr); if (err < 0) { error("L2CAP connect failed:%s (%d)", strerror(-err), -err); @@ -391,7 +391,7 @@ static void hid_record_cb(sdp_list_t *recs, int err, gpointer user_data) } /* No encryption or link key already exists -- connect control channel */ - err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, 0, control_connect_cb, pr); if (err < 0) { error("L2CAP connect failed:%s (%d)", strerror(-err), -err); -- cgit From 2af3c3a7ddc43577c067892cdfdc06dc4e63386c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 8 May 2008 17:24:48 +0000 Subject: Remove service daemon activation handling --- input/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index d8236ada..a98bc72f 100644 --- a/input/main.c +++ b/input/main.c @@ -55,15 +55,19 @@ static int input_init(void) return -EIO; } - register_uuids("input", uuids); + register_service("input"); - register_external_service(conn, "input", "Input service", ""); + register_uuids("input", uuids); return 0; } static void input_exit(void) { + unregister_uuids("input"); + + unregister_service("input"); + input_manager_exit(); dbus_connection_unref(conn); -- cgit From b5514e6c7f0258da455bbde02482fbcdb29d4442 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 8 May 2008 18:37:09 +0000 Subject: Register service and UUIDs in one step --- input/main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index a98bc72f..c9432c21 100644 --- a/input/main.c +++ b/input/main.c @@ -55,17 +55,13 @@ static int input_init(void) return -EIO; } - register_service("input"); - - register_uuids("input", uuids); + register_service("input", uuids); return 0; } static void input_exit(void) { - unregister_uuids("input"); - unregister_service("input"); input_manager_exit(); -- cgit From 44a204a75880c342c3ac9066072f102f773a539a Mon Sep 17 00:00:00 2001 From: Cidorvan Leite Date: Thu, 8 May 2008 19:58:35 +0000 Subject: Removed function not used. --- input/device.c | 63 ---------------------------------------------------------- input/device.h | 3 --- 2 files changed, 66 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index b27800e4..ab4e59c7 100644 --- a/input/device.c +++ b/input/device.c @@ -1068,69 +1068,6 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } -int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, - GIOFunc cb, void *data) -{ - GIOChannel *io; - struct sockaddr_l2 addr; - struct l2cap_options opts; - int sk, err; - - sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (sk < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, src); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) - goto failed; - - if (set_nonblocking(sk) < 0) - goto failed; - - memset(&opts, 0, sizeof(opts)); -#if 0 - opts.imtu = HIDP_DEFAULT_MTU; - opts.omtu = HIDP_DEFAULT_MTU; - opts.flush_to = 0xffff; - - if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) - goto failed; -#endif - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, dst); - addr.l2_psm = htobs(psm); - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, FALSE); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - if (!(errno == EAGAIN || errno == EINPROGRESS)) { - g_io_channel_unref(io); - goto failed; - } - - g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) cb, data); - } else - cb(io, G_IO_OUT, data); - - g_io_channel_unref(io); - - return 0; - -failed: - err = errno; - close(sk); - errno = err; - - return -1; -} - static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; diff --git a/input/device.h b/input/device.h index aef4a915..00f56df6 100644 --- a/input/device.h +++ b/input/device.h @@ -48,6 +48,3 @@ gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst); int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk); int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst); int input_device_connadd(bdaddr_t *src, bdaddr_t *dst); - -int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, - unsigned short psm, GIOFunc cb, void *data); -- cgit From e7d668ac9e813bc9922ee7d771848bd8822d5d1f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 8 May 2008 20:23:45 +0000 Subject: Move D-Bus watch functions into libgdbus --- input/Makefile.am | 4 ++-- input/device.c | 2 -- input/main.c | 3 ++- input/manager.c | 1 - input/server.c | 3 ++- 5 files changed, 6 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 52a46a74..a514b629 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -10,12 +10,12 @@ libinput_la_SOURCES = main.c \ fakehid.c fakehid.h LDADD = $(top_builddir)/common/libhelper.a \ - @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ + @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ endif AM_LDFLAGS = -module -avoid-version -export-symbols-regex bluetooth_plugin_desc -AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid diff --git a/input/device.c b/input/device.c index ab4e59c7..151ce08c 100644 --- a/input/device.c +++ b/input/device.c @@ -40,10 +40,8 @@ #include #include - #include -#include "dbus.h" #include "dbus-helper.h" #include "logging.h" #include "textfile.h" diff --git a/input/main.c b/input/main.c index c9432c21..b57286b2 100644 --- a/input/main.c +++ b/input/main.c @@ -29,7 +29,8 @@ #include -#include "dbus.h" +#include +#include #include "plugin.h" #include "dbus-service.h" diff --git a/input/manager.c b/input/manager.c index 1c024c9c..11e14514 100644 --- a/input/manager.c +++ b/input/manager.c @@ -42,7 +42,6 @@ #include -#include "dbus.h" #include "dbus-helper.h" #include "logging.h" #include "textfile.h" diff --git a/input/server.c b/input/server.c index ff7cdbfd..5e29e99f 100644 --- a/input/server.c +++ b/input/server.c @@ -38,13 +38,14 @@ #include #include +#include #include "logging.h" -#include "dbus.h" #include "device.h" #include "server.h" #include "storage.h" +#include "dbus-helper.h" #include "dbus-service.h" static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; -- cgit From 15ea15b3a752f0487bc50d0ea04925f1b9d33dcb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 8 May 2008 22:19:14 +0000 Subject: Move D-Bus object and interface helpers into libgdbus --- input/device.c | 2 +- input/manager.c | 3 +-- input/server.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 151ce08c..1975be16 100644 --- a/input/device.c +++ b/input/device.c @@ -41,8 +41,8 @@ #include #include +#include -#include "dbus-helper.h" #include "logging.h" #include "textfile.h" #include "uinput.h" diff --git a/input/manager.c b/input/manager.c index 11e14514..618641f1 100644 --- a/input/manager.c +++ b/input/manager.c @@ -39,10 +39,9 @@ #include #include - #include +#include -#include "dbus-helper.h" #include "logging.h" #include "textfile.h" diff --git a/input/server.c b/input/server.c index 5e29e99f..ea7139ec 100644 --- a/input/server.c +++ b/input/server.c @@ -39,13 +39,13 @@ #include #include +#include #include "logging.h" #include "device.h" #include "server.h" #include "storage.h" -#include "dbus-helper.h" #include "dbus-service.h" static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; -- cgit From f3c0a1a49b0b505b8543b5b3405bd62126be1a24 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 9 May 2008 09:16:32 +0000 Subject: Use -no-undefined for linking plugins --- input/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index a514b629..68132fea 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -13,7 +13,8 @@ LDADD = $(top_builddir)/common/libhelper.a \ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ endif -AM_LDFLAGS = -module -avoid-version -export-symbols-regex bluetooth_plugin_desc +AM_LDFLAGS = -module -avoid-version -no-undefined \ + -export-symbols-regex bluetooth_plugin_desc AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ -- cgit From 2ce4523624b67b48da037beceffe5710144850ec Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 14 May 2008 21:49:07 +0000 Subject: Add support for IdleTimeout config option --- input/device.c | 21 +++++++++++++-------- input/main.c | 26 +++++++++++++++++++++++++- input/manager.c | 17 +++++++++++++++-- input/manager.h | 2 +- 4 files changed, 54 insertions(+), 12 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 1975be16..131e626d 100644 --- a/input/device.c +++ b/input/device.c @@ -67,6 +67,7 @@ struct device; struct device { bdaddr_t src; bdaddr_t dst; + int timeout; char *name; uint8_t major; uint8_t minor; @@ -84,7 +85,8 @@ struct device { GSList *devices = NULL; -static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) +static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, + uint8_t subclass, int timeout) { struct device *idev; uint32_t cls; @@ -105,6 +107,7 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) bacpy(&idev->src, src); bacpy(&idev->dst, dst); + idev->timeout = timeout; read_device_name(src, dst, &idev->name); @@ -498,11 +501,11 @@ static guint create_watch(int sk, GIOFunc cb, struct device *idev) } static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, - int ctrl_sk, int intr_sk, const char *name) + int ctrl_sk, int intr_sk, int timeout, const char *name) { struct hidp_connadd_req req; char addr[18]; - int ctl, err, timeout = 30; + int ctl, err; ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { @@ -516,7 +519,7 @@ static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, req.ctrl_sock = ctrl_sk; req.intr_sock = intr_sk; req.flags = 0; - req.idle_to = timeout * 60; + req.idle_to = timeout; err = get_stored_device_info(src, dst, &req); if (err < 0) { @@ -561,7 +564,8 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) idev->intr_sk = g_io_channel_unix_get_fd(chan); err = hidp_connadd(&idev->src, &idev->dst, - idev->ctrl_sk, idev->intr_sk, idev->name); + idev->ctrl_sk, idev->intr_sk, + idev->timeout, idev->name); if (err < 0) goto failed; @@ -964,7 +968,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, const char *path; int err; - idev = device_new(src, dst, hid->subclass); + idev = device_new(src, dst, hid->subclass, hid->idle_to); if (!idev) return -EINVAL; @@ -994,7 +998,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, const char *path; int err; - idev = device_new(src, dst, 0); + idev = device_new(src, dst, 0, 0); if (!idev) return -EINVAL; @@ -1165,7 +1169,8 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) fake->priv = fake_hid; err = fake_hid_connadd(fake, idev->intr_sk, fake_hid); } else - err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); + err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, + idev->timeout, idev->name); if (err < 0) goto error; diff --git a/input/main.c b/input/main.c index b57286b2..6018cf7e 100644 --- a/input/main.c +++ b/input/main.c @@ -34,6 +34,7 @@ #include "plugin.h" #include "dbus-service.h" +#include "logging.h" #include "manager.h" #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" @@ -45,17 +46,40 @@ static const char *uuids[] = { static DBusConnection *conn; +static GKeyFile *load_config_file(const char *file) +{ + GKeyFile *keyfile; + GError *err = NULL; + + keyfile = g_key_file_new(); + + if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { + error("Parsing %s failed: %s", file, err->message); + g_error_free(err); + g_key_file_free(keyfile); + return NULL; + } + + return keyfile; +} + static int input_init(void) { + GKeyFile *config; + conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (conn == NULL) return -EIO; - if (input_manager_init(conn) < 0) { + config = load_config_file(CONFIGDIR "/input.conf"); + + if (input_manager_init(conn, config) < 0) { dbus_connection_unref(conn); return -EIO; } + g_key_file_free(config); + register_service("input", uuids); return 0; diff --git a/input/manager.c b/input/manager.c index 618641f1..13ca178d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -63,6 +63,8 @@ struct pending_req { GIOChannel *ctrl_channel; }; +static int idle_timeout = 0; + static GSList *device_paths = NULL; /* Input registered paths */ static DBusConnection *connection = NULL; @@ -227,6 +229,8 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) g_io_channel_close(chan); g_io_channel_unref(chan); + hidp.idle_to = idle_timeout * 60; + extract_hid_record(pr->hid_recs->data, &hidp); if (pr->pnp_recs) extract_pnp_record(pr->pnp_recs->data, &hidp); @@ -753,9 +757,18 @@ static DBusSignalVTable manager_signals[] = { { NULL, NULL } }; -int input_manager_init(DBusConnection *conn) +int input_manager_init(DBusConnection *conn, GKeyFile *config) { - dbus_connection_set_exit_on_disconnect(conn, TRUE); + GError *err = NULL; + + if (config) { + idle_timeout = g_key_file_get_integer(config, "General", + "IdleTimeout", &err); + if (err) { + debug("input.conf: %s", err->message); + g_error_free(err); + } + } if (!dbus_connection_create_object_path(conn, INPUT_PATH, NULL, manager_unregister)) { diff --git a/input/manager.h b/input/manager.h index cccff683..8f9d999e 100644 --- a/input/manager.h +++ b/input/manager.h @@ -24,5 +24,5 @@ #define INPUT_PATH "/org/bluez/input" #define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" -int input_manager_init(DBusConnection *conn); +int input_manager_init(DBusConnection *conn, GKeyFile *config); void input_manager_exit(void); -- cgit From 0094809955895c974fbe95f2d3ed13f420a6a6ed Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 14 May 2008 22:16:16 +0000 Subject: Make bt_io_callback_t to take both source and destination. --- input/device.c | 9 ++++++--- input/manager.c | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 131e626d..04cabb0f 100644 --- a/input/device.c +++ b/input/device.c @@ -371,7 +371,8 @@ failed: return FALSE; } -static void rfcomm_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; struct fake_input *fake; @@ -553,7 +554,8 @@ cleanup: return err; } -static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; @@ -594,7 +596,8 @@ cleanup: idev->pending_connect = NULL; } -static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void control_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; diff --git a/input/manager.c b/input/manager.c index 13ca178d..9ed1f195 100644 --- a/input/manager.c +++ b/input/manager.c @@ -212,7 +212,9 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void interrupt_connect_cb(GIOChannel *chan, int err, + const bdaddr_t *src, const bdaddr_t *dst, + gpointer user_data) { struct pending_req *pr = user_data; struct hidp_connadd_req hidp; @@ -272,7 +274,8 @@ cleanup: g_free(hidp.rd_data); } -static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void control_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct pending_req *pr = user_data; -- cgit From aacac39879203869ff190be2df7a6f0556ced060 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 15 May 2008 02:25:47 +0000 Subject: Fix key file handling if config file doesn't exist --- input/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 6018cf7e..49252ea1 100644 --- a/input/main.c +++ b/input/main.c @@ -78,7 +78,8 @@ static int input_init(void) return -EIO; } - g_key_file_free(config); + if (config) + g_key_file_free(config); register_service("input", uuids); -- cgit From 16ac1a8c833c201e45a59940c7e6073664c1fab5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 15 May 2008 15:19:39 +0000 Subject: Add sample for input.conf file --- input/Makefile.am | 2 +- input/input.conf | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 input/input.conf (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 68132fea..942e4be2 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -20,6 +20,6 @@ AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -EXTRA_DIST = input-api.txt test-input +EXTRA_DIST = input.conf input-api.txt test-input MAINTAINERCLEANFILES = Makefile.in diff --git a/input/input.conf b/input/input.conf new file mode 100644 index 00000000..abfb64f2 --- /dev/null +++ b/input/input.conf @@ -0,0 +1,9 @@ +# Configuration file for the input service + +# This section contains options which are not specific to any +# particular interface +[General] + +# Set idle timeout (in minutes) before the connection will +# be disconnect (defaults to 0 for no timeout) +#IdleTimeout=30 -- cgit From bac8b236123c94ef6e7b723a7c920499f90014aa Mon Sep 17 00:00:00 2001 From: Cidorvan Leite Date: Thu, 15 May 2008 22:34:08 +0000 Subject: Input listen clean up --- input/server.c | 85 +++++++++++++--------------------------------------------- 1 file changed, 19 insertions(+), 66 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index ea7139ec..c4fa857d 100644 --- a/input/server.c +++ b/input/server.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ #include "server.h" #include "storage.h" #include "dbus-service.h" +#include "glib-helper.h" static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; @@ -166,86 +168,35 @@ fallback: return 0; } -static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) +static void connect_event_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer data) { - struct sockaddr_l2 addr; - socklen_t addrlen; - bdaddr_t src, dst; - unsigned char psm; - int sk, nsk; + int sk, psm = GPOINTER_TO_UINT(data); - sk = g_io_channel_unix_get_fd(chan); - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - - nsk = accept(sk, (struct sockaddr *) &addr, &addrlen); - if (nsk < 0) - return TRUE; - - bacpy(&dst, &addr.l2_bdaddr); - psm = btohs(addr.l2_psm); - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - - if (getsockname(nsk, (struct sockaddr *) &addr, &addrlen) < 0) { - close(nsk); - return TRUE; + if (err < 0) { + error("accept: %s (%d)", strerror(-err), -err); + return; } - bacpy(&src, &addr.l2_bdaddr); + sk = g_io_channel_unix_get_fd(chan); debug("Incoming connection on PSM %d", psm); - if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { + if (input_device_set_channel(src, dst, psm, sk) < 0) { /* Send unplug virtual cable to unknown devices */ if (psm == L2CAP_PSM_HIDP_CTRL) { unsigned char unplug[] = { 0x15 }; int err; - err = write(nsk, unplug, sizeof(unplug)); + err = write(sk, unplug, sizeof(unplug)); } - close(nsk); - return TRUE; - } - - if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(&src, &dst) < 0)) - input_device_close_channels(&src, &dst); - - return TRUE; -} - -static GIOChannel *setup_l2cap(unsigned int psm) -{ - GIOChannel *io; - struct sockaddr_l2 addr; - int sk; - - sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (sk < 0) - return NULL; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, BDADDR_ANY); - addr.l2_psm = htobs(psm); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(sk); - return NULL; - } - - if (listen(sk, 10) < 0) { - close(sk); - return NULL; + return; } - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, TRUE); - - g_io_add_watch(io, G_IO_IN, connect_event, NULL); + if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(src, dst) < 0)) + input_device_close_channels(src, dst); - return io; + return; } static GIOChannel *ctrl_io = NULL; @@ -253,14 +204,16 @@ static GIOChannel *intr_io = NULL; int server_start(DBusConnection *conn) { - ctrl_io = setup_l2cap(L2CAP_PSM_HIDP_CTRL); + ctrl_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_CTRL, 0, 0, + connect_event_cb, (void *) L2CAP_PSM_HIDP_CTRL); if (!ctrl_io) { error("Failed to listen on control channel"); return -1; } g_io_channel_set_close_on_unref(ctrl_io, TRUE); - intr_io = setup_l2cap(L2CAP_PSM_HIDP_INTR); + intr_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_INTR, 0, 0, + connect_event_cb, (void *) L2CAP_PSM_HIDP_INTR); if (!intr_io) { error("Failed to listen on interrupt channel"); g_io_channel_unref(ctrl_io); -- cgit From aa82d089f929c270f323d2a0dc04598df0f4d3ae Mon Sep 17 00:00:00 2001 From: Cidorvan Leite Date: Thu, 15 May 2008 22:41:31 +0000 Subject: Removed casts from user data --- input/server.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index c4fa857d..48ffd7fd 100644 --- a/input/server.c +++ b/input/server.c @@ -205,7 +205,8 @@ static GIOChannel *intr_io = NULL; int server_start(DBusConnection *conn) { ctrl_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_CTRL, 0, 0, - connect_event_cb, (void *) L2CAP_PSM_HIDP_CTRL); + connect_event_cb, + GUINT_TO_POINTER(L2CAP_PSM_HIDP_CTRL)); if (!ctrl_io) { error("Failed to listen on control channel"); return -1; @@ -213,7 +214,8 @@ int server_start(DBusConnection *conn) g_io_channel_set_close_on_unref(ctrl_io, TRUE); intr_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_INTR, 0, 0, - connect_event_cb, (void *) L2CAP_PSM_HIDP_INTR); + connect_event_cb, + GUINT_TO_POINTER(L2CAP_PSM_HIDP_INTR)); if (!intr_io) { error("Failed to listen on interrupt channel"); g_io_channel_unref(ctrl_io); -- cgit From dcada8eed787ddcca19634f5a71a4dd0a2dc1856 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 15 May 2008 22:49:02 +0000 Subject: Fix wrong usage of non const bdaddr_t --- input/device.c | 6 +++--- input/device.h | 4 ++-- input/server.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 04cabb0f..aa0689d0 100644 --- a/input/device.c +++ b/input/device.c @@ -1073,7 +1073,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } -static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) +static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst) { struct device *idev; GSList *list; @@ -1097,7 +1097,7 @@ gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst) return TRUE; } -int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) +int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, int nsk) { struct device *idev = find_device(src, dst); if (!idev) @@ -1115,7 +1115,7 @@ int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) return 0; } -int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst) +int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst) { struct device *idev = find_device(src, dst); if (!idev) diff --git a/input/device.h b/input/device.h index 00f56df6..c9296ad0 100644 --- a/input/device.h +++ b/input/device.h @@ -45,6 +45,6 @@ int input_device_unregister(DBusConnection *conn, const char *path); gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst); -int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk); -int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst); +int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, int nsk); +int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst); int input_device_connadd(bdaddr_t *src, bdaddr_t *dst); diff --git a/input/server.c b/input/server.c index 48ffd7fd..976b8522 100644 --- a/input/server.c +++ b/input/server.c @@ -122,7 +122,7 @@ static void auth_callback(DBusError *derr, void *user_data) g_free(auth); } -static int authorize_device(bdaddr_t *src, bdaddr_t *dst) +static int authorize_device(const bdaddr_t *src, const bdaddr_t *dst) { struct authorization_data *auth; DBusMessage *msg; -- cgit From 4de66ff306262950a6da54399cef89a9134247f0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 16 May 2008 09:30:18 +0000 Subject: Use EACCES instead of ENOKEY --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index aa0689d0..1794cf58 100644 --- a/input/device.c +++ b/input/device.c @@ -530,7 +530,7 @@ static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, if (req.subclass & 0x40) { err = encrypt_link(src, dst); - if (err < 0 && err != -ENOKEY) + if (err < 0 && err != -EACCES) goto cleanup; } -- cgit From fd9b76b9b1e225da8c8d5626fd5cca8e2b78158d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 12:19:50 +0000 Subject: Convert input manager to use gdbus API --- input/manager.c | 119 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 56 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index 9ed1f195..c5e075cc 100644 --- a/input/manager.c +++ b/input/manager.c @@ -510,11 +510,34 @@ fail: pending_req_free(pr); } -static DBusHandlerResult create_device(DBusConnection *conn, +static inline DBusMessage *adapter_not_available(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", + "Adapter not available"); +} + +static inline DBusMessage *already_exists(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists", + "Input Already exists"); +} + +static inline DBusMessage *not_supported(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".NotSupported", + "Not supported"); +} + +static inline DBusMessage *does_not_exist(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists", + "Input doesn't exist"); +} + +static DBusMessage *create_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct pending_req *pr; - DBusError derr; const char *addr; bdaddr_t src, dst; uint32_t cls = 0; @@ -522,39 +545,34 @@ static DBusHandlerResult create_device(DBusConnection *conn, uuid_t uuid; bt_callback_t cb; - dbus_error_init(&derr); - if (!dbus_message_get_args(msg, &derr, - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_INVALID)) { - error_invalid_arguments(conn, msg, derr.message); - dbus_error_free(&derr); - return DBUS_HANDLER_RESULT_HANDLED; - } + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID)) + return NULL; /* Get the default adapter */ dev_id = hci_get_route(NULL); if (dev_id < 0) { error("Bluetooth adapter not available"); - return error_failed(conn, msg, "Adapter not available"); + return adapter_not_available(msg); } if (hci_devba(dev_id, &src) < 0) { error("Can't get local adapter device info"); - return error_failed(conn, msg, "Adapter not available"); + return adapter_not_available(msg); } str2ba(addr, &dst); if (input_device_is_registered(&src, &dst)) - return error_already_exists(conn, msg, "Input Already exists"); + return already_exists(msg); if (read_device_class(&src, &dst, &cls) < 0) { error("Device class not available"); - return error_not_supported(conn, msg); + return not_supported(msg); } pr = pending_req_new(conn, msg, &src, &dst); if (!pr) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return NULL; switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ @@ -568,57 +586,51 @@ static DBusHandlerResult create_device(DBusConnection *conn, break; default: pending_req_free(pr); - return error_not_supported(conn, msg); + return not_supported(msg); } err = bt_search_service(&src, &dst, &uuid, cb, pr, NULL); if (err < 0) { pending_req_free(pr); - return error_not_supported(conn, msg); + return not_supported(msg); } - return DBUS_HANDLER_RESULT_HANDLED; + return NULL; } -static DBusHandlerResult remove_device(DBusConnection *conn, +static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessage *reply; - DBusError derr; GSList *l; const char *path; int err; - dbus_error_init(&derr); - if (!dbus_message_get_args(msg, &derr, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID)) { - error_invalid_arguments(conn, msg, derr.message); - dbus_error_free(&derr); - return DBUS_HANDLER_RESULT_HANDLED; - } + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID)) + return NULL; l = g_slist_find_custom(device_paths, path, (GCompareFunc) strcmp); if (!l) - return error_does_not_exist(conn, msg, "Input doesn't exist"); + return does_not_exist(msg); reply = dbus_message_new_method_return(msg); if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return NULL; err = input_device_unregister(conn, path); if (err < 0) { dbus_message_unref(reply); - return error_failed_errno(conn, msg, -err); + return create_errno_message(msg, -err); } g_free(l->data); device_paths = g_slist_remove(device_paths, l->data); - return send_message_and_unref(conn, reply); + return reply; } -static DBusHandlerResult list_devices(DBusConnection *conn, +static DBusMessage *list_devices(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter, iter_array; @@ -627,7 +639,7 @@ static DBusHandlerResult list_devices(DBusConnection *conn, reply = dbus_message_new_method_return(msg); if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, @@ -641,10 +653,10 @@ static DBusHandlerResult list_devices(DBusConnection *conn, dbus_message_iter_close_container(&iter, &iter_array); - return send_message_and_unref(conn, reply); + return reply; } -static void manager_unregister(DBusConnection *conn, void *data) +static void manager_unregister(void *data) { info("Unregistered manager path"); @@ -746,18 +758,20 @@ static void register_stored_inputs(void) closedir(dir); } -static DBusMethodVTable manager_methods[] = { - { "ListDevices", list_devices, "", "as" }, - { "CreateDevice", create_device, "s", "s" }, - { "CreateSecureDevice", create_device, "s", "s" }, - { "RemoveDevice", remove_device, "s", "" }, - { NULL, NULL, NULL, NULL }, +static GDBusMethodTable manager_methods[] = { + { "ListDevices", "", "as", list_devices }, + { "CreateDevice", "s", "s", create_device, + G_DBUS_METHOD_FLAG_ASYNC }, + { "CreateSecureDevice", "s", "s", create_device, + G_DBUS_METHOD_FLAG_ASYNC }, + { "RemoveDevice", "s", "", remove_device }, + { } }; -static DBusSignalVTable manager_signals[] = { +static GDBusSignalTable manager_signals[] = { { "DeviceCreated", "s" }, { "DeviceRemoved", "s" }, - { NULL, NULL } + { } }; int input_manager_init(DBusConnection *conn, GKeyFile *config) @@ -773,19 +787,11 @@ int input_manager_init(DBusConnection *conn, GKeyFile *config) } } - if (!dbus_connection_create_object_path(conn, INPUT_PATH, - NULL, manager_unregister)) { - error("D-Bus failed to register %s path", INPUT_PATH); - return -1; - } - - if (!dbus_connection_register_interface(conn, INPUT_PATH, - INPUT_MANAGER_INTERFACE, - manager_methods, - manager_signals, NULL)) { + if (g_dbus_register_interface(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, + manager_methods, manager_signals, NULL, + NULL, manager_unregister) == FALSE) { error("Failed to register %s interface to %s", INPUT_MANAGER_INTERFACE, INPUT_PATH); - dbus_connection_destroy_object_path(connection, INPUT_PATH); return -1; } @@ -803,7 +809,8 @@ int input_manager_init(DBusConnection *conn, GKeyFile *config) void input_manager_exit(void) { - dbus_connection_destroy_object_path(connection, INPUT_PATH); + g_dbus_unregister_interface(connection, INPUT_PATH, + INPUT_MANAGER_INTERFACE); server_stop(); -- cgit From ee47f9f75ecc4ea8756f9b301905ec7de5ac07a3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 18:05:38 +0000 Subject: Use message sending helpers --- input/manager.c | 22 +++++----------------- input/server.c | 4 ++-- 2 files changed, 7 insertions(+), 19 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index c5e075cc..b65ccb16 100644 --- a/input/manager.c +++ b/input/manager.c @@ -218,7 +218,6 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, { struct pending_req *pr = user_data; struct hidp_connadd_req hidp; - DBusMessage *reply; const char *path; memset(&hidp, 0, sizeof(hidp)); @@ -252,16 +251,11 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, device_paths = g_slist_append(device_paths, g_strdup(path)); - /* Replying to the requestor */ - reply = dbus_message_new_method_return(pr->msg); - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(pr->conn, reply); + g_dbus_send_reply(pr->conn, pr->msg, DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); goto cleanup; + failed: error_connection_attempt_failed(pr->conn, pr->msg, err); @@ -447,7 +441,6 @@ fail: static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct pending_req *pr = user_data; - DBusMessage *reply; sdp_record_t *rec; sdp_list_t *protos; const char *path; @@ -498,13 +491,8 @@ static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data) device_paths = g_slist_append(device_paths, g_strdup(path)); - reply = dbus_message_new_method_return(pr->msg); - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(pr->conn, reply); + g_dbus_send_reply(pr->conn, pr->msg, DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); fail: pending_req_free(pr); diff --git a/input/server.c b/input/server.c index 976b8522..f5861635 100644 --- a/input/server.c +++ b/input/server.c @@ -50,7 +50,7 @@ #include "dbus-service.h" #include "glib-helper.h" -static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; +static const char *HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; static DBusConnection *connection = NULL; @@ -71,7 +71,7 @@ static void cancel_authorization(const char *addr) DBUS_TYPE_STRING, &HID_UUID, DBUS_TYPE_INVALID); - send_message_and_unref(connection, msg); + g_dbus_send_message(connection, msg); } struct authorization_data { -- cgit From e8961085b8d3dabc5550a4f1b309ae06065d14b4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 18:16:17 +0000 Subject: Convert the input device handling to gdbus API --- input/device.c | 187 ++++++++++++++++++++++---------------------------------- input/manager.c | 13 +--- 2 files changed, 77 insertions(+), 123 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 1794cf58..1a8e0eee 100644 --- a/input/device.c +++ b/input/device.c @@ -402,7 +402,7 @@ static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, /* Replying to the requestor */ reply = dbus_message_new_method_return(idev->pending_connect); - send_message_and_unref(idev->conn, reply); + g_dbus_send_message(idev->conn, reply); /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect); @@ -545,6 +545,7 @@ static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, } err = ioctl(ctl, HIDPCONNADD, &req); + cleanup: close(ctl); @@ -580,8 +581,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, DBUS_TYPE_INVALID); /* Replying to the requestor */ - send_message_and_unref(idev->conn, - dbus_message_new_method_return(idev->pending_connect)); + g_dbus_send_reply(idev->conn, idev->pending_connect, DBUS_TYPE_INVALID); goto cleanup; @@ -698,6 +698,7 @@ static int disconnect(struct device *idev, uint32_t flags) close(ctl); return 0; + fail: err = errno; close(ctl); @@ -736,10 +737,28 @@ static int is_connected(struct device *idev) return 1; } +static inline DBusMessage *in_progress(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", + "Device connection already in progress"); +} + +static inline DBusMessage *already_connected(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", + "Already connected to a device"); +} + +static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", + err ? strerror(err) : "Connection attempt failed"); +} + /* * Input Device methods */ -static DBusHandlerResult device_connect(DBusConnection *conn, +static DBusMessage *device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; @@ -747,11 +766,10 @@ static DBusHandlerResult device_connect(DBusConnection *conn, int err; if (idev->pending_connect) - return error_in_progress(conn, msg, - "Device connection already in progress"); + return in_progress(msg); if (is_connected(idev)) - return error_already_connected(conn, msg); + return already_connected(msg); idev->pending_connect = dbus_message_ref(msg); @@ -763,153 +781,103 @@ static DBusHandlerResult device_connect(DBusConnection *conn, error("Connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, - msg, err); + return connection_attempt_failed(msg, err); } fake->flags |= FI_FLAG_CONNECTED; - return DBUS_HANDLER_RESULT_HANDLED; + return NULL; } /* HID devices */ - err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, 0, - control_connect_cb, idev); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + 0, control_connect_cb, idev); if (err < 0) { error("L2CAP connect failed: %s(%d)", strerror(-err), -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, msg, -err); + return connection_attempt_failed(msg, -err); } - return DBUS_HANDLER_RESULT_HANDLED; + return NULL; } -static DBusHandlerResult device_disconnect(DBusConnection *conn, +static DBusMessage *device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; + int err; - if (disconnect(idev, 0) < 0) - return error_failed_errno(conn, msg, errno); + err = disconnect(idev, 0); + if (err < 0) + return create_errno_message(msg, -err); - /* Replying to the requestor */ - return send_message_and_unref(conn, - dbus_message_new_method_return(msg)); + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static DBusHandlerResult device_is_connected(DBusConnection *conn, +static DBusMessage *device_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; - dbus_bool_t connected; - - connected = is_connected(idev); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + dbus_bool_t connected = is_connected(idev); - dbus_message_append_args(reply, - DBUS_TYPE_BOOLEAN, &connected, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_adapter(DBusConnection *conn, +static DBusMessage *device_get_adapter(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; char addr[18]; const char *paddr = addr; ba2str(&idev->src, addr); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_address(DBusConnection *conn, +static DBusMessage *device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; char addr[18]; const char *paddr = addr; ba2str(&idev->dst, addr); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_name(DBusConnection *conn, +static DBusMessage *device_get_name(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; const char *pname = (idev->name ? idev->name : ""); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &pname, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &pname, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_product_id(DBusConnection *conn, +static DBusMessage *device_get_product_id(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->product, - DBUS_TYPE_INVALID); - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->product, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, +static DBusMessage *device_get_vendor_id(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->vendor, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->vendor, + DBUS_TYPE_INVALID); } -static void device_unregister(DBusConnection *conn, void *data) +static void device_unregister(void *data) { struct device *idev = data; @@ -918,22 +886,23 @@ static void device_unregister(DBusConnection *conn, void *data) device_free(idev); } -static DBusMethodVTable device_methods[] = { - { "Connect", device_connect, "", "" }, - { "Disconnect", device_disconnect, "", "" }, - { "IsConnected", device_is_connected, "", "b" }, - { "GetAdapter", device_get_adapter, "", "s" }, - { "GetAddress", device_get_address, "", "s" }, - { "GetName", device_get_name, "", "s" }, - { "GetProductId", device_get_product_id, "", "q" }, - { "GetVendorId", device_get_vendor_id, "", "q" }, - { NULL, NULL, NULL, NULL } +static GDBusMethodTable device_methods[] = { + { "Connect", "", "", device_connect, + G_DBUS_METHOD_FLAG_ASYNC }, + { "Disconnect", "", "", device_disconnect }, + { "IsConnected", "", "b", device_is_connected }, + { "GetAdapter", "", "s", device_get_adapter }, + { "GetAddress", "", "s", device_get_address }, + { "GetName", "", "s", device_get_name }, + { "GetProductId", "", "q", device_get_product_id }, + { "GetVendorId", "", "q", device_get_vendor_id }, + { } }; -static DBusSignalVTable device_signals[] = { +static GDBusSignalTable device_signals[] = { { "Connected", "" }, { "Disconnected", "" }, - { NULL, NULL } + { } }; /* @@ -941,19 +910,11 @@ static DBusSignalVTable device_signals[] = { */ static int register_path(DBusConnection *conn, const char *path, struct device *idev) { - if (!dbus_connection_create_object_path(conn, path, - idev, device_unregister)) { - error("Input device path registration failed"); - return -EINVAL; - } - - if (!dbus_connection_register_interface(conn, path, - INPUT_DEVICE_INTERFACE, - device_methods, - device_signals, NULL)) { + if (g_dbus_register_interface(conn, path, INPUT_DEVICE_INTERFACE, + device_methods, device_signals, NULL, + NULL, device_unregister) == FALSE) { error("Failed to register %s interface to %s", - INPUT_DEVICE_INTERFACE, path); - dbus_connection_destroy_object_path(conn, path); + INPUT_DEVICE_INTERFACE, path); return -1; } diff --git a/input/manager.c b/input/manager.c index b65ccb16..aae101fd 100644 --- a/input/manager.c +++ b/input/manager.c @@ -332,7 +332,7 @@ static int create_bonding(struct pending_req *pr) char address[18], *addr_ptr = address; msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, - "org.bluez.Adapter", "CreateBonding"); + "org.bluez.Adapter", "CreateBonding"); if (!msg) { error("Unable to allocate new method call"); return -1; @@ -589,7 +589,6 @@ static DBusMessage *create_device(DBusConnection *conn, static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg, void *data) { - DBusMessage *reply; GSList *l; const char *path; int err; @@ -602,20 +601,14 @@ static DBusMessage *remove_device(DBusConnection *conn, if (!l) return does_not_exist(msg); - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - err = input_device_unregister(conn, path); - if (err < 0) { - dbus_message_unref(reply); + if (err < 0) return create_errno_message(msg, -err); - } g_free(l->data); device_paths = g_slist_remove(device_paths, l->data); - return reply; + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static DBusMessage *list_devices(DBusConnection *conn, -- cgit From c71805ac4bd1bd85d1d0dfc31a200a26d43a9a14 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 18:43:59 +0000 Subject: Don't forget user data on interface registration --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 1a8e0eee..0f06d095 100644 --- a/input/device.c +++ b/input/device.c @@ -912,7 +912,7 @@ static int register_path(DBusConnection *conn, const char *path, struct device * { if (g_dbus_register_interface(conn, path, INPUT_DEVICE_INTERFACE, device_methods, device_signals, NULL, - NULL, device_unregister) == FALSE) { + idev, device_unregister) == FALSE) { error("Failed to register %s interface to %s", INPUT_DEVICE_INTERFACE, path); return -1; -- cgit From a7bc44bcbad838b8da5ab279a11075ae4f6f1418 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 19:35:53 +0000 Subject: Fix user data issue when removing device --- input/device.c | 57 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 23 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 0f06d095..b85f9cdb 100644 --- a/input/device.c +++ b/input/device.c @@ -990,12 +990,40 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, return err; } +static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst) +{ + GSList *list; + + for (list = devices; list != NULL; list = list->next) { + struct device *idev = list->data; + + if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) + return idev; + } + + return NULL; +} + +static struct device *find_device_by_path(const char *path) +{ + GSList *list; + + for (list = devices; list != NULL; list = list->next) { + struct device *idev = list->data; + + if (strcmp(idev->path, path) == 0) + return idev; + } + + return NULL; +} + int input_device_unregister(DBusConnection *conn, const char *path) { struct device *idev; - if (!dbus_connection_get_object_user_data(conn, - path, (void *) &idev) || !idev) + idev = find_device_by_path(path); + if (idev == NULL) return -EINVAL; if (idev->pending_connect) { @@ -1018,35 +1046,18 @@ int input_device_unregister(DBusConnection *conn, const char *path) if (idev->intr_watch) { g_source_remove(idev->intr_watch); dbus_connection_emit_signal(conn, - path, - INPUT_DEVICE_INTERFACE, - "Disconnected", - DBUS_TYPE_INVALID); + path, INPUT_DEVICE_INTERFACE, + "Disconnected", DBUS_TYPE_INVALID); } - dbus_connection_destroy_object_path(conn, path); - dbus_connection_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); - return 0; -} - -static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst) -{ - struct device *idev; - GSList *list; - - for (list = devices; list != NULL; list = list->next) { - idev = list->data; - - if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) - return idev; - } + g_dbus_unregister_interface(conn, path, INPUT_DEVICE_INTERFACE); - return NULL; + return 0; } gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst) -- cgit From dea62fb2e9e09e8083e126f6f177e6f85aa7b186 Mon Sep 17 00:00:00 2001 From: Cidorvan Leite Date: Tue, 27 May 2008 19:44:49 +0000 Subject: Added missing braces --- input/fakehid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'input') diff --git a/input/fakehid.c b/input/fakehid.c index 44c3ff6d..d752d85a 100644 --- a/input/fakehid.c +++ b/input/fakehid.c @@ -305,12 +305,13 @@ static int ps3remote_setup_uinput(struct fake_input *fake, fake->uinput = open("/dev/input/uinput", O_RDWR); if (fake->uinput < 0) { fake->uinput = open("/dev/uinput", O_RDWR); - if (fake->uinput < 0) + if (fake->uinput < 0) { fake->uinput = open("/dev/misc/uinput", O_RDWR); if (fake->uinput < 0) { error("Error opening uinput device file"); return 1; } + } } memset(&dev, 0, sizeof(dev)); -- cgit From 27b076bdd6b65521f9e37fc6e088ea9396105d3b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 22:03:43 +0000 Subject: Fix some handling of error cases --- input/device.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index b85f9cdb..261c1a58 100644 --- a/input/device.c +++ b/input/device.c @@ -371,6 +371,24 @@ failed: return FALSE; } +static inline DBusMessage *in_progress(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", + "Device connection already in progress"); +} + +static inline DBusMessage *already_connected(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", + "Already connected to a device"); +} + +static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", + err ? strerror(err) : "Connection attempt failed"); +} + static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer user_data) { @@ -416,8 +434,9 @@ static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, return; failed: - error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); + reply = connection_attempt_failed(idev->pending_connect, err); + g_dbus_send_message(idev->conn, reply); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; } @@ -559,6 +578,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; + DBusMessage *reply; if (err < 0) { error("connect(): %s (%d)", strerror(-err), -err); @@ -586,8 +606,9 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, goto cleanup; failed: - error_connection_attempt_failed(idev->conn, - idev->pending_connect, -err); + reply = connection_attempt_failed(idev->pending_connect, -err); + g_dbus_send_message(idev->conn, reply); + idev->intr_sk = -1; idev->ctrl_sk = -1; @@ -737,24 +758,6 @@ static int is_connected(struct device *idev) return 1; } -static inline DBusMessage *in_progress(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", - "Device connection already in progress"); -} - -static inline DBusMessage *already_connected(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", - "Already connected to a device"); -} - -static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", - err ? strerror(err) : "Connection attempt failed"); -} - /* * Input Device methods */ -- cgit From 7c426c4c7e234e28a4dffcb7d88feb0eeefcd5ce Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 28 May 2008 07:39:21 +0000 Subject: input: removed old authorization method --- input/manager.c | 2 +- input/server.c | 89 ++------------------------------------------------------- input/server.h | 2 +- 3 files changed, 4 insertions(+), 89 deletions(-) (limited to 'input') diff --git a/input/manager.c b/input/manager.c index aae101fd..65c51fb5 100644 --- a/input/manager.c +++ b/input/manager.c @@ -783,7 +783,7 @@ int input_manager_init(DBusConnection *conn, GKeyFile *config) /* Register well known HID devices */ register_stored_inputs(); - server_start(connection); + server_start(); return 0; } diff --git a/input/server.c b/input/server.c index f5861635..003ce53b 100644 --- a/input/server.c +++ b/input/server.c @@ -52,60 +52,11 @@ static const char *HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; -static DBusConnection *connection = NULL; - -static void cancel_authorization(const char *addr) -{ - DBusMessage *msg; - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", - "CancelAuthorizationRequest"); - if (!msg) { - error("Unable to allocate new method call"); - return; - } - - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_STRING, &HID_UUID, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); -} - struct authorization_data { bdaddr_t src; bdaddr_t dst; }; -static void authorization_callback(DBusPendingCall *pcall, void *data) -{ - struct authorization_data *auth = data; - DBusMessage *reply = dbus_pending_call_steal_reply(pcall); - DBusError derr; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply) != TRUE) { - dbus_message_unref(reply); - input_device_connadd(&auth->src, &auth->dst); - return; - } - - error("Authorization denied: %s", derr.message); - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - char addr[18]; - memset(addr, 0, sizeof(addr)); - ba2str(&auth->dst, addr); - cancel_authorization(addr); - } - - input_device_close_channels(&auth->src, &auth->dst); - - dbus_error_free(&derr); - dbus_message_unref(reply); -} - static void auth_callback(DBusError *derr, void *user_data) { struct authorization_data *auth = user_data; @@ -125,47 +76,13 @@ static void auth_callback(DBusError *derr, void *user_data) static int authorize_device(const bdaddr_t *src, const bdaddr_t *dst) { struct authorization_data *auth; - DBusMessage *msg; - DBusPendingCall *pending; - char addr[18]; - const char *paddr = addr; - int retval; auth = g_new0(struct authorization_data, 1); bacpy(&auth->src, src); bacpy(&auth->dst, dst); - retval = service_req_auth(src, dst, HID_UUID, + return service_req_auth(src, dst, HID_UUID, auth_callback, auth); - if (retval < 0) - goto fallback; - - return retval; - -fallback: - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "RequestAuthorization"); - if (!msg) { - error("Unable to allocate new RequestAuthorization method call"); - return -ENOMEM; - } - - memset(addr, 0, sizeof(addr)); - ba2str(dst, addr); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_STRING, &HID_UUID, - DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(connection, - msg, &pending, -1) == FALSE) - return -EACCES; - - dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free); - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - - return 0; } static void connect_event_cb(GIOChannel *chan, int err, const bdaddr_t *src, @@ -202,7 +119,7 @@ static void connect_event_cb(GIOChannel *chan, int err, const bdaddr_t *src, static GIOChannel *ctrl_io = NULL; static GIOChannel *intr_io = NULL; -int server_start(DBusConnection *conn) +int server_start(void) { ctrl_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_CTRL, 0, 0, connect_event_cb, @@ -223,8 +140,6 @@ int server_start(DBusConnection *conn) } g_io_channel_set_close_on_unref(intr_io, TRUE); - connection = conn; - return 0; } diff --git a/input/server.h b/input/server.h index 355406aa..75cf704c 100644 --- a/input/server.h +++ b/input/server.h @@ -21,5 +21,5 @@ * */ -int server_start(DBusConnection *conn); +int server_start(void); void server_stop(void); -- cgit From ba4e3484118a69f49772b7e8dba9d8a02f8dff61 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 29 May 2008 07:44:22 +0000 Subject: Add input interface driver handlers --- input/main.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 49252ea1..06a950ad 100644 --- a/input/main.c +++ b/input/main.c @@ -29,23 +29,64 @@ #include -#include -#include +#include #include "plugin.h" -#include "dbus-service.h" +#include "../hcid/device.h" #include "logging.h" +#include "dbus-service.h" #include "manager.h" -#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" +#define INPUT_INTERFACE "org.bluez.Input" + +static DBusMessage *input_connect(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static DBusMessage *input_disconnect(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static GDBusMethodTable input_methods[] = { + { "Connect", "", "", input_connect }, + { "Disconnect", "", "", input_disconnect }, + { } +}; -static const char *uuids[] = { - HID_UUID, - NULL +static GDBusSignalTable input_signals[] = { + { "Connected", "" }, + { "Disconnected", "" }, + { } }; static DBusConnection *conn; +static int input_probe(const char *path) +{ + debug("path %s", path); + + return g_dbus_register_interface(conn, path, INPUT_INTERFACE, + input_methods, input_signals, NULL, NULL, NULL); +} + +static void input_remove(const char *path) +{ + debug("path %s", path); + + g_dbus_unregister_interface(conn, path, INPUT_INTERFACE); +} + +static struct btd_device_driver input_driver = { + .name = "input", + .uuids = BTD_UUIDS("00001124-0000-1000-8000-00805f9b34fb"), + .probe = input_probe, + .remove = input_remove, +}; + static GKeyFile *load_config_file(const char *file) { GKeyFile *keyfile; @@ -81,14 +122,14 @@ static int input_init(void) if (config) g_key_file_free(config); - register_service("input", uuids); + btd_register_device_driver(&input_driver); return 0; } static void input_exit(void) { - unregister_service("input"); + btd_unregister_device_driver(&input_driver); input_manager_exit(); -- cgit From f0b4cc6f3b05f3ee1b963927acd5826ca99fa179 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 29 May 2008 09:04:32 +0000 Subject: Add missing method skeletons --- input/main.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 06a950ad..7953e4b8 100644 --- a/input/main.c +++ b/input/main.c @@ -45,15 +45,32 @@ static DBusMessage *input_connect(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } +static DBusMessage *input_cancel_connect(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + static DBusMessage *input_disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data) { return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } +static DBusMessage *input_is_connected(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + dbus_bool_t connected = FALSE; + + return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); +} + static GDBusMethodTable input_methods[] = { - { "Connect", "", "", input_connect }, - { "Disconnect", "", "", input_disconnect }, + { "Connect", "", "", input_connect }, + { "CancelConnect", "", "", input_cancel_connect }, + { "Disconnect", "", "", input_disconnect }, + { "IsConnected", "", "b", input_is_connected }, { } }; -- cgit From a93a6fa2f4091679556db6ddd65b3291592fe9c9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 29 May 2008 21:16:32 +0000 Subject: Remove CancelConnect implementation --- input/main.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 7953e4b8..990ca360 100644 --- a/input/main.c +++ b/input/main.c @@ -45,12 +45,6 @@ static DBusMessage *input_connect(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static DBusMessage *input_cancel_connect(DBusConnection *conn, - DBusMessage *msg, void *user_data) -{ - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); -} - static DBusMessage *input_disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -67,10 +61,9 @@ static DBusMessage *input_is_connected(DBusConnection *conn, } static GDBusMethodTable input_methods[] = { - { "Connect", "", "", input_connect }, - { "CancelConnect", "", "", input_cancel_connect }, - { "Disconnect", "", "", input_disconnect }, - { "IsConnected", "", "b", input_is_connected }, + { "Connect", "", "", input_connect }, + { "Disconnect", "", "", input_disconnect }, + { "IsConnected", "", "b", input_is_connected }, { } }; -- cgit From 2aab870f593da0b3ec83095e5ded93b900e4b600 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 3 Jun 2008 20:07:34 +0000 Subject: Update autoconf/automake options --- input/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 942e4be2..3d841d7c 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -1,5 +1,5 @@ -if INPUTSERVICE +if INPUTPLUGIN plugindir = $(libdir)/bluetooth/plugins plugin_LTLIBRARIES = libinput.la -- cgit From f80a7215275b229a597cf8d2bbc7e4e208af522c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 7 Jun 2008 19:30:24 +0000 Subject: Use g_dbus_emit_signal for sending D-Bus signals --- input/device.c | 14 +++++++------- input/manager.c | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'input') diff --git a/input/device.c b/input/device.c index 261c1a58..75acaa82 100644 --- a/input/device.c +++ b/input/device.c @@ -424,7 +424,7 @@ static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect); - dbus_connection_emit_signal(idev->conn, path, + g_dbus_emit_signal(idev->conn, path, INPUT_DEVICE_INTERFACE, "Connected", DBUS_TYPE_INVALID); @@ -462,7 +462,7 @@ static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data if (cond & (G_IO_HUP | G_IO_ERR)) g_io_channel_close(chan); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Disconnected", @@ -489,7 +489,7 @@ static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data if (cond & (G_IO_HUP | G_IO_ERR)) g_io_channel_close(chan); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Disconnected", @@ -594,7 +594,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Connected", @@ -1048,12 +1048,12 @@ int input_device_unregister(DBusConnection *conn, const char *path) if (idev->intr_watch) { g_source_remove(idev->intr_watch); - dbus_connection_emit_signal(conn, + g_dbus_emit_signal(conn, path, INPUT_DEVICE_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); } - dbus_connection_emit_signal(conn, INPUT_PATH, + g_dbus_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); @@ -1154,7 +1154,7 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Connected", diff --git a/input/manager.c b/input/manager.c index 65c51fb5..2dfb9b2d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -244,7 +244,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, goto cleanup; } - dbus_connection_emit_signal(pr->conn, INPUT_PATH, + g_dbus_emit_signal(pr->conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); @@ -484,7 +484,7 @@ static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data) goto fail; } - dbus_connection_emit_signal(pr->conn, INPUT_PATH, + g_dbus_emit_signal(pr->conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); -- cgit From 8bf636881f152a97727774f4f9ea2504c72dfb23 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Jun 2008 20:54:55 +0000 Subject: Use DBG in plugin to show function names --- input/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 990ca360..6b5e7c8f 100644 --- a/input/main.c +++ b/input/main.c @@ -77,7 +77,7 @@ static DBusConnection *conn; static int input_probe(const char *path) { - debug("path %s", path); + DBG("path %s", path); return g_dbus_register_interface(conn, path, INPUT_INTERFACE, input_methods, input_signals, NULL, NULL, NULL); @@ -85,7 +85,7 @@ static int input_probe(const char *path) static void input_remove(const char *path) { - debug("path %s", path); + DBG("path %s", path); g_dbus_unregister_interface(conn, path, INPUT_INTERFACE); } -- cgit From 0f62b72c8564608f849b3bbe54bf48db07c45015 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Jun 2008 21:21:54 +0000 Subject: Update plugin interface registration --- input/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 6b5e7c8f..6a667f51 100644 --- a/input/main.c +++ b/input/main.c @@ -79,8 +79,12 @@ static int input_probe(const char *path) { DBG("path %s", path); - return g_dbus_register_interface(conn, path, INPUT_INTERFACE, - input_methods, input_signals, NULL, NULL, NULL); + if (g_dbus_register_interface(conn, path, INPUT_INTERFACE, + input_methods, input_signals, NULL, + NULL, NULL) == FALSE) + return -1; + + return 0; } static void input_remove(const char *path) -- cgit From 5243ac4fd278b0176ece84cbcec537a92a9c7290 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Jun 2008 22:57:11 +0000 Subject: Update probe/remove callback and implement serial API --- input/main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'input') diff --git a/input/main.c b/input/main.c index 6a667f51..9a27a2ef 100644 --- a/input/main.c +++ b/input/main.c @@ -75,23 +75,23 @@ static GDBusSignalTable input_signals[] = { static DBusConnection *conn; -static int input_probe(const char *path) +static int input_probe(struct btd_device *device) { - DBG("path %s", path); + DBG("path %s", device->path); - if (g_dbus_register_interface(conn, path, INPUT_INTERFACE, + if (g_dbus_register_interface(conn, device->path, INPUT_INTERFACE, input_methods, input_signals, NULL, - NULL, NULL) == FALSE) + device, NULL) == FALSE) return -1; return 0; } -static void input_remove(const char *path) +static void input_remove(struct btd_device *device) { - DBG("path %s", path); + DBG("path %s", device->path); - g_dbus_unregister_interface(conn, path, INPUT_INTERFACE); + g_dbus_unregister_interface(conn, device->path, INPUT_INTERFACE); } static struct btd_device_driver input_driver = { -- cgit From e8ca2351ee3ba3f8b2b99731972234f42ae9b64b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 17 Jun 2008 19:37:36 +0000 Subject: Fix authorization mechanism for 3.x. --- input/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input') diff --git a/input/server.c b/input/server.c index 003ce53b..9267e4aa 100644 --- a/input/server.c +++ b/input/server.c @@ -64,7 +64,7 @@ static void auth_callback(DBusError *derr, void *user_data) if (derr) { error("Access denied: %s", derr->message); if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) - service_cancel_auth(&auth->dst); + service_cancel_auth(&auth->src, &auth->dst); input_device_close_channels(&auth->src, &auth->dst); } else -- cgit From a22a088109b664efdee397affed55b039cb0999b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2008 05:47:13 +0000 Subject: Don't use lib prefix for plugins --- input/Makefile.am | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'input') diff --git a/input/Makefile.am b/input/Makefile.am index 3d841d7c..1bc81fbe 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -2,12 +2,11 @@ if INPUTPLUGIN plugindir = $(libdir)/bluetooth/plugins -plugin_LTLIBRARIES = libinput.la +plugin_LTLIBRARIES = input.la -libinput_la_SOURCES = main.c \ - manager.h manager.c \ - server.h server.c device.h device.c storage.h storage.c \ - fakehid.c fakehid.h +input_la_SOURCES = main.c manager.h manager.c \ + server.h server.c device.h device.c \ + storage.h storage.c fakehid.c fakehid.h LDADD = $(top_builddir)/common/libhelper.a \ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ -- cgit From c4139033616c53b1f790fe165d1a22fcce292e74 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 30 Jun 2008 17:35:47 +0000 Subject: Fixed missing include --- input/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'input') diff --git a/input/main.c b/input/main.c index 9a27a2ef..b269c76e 100644 --- a/input/main.c +++ b/input/main.c @@ -28,6 +28,7 @@ #include #include +#include #include -- cgit