summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--input/device.c242
-rw-r--r--input/device.h4
-rw-r--r--input/main.c74
-rw-r--r--input/manager.c654
-rw-r--r--input/manager.h4
5 files changed, 114 insertions, 864 deletions
diff --git a/input/device.c b/input/device.c
index 75acaa82..632b5564 100644
--- a/input/device.c
+++ b/input/device.c
@@ -49,14 +49,14 @@
#include "device.h"
#include "error.h"
-#include "manager.h"
#include "storage.h"
#include "fakehid.h"
#include "glib-helper.h"
-#define INPUT_DEVICE_INTERFACE "org.bluez.input.Device"
+#define INPUT_DEVICE_INTERFACE "org.bluez.input.Device"
+#define INPUT_HEADSET_INTERFACE "org.bluez.input.Headset"
-#define BUF_SIZE 16
+#define BUF_SIZE 16
#define UPDOWN_ENABLED 1
@@ -77,6 +77,7 @@ struct device {
DBusMessage *pending_connect;
DBusConnection *conn;
char *path;
+ char *iface;
int ctrl_sk;
int intr_sk;
guint ctrl_watch;
@@ -193,85 +194,6 @@ static int uinput_create(char *name)
return fd;
}
-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 (major) {
- case 0x02: /* Phone */
- strcpy(subpath, "phone");
- break;
- 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 & 0x0f) && (strlen(subpath) > 0))
- strcat(subpath, "/");
-
- 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:
- return NULL;
- }
-
- snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++);
- return path;
-}
-
static int decode_key(const char *str)
{
static int mode = UPDOWN_ENABLED, gain = 0;
@@ -425,7 +347,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);
g_dbus_emit_signal(idev->conn, path,
- INPUT_DEVICE_INTERFACE, "Connected",
+ idev->iface, "Connected",
DBUS_TYPE_INVALID);
dbus_message_unref(idev->pending_connect);
@@ -462,11 +384,8 @@ static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data
if (cond & (G_IO_HUP | G_IO_ERR))
g_io_channel_close(chan);
- g_dbus_emit_signal(idev->conn,
- idev->path,
- INPUT_DEVICE_INTERFACE,
- "Disconnected",
- DBUS_TYPE_INVALID);
+ g_dbus_emit_signal(idev->conn, idev->path, idev->iface,
+ "Disconnected", DBUS_TYPE_INVALID);
g_source_remove(idev->ctrl_watch);
idev->ctrl_watch = 0;
@@ -489,11 +408,8 @@ static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data
if (cond & (G_IO_HUP | G_IO_ERR))
g_io_channel_close(chan);
- g_dbus_emit_signal(idev->conn,
- idev->path,
- INPUT_DEVICE_INTERFACE,
- "Disconnected",
- DBUS_TYPE_INVALID);
+ g_dbus_emit_signal(idev->conn, idev->path, idev->iface,
+ "Disconnected", DBUS_TYPE_INVALID);
g_source_remove(idev->intr_watch);
idev->intr_watch = 0;
@@ -594,11 +510,8 @@ 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);
- g_dbus_emit_signal(idev->conn,
- idev->path,
- INPUT_DEVICE_INTERFACE,
- "Connected",
- DBUS_TYPE_INVALID);
+ g_dbus_emit_signal(idev->conn, idev->path, idev->iface,
+ "Connected", DBUS_TYPE_INVALID);
/* Replying to the requestor */
g_dbus_send_reply(idev->conn, idev->pending_connect, DBUS_TYPE_INVALID);
@@ -826,64 +739,12 @@ static DBusMessage *device_is_connected(DBusConnection *conn,
DBUS_TYPE_INVALID);
}
-static DBusMessage *device_get_adapter(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct device *idev = data;
- char addr[18];
- const char *paddr = addr;
-
- ba2str(&idev->src, addr);
-
- return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr,
- DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *device_get_address(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct device *idev = data;
- char addr[18];
- const char *paddr = addr;
-
- ba2str(&idev->dst, addr);
-
- return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr,
- DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *device_get_name(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct device *idev = data;
- const char *pname = (idev->name ? idev->name : "");
-
- return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &pname,
- DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *device_get_product_id(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct device *idev = data;
-
- return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->product,
- DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *device_get_vendor_id(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct device *idev = data;
-
- return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->vendor,
- DBUS_TYPE_INVALID);
-}
-
static void device_unregister(void *data)
{
struct device *idev = data;
+ info("Unregistered interface %s on path %s", idev->iface, idev->path);
+
/* Disconnect if applied */
disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG));
device_free(idev);
@@ -894,11 +755,6 @@ static GDBusMethodTable device_methods[] = {
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 },
{ }
};
@@ -911,71 +767,53 @@ static GDBusSignalTable device_signals[] = {
/*
* Input registration functions
*/
-static int register_path(DBusConnection *conn, const char *path, struct device *idev)
+static int register_path(DBusConnection *conn, struct device *idev)
{
- if (g_dbus_register_interface(conn, path, INPUT_DEVICE_INTERFACE,
+ if (g_dbus_register_interface(conn, idev->path, idev->iface,
device_methods, device_signals, NULL,
idev, device_unregister) == FALSE) {
- error("Failed to register %s interface to %s",
- INPUT_DEVICE_INTERFACE, path);
+ error("Failed to register interface %s on path %s",
+ idev->iface, idev->path);
+ device_free(idev);
return -1;
}
devices = g_slist_append(devices, idev);
- info("Created input device: %s", path);
+ info("Registered interface %s on path %s", idev->iface, idev->path);
return 0;
}
int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
- struct hidp_connadd_req *hid, const char **ppath)
+ struct hidp_connadd_req *hid, const char *path)
{
struct device *idev;
- const char *path;
- int err;
idev = device_new(src, dst, hid->subclass, hid->idle_to);
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;
- idev->conn = dbus_connection_ref(conn);
-
- err = register_path(conn, path, idev);
-
- if (!err && ppath)
- *ppath = path;
+ idev->path = g_strdup(path);
+ idev->iface = INPUT_DEVICE_INTERFACE;
+ idev->product = hid->product;
+ idev->vendor = hid->vendor;
+ idev->conn = dbus_connection_ref(conn);
- return err;
+ return register_path(conn, idev);
}
int fake_input_register(DBusConnection *conn, bdaddr_t *src,
- bdaddr_t *dst, uint8_t ch, const char **ppath)
+ bdaddr_t *dst, uint8_t ch, const char *path)
{
struct device *idev;
- const char *path;
- int err;
idev = device_new(src, dst, 0, 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->iface = INPUT_HEADSET_INTERFACE;
idev->conn = dbus_connection_ref(conn);
/* FIXME: Missing set product and vendor */
@@ -985,12 +823,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src,
idev->fake->connect = rfcomm_connect;
idev->fake->disconnect = fake_disconnect;
- err = register_path(conn, path, idev);
-
- if (!err && ppath)
- *ppath = path;
-
- return err;
+ return register_path(conn, idev);
}
static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst)
@@ -1048,17 +881,11 @@ int input_device_unregister(DBusConnection *conn, const char *path)
if (idev->intr_watch) {
g_source_remove(idev->intr_watch);
- g_dbus_emit_signal(conn,
- path, INPUT_DEVICE_INTERFACE,
+ g_dbus_emit_signal(conn, path, idev->iface,
"Disconnected", DBUS_TYPE_INVALID);
}
- g_dbus_emit_signal(conn, INPUT_PATH,
- INPUT_MANAGER_INTERFACE, "DeviceRemoved" ,
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
-
- g_dbus_unregister_interface(conn, path, INPUT_DEVICE_INTERFACE);
+ g_dbus_unregister_interface(conn, path, idev->iface);
return 0;
}
@@ -1154,11 +981,8 @@ 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);
- g_dbus_emit_signal(idev->conn,
- idev->path,
- INPUT_DEVICE_INTERFACE,
- "Connected",
- DBUS_TYPE_INVALID);
+ g_dbus_emit_signal(idev->conn, idev->path, idev->iface,
+ "Connected", DBUS_TYPE_INVALID);
return 0;
error:
diff --git a/input/device.h b/input/device.h
index c9296ad0..d71e7a73 100644
--- a/input/device.h
+++ b/input/device.h
@@ -38,9 +38,9 @@ struct fake_input {
};
int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
- struct hidp_connadd_req *hidp, const char **ppath);
+ struct hidp_connadd_req *hid, const char *path);
int fake_input_register(DBusConnection *conn, bdaddr_t *src,
- bdaddr_t *dst, uint8_t ch, const char **ppath);
+ bdaddr_t *dst, uint8_t ch, const char *path);
int input_device_unregister(DBusConnection *conn, const char *path);
gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst);
diff --git a/input/main.c b/input/main.c
index 8462967a..d70bf2a0 100644
--- a/input/main.c
+++ b/input/main.c
@@ -33,77 +33,10 @@
#include <gdbus.h>
#include "plugin.h"
-#include "../hcid/device.h"
#include "logging.h"
#include "dbus-service.h"
#include "manager.h"
-#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 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 },
- { "IsConnected", "", "b", input_is_connected },
- { }
-};
-
-static GDBusSignalTable input_signals[] = {
- { "Connected", "" },
- { "Disconnected", "" },
- { }
-};
-
-static DBusConnection *conn;
-
-static int input_probe(struct btd_device *device, GSList *records)
-{
- const gchar *path = device_get_path(device);
- DBG("path %s", path);
-
- if (g_dbus_register_interface(conn, path, INPUT_INTERFACE,
- input_methods, input_signals, NULL,
- device, NULL) == FALSE)
- return -1;
-
- return 0;
-}
-
-static void input_remove(struct btd_device *device)
-{
- const gchar *path = device_get_path(device);
- DBG("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;
@@ -124,6 +57,7 @@ static GKeyFile *load_config_file(const char *file)
static int input_init(void)
{
GKeyFile *config;
+ DBusConnection *conn;
conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
if (conn == NULL)
@@ -139,18 +73,12 @@ static int input_init(void)
if (config)
g_key_file_free(config);
- btd_register_device_driver(&input_driver);
-
return 0;
}
static void input_exit(void)
{
- btd_unregister_device_driver(&input_driver);
-
input_manager_exit();
-
- dbus_connection_unref(conn);
}
BLUETOOTH_PLUGIN_DEFINE("input", input_init, input_exit)
diff --git a/input/manager.c b/input/manager.c
index 2dfb9b2d..dc7440cd 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -44,6 +44,8 @@
#include "logging.h"
#include "textfile.h"
+#include "../hcid/adapter.h"
+#include "../hcid/device.h"
#include "device.h"
#include "server.h"
@@ -52,70 +54,10 @@
#include "storage.h"
#include "glib-helper.h"
-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_list_t *pnp_recs;
- sdp_list_t *hid_recs;
- GIOChannel *ctrl_channel;
-};
-
static int idle_timeout = 0;
-static GSList *device_paths = NULL; /* Input registered paths */
-
static DBusConnection *connection = NULL;
-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);
- 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_recs)
- sdp_list_free(pr->pnp_recs, (sdp_free_func_t) sdp_record_free);
-
- if (pr->hid_recs)
- sdp_list_free(pr->hid_recs, (sdp_free_func_t) sdp_record_free);
-
- g_free(pr);
-}
-
static void epox_endian_quirk(unsigned char *data, int size)
{
/* USAGE_PAGE (Keyboard) 05 07
@@ -198,567 +140,133 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
}
}
-static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req)
+/*
+ * Stored inputs registration functions
+ */
+
+static int load_stored(const char *source, const char *destination,
+ struct hidp_connadd_req *hidp)
{
- sdp_data_t *pdlist;
+ char filename[PATH_MAX + 1];
+ char *value;
+
+ /* load the input stored */
+ create_name(filename, PATH_MAX, STORAGEDIR, destination, "input");
- pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
- req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;
+ value = textfile_get(filename, destination);
+ if (!value)
+ return -EINVAL;
- pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
- req->product = pdlist ? pdlist->val.uint16 : 0x0000;
+ memset(&hidp, 0, sizeof(hidp));
- pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
- req->version = pdlist ? pdlist->val.uint16 : 0x0000;
+ return parse_stored_device_info(value, hidp);
}
-static void interrupt_connect_cb(GIOChannel *chan, int err,
- const bdaddr_t *src, const bdaddr_t *dst,
- gpointer user_data)
+int input_probe(struct btd_device *device, GSList *records)
{
- struct pending_req *pr = user_data;
+ struct adapter *adapter = device_get_adapter(device);
+ const gchar *path = device_get_path(device);
+ const char *source, *destination;
struct hidp_connadd_req hidp;
- const char *path;
+ bdaddr_t src, dst;
+
+ DBG("path %s", path);
memset(&hidp, 0, sizeof(hidp));
- if (err < 0) {
- error("connect(): %s (%d)", strerror(-err), -err);
- goto failed;
- }
+ source = adapter->address;
+ destination = device_get_address(device);
- g_io_channel_close(chan);
- g_io_channel_unref(chan);
+ if (load_stored(source, destination, &hidp) == 0)
+ goto done;
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);
-
- store_device_info(&pr->src, &pr->dst, &hidp);
-
- if (input_device_register(pr->conn, &pr->src,
- &pr->dst, &hidp, &path) < 0) {
- error_failed(pr->conn, pr->msg, "path registration failed");
- goto cleanup;
- }
-
- g_dbus_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));
-
- g_dbus_send_reply(pr->conn, pr->msg, DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
+ extract_hid_record(records->data, &hidp);
- goto cleanup;
+done:
+ str2ba(source, &src);
+ str2ba(destination, &dst);
-failed:
- error_connection_attempt_failed(pr->conn, pr->msg, err);
-
-cleanup:
- g_io_channel_close(pr->ctrl_channel);
- g_io_channel_unref(pr->ctrl_channel);
- pending_req_free(pr);
+ store_device_info(&src, &dst, &hidp);
if (hidp.rd_data)
g_free(hidp.rd_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;
-
- if (err < 0) {
- error("connect(): %s (%d)", strerror(-err), -err);
- goto failed;
- }
- /* Set HID control channel */
- pr->ctrl_channel = chan;
-
- /* Connect to the HID interrupt channel */
- 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);
- goto failed;
- }
-
- return;
-
-failed:
- error_connection_attempt_failed(pr->conn, pr->msg, -err);
- pending_req_free(pr);
+ return input_device_register(connection, &src, &dst, &hidp, path);
}
-static void create_bonding_reply(DBusPendingCall *call, void *data)
+void input_remove(struct btd_device *device)
{
- 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)) {
- error("CreateBonding failed: %s(%s)",
- derr.name, derr.message);
- error_failed(pr->conn, pr->msg, "Authentication failed (CreateBonding)");
- dbus_error_free(&derr);
- dbus_message_unref(reply);
- pending_req_free(pr);
- return;
- }
+ const gchar *path = device_get_path(device);
- dbus_message_unref(reply);
+ DBG("path %s", path);
- 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);
- error_connection_attempt_failed(pr->conn, pr->msg, -err);
- pending_req_free(pr);
- }
-}
-
-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;
+ input_device_unregister(connection, path);
}
-static void hid_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+int headset_input_probe(struct btd_device *device, GSList *records)
{
- struct pending_req *pr = user_data;
-
- if (err < 0) {
- error_not_supported(pr->conn, pr->msg);
- error("SDP search error: %s (%d)", strerror(-err), -err);
- goto fail;
- }
-
- if (!recs || !recs->data) {
- error_not_supported(pr->conn, pr->msg);
- error("Invalid HID service record length");
- goto fail;
- }
-
- 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_recs->data,
- SDP_ATTR_HID_DEVICE_SUBCLASS);
- if (d && (d->val.uint8 & 0x40) &&
- !has_bonding(&pr->src, &pr->dst)) {
- if (create_bonding(pr) < 0) {
- error_failed(pr->conn, pr->msg,
- "Unable to initialize bonding process");
- goto fail;
- }
- /* Wait bonding reply */
- return;
- }
-
- /* Otherwise proceede L2CAP connection */
- }
-
- /* No encryption or link key already exists -- connect control channel */
- 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);
- error_connection_attempt_failed(pr->conn, pr->msg, -err);
- goto fail;
- }
-
- /* Wait L2CAP connect */
- return;
-
-fail:
- pending_req_free(pr);
-}
-
-static void pnp_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
- struct pending_req *pr = user_data;
- uuid_t uuid;
-
- if (err < 0) {
- error_not_supported(pr->conn, pr->msg);
- error("SDP search error: %s (%d)", strerror(-err), -err);
- goto fail;
- }
-
- if (!recs || !recs->data) {
- error_not_supported(pr->conn, pr->msg);
- error("Invalid PnP service record length");
- goto fail;
- }
-
- 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);
- if (err < 0) {
- error_not_supported(pr->conn, pr->msg);
- error("HID service search request failed");
- goto fail;
- }
-
- return;
-
-fail:
- pending_req_free(pr);
-}
-
-static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
- struct pending_req *pr = user_data;
- sdp_record_t *rec;
+ struct adapter *adapter = device_get_adapter(device);
+ const gchar *path = device_get_path(device);
+ sdp_record_t *record = records->data;
sdp_list_t *protos;
- const char *path;
uint8_t ch;
+ const char *source, *destination;
+ bdaddr_t src, dst;
- if (err < 0) {
- error_not_supported(pr->conn, pr->msg);
- error("SDP search error: %s (%d)", strerror(-err), -err);
- goto fail;
- }
-
- if (!recs || !recs->data) {
- error_not_supported(pr->conn, pr->msg);
- error("Invalid headset service record length");
- goto fail;
- }
-
- rec = recs->data;
+ DBG("path %s", path);
- if (sdp_get_access_protos(rec, &protos) < 0) {
- error_not_supported(pr->conn, pr->msg);
- goto fail;
+ if (sdp_get_access_protos(record, &protos) < 0) {
+ error("Invalid record");
+ return -EINVAL;
}
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) {
- error_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);
- error_failed(pr->conn, pr->msg, "Path registration failed");
- goto fail;
- }
-
- g_dbus_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));
-
- g_dbus_send_reply(pr->conn, pr->msg, DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
-
-fail:
- pending_req_free(pr);
-}
-
-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;
- const char *addr;
- bdaddr_t src, dst;
- uint32_t cls = 0;
- int dev_id, err;
- uuid_t uuid;
- bt_callback_t cb;
-
- 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 adapter_not_available(msg);
- }
-
- if (hci_devba(dev_id, &src) < 0) {
- error("Can't get local adapter device info");
- return adapter_not_available(msg);
- }
-
- str2ba(addr, &dst);
- if (input_device_is_registered(&src, &dst))
- return already_exists(msg);
-
- if (read_device_class(&src, &dst, &cls) < 0) {
- error("Device class not available");
- return not_supported(msg);
+ return -EINVAL;
}
- pr = pending_req_new(conn, msg, &src, &dst);
- if (!pr)
- return NULL;
-
- switch (cls & 0x1f00) {
- case 0x0500: /* Peripheral */
- case 0x0200: /* Phone */
- sdp_uuid16_create(&uuid, PNP_INFO_SVCLASS_ID);
- cb = pnp_record_cb;
- break;
- case 0x0400: /* Fake input */
- sdp_uuid16_create(&uuid, HEADSET_SVCLASS_ID);
- cb = headset_record_cb;
- break;
- default:
- pending_req_free(pr);
- return not_supported(msg);
- }
-
- err = bt_search_service(&src, &dst, &uuid, cb, pr, NULL);
- if (err < 0) {
- pending_req_free(pr);
- return not_supported(msg);
- }
-
- return NULL;
-}
-
-static DBusMessage *remove_device(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- GSList *l;
- const char *path;
- int err;
-
- 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 does_not_exist(msg);
-
- err = input_device_unregister(conn, path);
- if (err < 0)
- return create_errno_message(msg, -err);
-
- g_free(l->data);
- device_paths = g_slist_remove(device_paths, l->data);
-
- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *list_devices(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter, iter_array;
- DBusMessage *reply;
- GSList *paths;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- 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 = device_paths; paths != NULL; paths = paths->next) {
- const char *ppath = paths->data;
- dbus_message_iter_append_basic(&iter_array,
- DBUS_TYPE_STRING, &ppath);
- }
+ source = adapter->address;
+ destination = device_get_address(device);
- dbus_message_iter_close_container(&iter, &iter_array);
+ str2ba(source, &src);
+ str2ba(destination, &dst);
- return reply;
+ return fake_input_register(connection, &src, &dst, ch, path);
}
-static void manager_unregister(void *data)
+void headset_input_remove(struct btd_device *device)
{
- info("Unregistered manager path");
+ const gchar *path = device_get_path(device);
- g_slist_foreach(device_paths, (GFunc) free, NULL);
+ DBG("path %s", path);
- g_slist_free(device_paths);
+ input_device_unregister(connection, path);
}
-/*
- * Stored inputs registration functions
- */
-
-static void stored_input(char *key, char *value, void *data)
-{
- const char *path;
- struct hidp_connadd_req hidp;
- bdaddr_t dst, *src = data;
-
- str2ba(key, &dst);
-
- memset(&hidp, 0, sizeof(hidp));
-
- if (parse_stored_device_info(value, &hidp) < 0)
- return;
-
- /*
- * Repeated entries for the same remote device are
- * acceptable since the source is different.
- */
- if (input_device_register(connection, src, &dst, &hidp, &path) < 0)
- goto cleanup;
-
- device_paths = g_slist_append(device_paths, g_strdup(path));
-cleanup:
- if (hidp.rd_data)
- 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(hidp));
-
- 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];
- char filename[PATH_MAX + 1];
- struct dirent *de;
- DIR *dir;
- bdaddr_t src;
-
- snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
-
- dir = opendir(dirname);
- if (!dir)
- return;
-
- while ((de = readdir(dir)) != NULL) {
- 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, "hidd");
- textfile_foreach(filename, stored_hidd, &src);
-
- /* load the input stored devices */
- create_name(filename, PATH_MAX, STORAGEDIR,
- de->d_name, "input");
-
- textfile_foreach(filename, stored_input, &src);
- }
-
- closedir(dir);
-}
-
-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 struct btd_device_driver input_driver = {
+ .name = "input",
+ .uuids = BTD_UUIDS(HID_UUID),
+ .probe = input_probe,
+ .remove = input_remove,
};
-static GDBusSignalTable manager_signals[] = {
- { "DeviceCreated", "s" },
- { "DeviceRemoved", "s" },
- { }
+static struct btd_device_driver input_headset_driver = {
+ .name = "input-headset",
+ .uuids = BTD_UUIDS(HSP_HS_UUID),
+ .probe = headset_input_probe,
+ .remove = headset_input_remove,
};
int input_manager_init(DBusConnection *conn, GKeyFile *config)
{
GError *err = NULL;
-
+
if (config) {
idle_timeout = g_key_file_get_integer(config, "General",
"IdleTimeout", &err);
@@ -768,33 +276,23 @@ int input_manager_init(DBusConnection *conn, GKeyFile *config)
}
}
- 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);
- return -1;
- }
-
connection = dbus_connection_ref(conn);
- info("Registered input manager path:%s", INPUT_PATH);
-
- /* Register well known HID devices */
- register_stored_inputs();
-
server_start();
+ btd_register_device_driver(&input_driver);
+ btd_register_device_driver(&input_headset_driver);
+
return 0;
}
void input_manager_exit(void)
{
- g_dbus_unregister_interface(connection, INPUT_PATH,
- INPUT_MANAGER_INTERFACE);
-
server_stop();
+ btd_unregister_device_driver(&input_driver);
+ btd_unregister_device_driver(&input_headset_driver);
+
dbus_connection_unref(connection);
connection = NULL;
diff --git a/input/manager.h b/input/manager.h
index 8f9d999e..f50975c8 100644
--- a/input/manager.h
+++ b/input/manager.h
@@ -21,8 +21,8 @@
*
*/
-#define INPUT_PATH "/org/bluez/input"
-#define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager"
+#define HSP_HS_UUID "00001108-0000-1000-8000-00805F9B34FB"
+#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
int input_manager_init(DBusConnection *conn, GKeyFile *config);
void input_manager_exit(void);