From 36dedff329b5ced8979a2161075e6a9d38c58785 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 26 Jun 2008 14:44:01 +0000 Subject: Fix probing and removing drivers when discovering services. --- hcid/adapter.c | 4 +- hcid/dbus-hci.c | 7 ++- hcid/device.c | 174 +++++++++++++++++++++++++++++++++++++++++--------------- hcid/device.h | 4 +- 4 files changed, 136 insertions(+), 53 deletions(-) diff --git a/hcid/adapter.c b/hcid/adapter.c index 5e8b4a27..75aa31a4 100644 --- a/hcid/adapter.c +++ b/hcid/adapter.c @@ -2416,7 +2416,7 @@ struct device *adapter_create_device(DBusConnection *conn, debug("adapter_create_device(%s)", address); - device = device_create(conn, adapter, address, NULL); + device = device_create(conn, adapter, address); if (!device) return NULL; @@ -3980,7 +3980,7 @@ static DBusMessage *create_device(DBusConnection *conn, debug("create_device(%s)", address); - device = device_create(conn, adapter, address, NULL); + device = device_create(conn, adapter, address); if (!device) return NULL; diff --git a/hcid/dbus-hci.c b/hcid/dbus-hci.c index cf4bd192..f9d87973 100644 --- a/hcid/dbus-hci.c +++ b/hcid/dbus-hci.c @@ -587,11 +587,12 @@ static void create_stored_device_from_profiles(char *key, char *value, GSList *uuids = bt_string2list(value); struct device *device; - device = device_create(connection, adapter, key, uuids); + device = device_create(connection, adapter, key); if (device) { device->temporary = FALSE; adapter->devices = g_slist_append(adapter->devices, device); - device_probe_drivers(device); + device_probe_drivers(device, uuids); + g_slist_free(uuids); } } @@ -605,7 +606,7 @@ static void create_stored_device_from_linkkeys(char *key, char *value, key, (GCompareFunc) device_address_cmp)) return; - device = device_create(connection, adapter, key, NULL); + device = device_create(connection, adapter, key); if (device) { device->temporary = FALSE; adapter->devices = g_slist_append(adapter->devices, device); diff --git a/hcid/device.c b/hcid/device.c index 8ef46aad..43ccd4e8 100644 --- a/hcid/device.c +++ b/hcid/device.c @@ -74,6 +74,8 @@ struct browse_req { DBusConnection *conn; DBusMessage *msg; struct device *device; + GSList *uuids_added; + GSList *uuids_removed; int search_uuid; gboolean browse; }; @@ -1184,7 +1186,7 @@ static GDBusSignalTable device_signals[] = { }; struct device *device_create(DBusConnection *conn, struct adapter *adapter, - const gchar *address, GSList *uuids) + const gchar *address) { gchar *address_up; struct device *device; @@ -1210,7 +1212,6 @@ struct device *device_create(DBusConnection *conn, struct adapter *adapter, device->address = g_strdup(address); device->adapter = adapter; - device->uuids = uuids; device->dev.path = device->path; str2ba(device->address, &device->dev.dst); @@ -1250,7 +1251,7 @@ static int cmp_by_name(const void *data, const void *user_data) return (strcmp(dev_driver->name, driver->name)); } -void device_probe_drivers(struct device *device) +void device_probe_drivers(struct device *device, GSList *uuids) { GSList *list; const char **uuid; @@ -1263,8 +1264,8 @@ void device_probe_drivers(struct device *device) gboolean do_probe = FALSE; for (uuid = driver->uuids; *uuid; uuid++) { - GSList *match = g_slist_find_custom(device->uuids, - *uuid, (GCompareFunc) strcasecmp); + GSList *match = g_slist_find_custom(uuids, *uuid, + (GCompareFunc) strcasecmp); if (match) { do_probe = TRUE; break; @@ -1285,6 +1286,37 @@ void device_probe_drivers(struct device *device) driver); } } + + for (list = uuids; list; list = list->next) + device->uuids = g_slist_insert_sorted(device->uuids, + list->data, (GCompareFunc) strcmp); +} + +void device_remove_drivers(struct device *device, GSList *uuids) +{ + GSList *list; + + debug("Remove drivers for %s", device->path); + + for (list = device->drivers; list; list = list->next) { + struct btd_device_driver *driver = list->data; + const char **uuid; + + for (uuid = driver->uuids; *uuid; uuid++) { + GSList *match = g_slist_find_custom(uuids, *uuid, + (GCompareFunc) strcasecmp); + + if (!match) + continue; + + driver->remove(&device->dev); + device->drivers = g_slist_remove(device->drivers, + driver); + } + } + + for (list = uuids; list; list = list->next) + device->uuids = g_slist_remove(device->uuids, list->data); } static void iter_append_record(DBusMessageIter *dict, uint32_t handle, @@ -1344,81 +1376,124 @@ static void discover_device_reply(struct browse_req *req, sdp_list_t *recs) dbus_message_unref(reply); } -static void browse_cb(sdp_list_t *recs, int err, gpointer user_data) +static void services_changed(struct browse_req *req) { - sdp_list_t *seq, *next, *svcclass; - struct browse_req *req = user_data; struct device *device = req->device; - struct adapter *adapter = device->adapter; - bdaddr_t src, dst; char **uuids; - int i; GSList *l; - uuid_t uuid; - DBusMessage *reply; + int i; - if (err < 0) - goto proceed; + uuids = g_new0(char *, g_slist_length(device->uuids) + 1); + for (i = 0, l = device->uuids; l; l = l->next, i++) + uuids[i] = l->data; + + dbus_connection_emit_property_changed(req->conn, device->path, + DEVICE_INTERFACE, "UUIDs", + DBUS_TYPE_ARRAY, &uuids); + + g_free(uuids); +} + +static void update_services(struct browse_req *req, sdp_list_t *recs) +{ + struct device *device = req->device; + sdp_list_t *seq; - for (seq = recs; seq; seq = next) { + for (seq = recs; seq; seq = seq->next) { sdp_record_t *rec = (sdp_record_t *) seq->data; + sdp_list_t *svcclass = NULL; + gchar *uuid_str; + GSList *l; if (!rec) break; - svcclass = NULL; - if (sdp_get_service_classes(rec, &svcclass) == 0) { - /* Extract the first element and skip the remainning */ - gchar *uuid_str = bt_uuid2string(svcclass->data); - if (uuid_str) { - if (!g_slist_find_custom(device->uuids, uuid_str, - (GCompareFunc) strcmp)) - device->uuids = g_slist_insert_sorted(device->uuids, - uuid_str, (GCompareFunc) strcmp); - else - g_free(uuid_str); - } - sdp_list_free(svcclass, free); + if (sdp_get_service_classes(rec, &svcclass) < 0) + continue; + + /* Extract the first element and skip the remainning */ + uuid_str = bt_uuid2string(svcclass->data); + if (!uuid_str) + continue; + + l = g_slist_find_custom(device->uuids, uuid_str, + (GCompareFunc) strcmp); + if (!l) + req->uuids_added = g_slist_append(req->uuids_added, + uuid_str); + else { + req->uuids_removed = g_slist_remove(req->uuids_removed, + l->data); + g_free(uuid_str); } - next = seq->next; + sdp_list_free(svcclass, free); } +} + +static void store(struct device *device) +{ + struct adapter *adapter = device->adapter; + bdaddr_t src, dst; + char *str; str2ba(adapter->address, &src); str2ba(device->address, &dst); + if (!device->uuids) { + write_device_profiles(&src, &dst, ""); + return; + } + + str = bt_list2string(device->uuids); + write_device_profiles(&src, &dst, str); + g_free(str); +} + +static void browse_cb(sdp_list_t *recs, int err, gpointer user_data) +{ + struct browse_req *req = user_data; + struct device *device = req->device; + struct adapter *adapter = device->adapter; + bdaddr_t src, dst; + uuid_t uuid; + DBusMessage *reply; + + if (err < 0) + goto proceed; + + update_services(req, recs); + /* Public browsing successful or Single record requested */ if (req->browse == FALSE || (!req->search_uuid && recs)) goto probe; if (uuid_list[++req->search_uuid]) { sdp_uuid16_create(&uuid, uuid_list[req->search_uuid]); + str2ba(adapter->address, &src); + str2ba(device->address, &dst); bt_search_service(&src, &dst, &uuid, browse_cb, user_data, NULL); return; } probe: - /* Store the device's profiles in the filesystem */ - if (device->uuids) { - gchar *str = bt_list2string(device->uuids); - write_device_profiles(&src, &dst, str); - g_free(str); - uuids = g_new0(char *, g_slist_length(device->uuids) + 1); - for (i = 0, l = device->uuids; l; l = l->next, i++) - uuids[i] = l->data; + if (!req->uuids_added && !req->uuids_removed) + goto proceed; - dbus_connection_emit_property_changed(req->conn, device->path, - DEVICE_INTERFACE, "UUIDs", - DBUS_TYPE_ARRAY, &uuids); + /* Probe matching drivers for services added */ + if (req->uuids_added) + device_probe_drivers(device, req->uuids_added); - g_free(uuids); + /* Remove drivers for services removed */ + if (req->uuids_removed) + device_remove_drivers(device, req->uuids_removed); - } else - write_device_profiles(&src, &dst, ""); + /* Store the device's profiles in the filesystem */ + store(device); - /* Probe matching drivers */ - device_probe_drivers(device); + /* Propagate services changes */ + services_changed(req); proceed: if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, @@ -1458,6 +1533,8 @@ cleanup: dbus_message_unref(req->msg); dbus_connection_unref(req->conn); + g_slist_free(req->uuids_added); + g_slist_free(req->uuids_removed); g_free(req); } @@ -1468,12 +1545,17 @@ int device_browse(struct device *device, DBusConnection *conn, struct browse_req *req; bdaddr_t src, dst; uuid_t uuid; + GSList *l; req = g_new0(struct browse_req, 1); req->conn = dbus_connection_ref(conn); req->msg = dbus_message_ref(msg); req->device = device; + for (l = device->uuids; l; l = l->next) + req->uuids_removed = g_slist_append(req->uuids_removed, + l->data); + str2ba(adapter->address, &src); str2ba(device->address, &dst); diff --git a/hcid/device.h b/hcid/device.h index c6487f27..e7cee9f7 100644 --- a/hcid/device.h +++ b/hcid/device.h @@ -50,12 +50,12 @@ struct device { }; struct device *device_create(DBusConnection *conn, struct adapter *adapter, - const gchar *address, GSList *uuids); + const gchar *address); void device_remove(DBusConnection *conn, struct device *device); gint device_address_cmp(struct device *device, const gchar *address); int device_browse(struct device *device, DBusConnection *conn, DBusMessage *msg, uint16_t search); -void device_probe_drivers(struct device *device); +void device_probe_drivers(struct device *device, GSList *uuids); #define BTD_UUIDS(args...) ((const char *[]) { args, NULL } ) -- cgit