summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-06-26 14:44:01 +0000
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-06-26 14:44:01 +0000
commit36dedff329b5ced8979a2161075e6a9d38c58785 (patch)
tree67d1b87e88144974eede84c57f72a66882ac9e3c
parent1e8fbfbfa6fbcf88a668f77e5601bbc505eb483f (diff)
Fix probing and removing drivers when discovering services.
-rw-r--r--hcid/adapter.c4
-rw-r--r--hcid/dbus-hci.c7
-rw-r--r--hcid/device.c174
-rw-r--r--hcid/device.h4
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 } )