diff options
Diffstat (limited to 'drivers/qmimodem/qmi.c')
-rw-r--r-- | drivers/qmimodem/qmi.c | 130 |
1 files changed, 96 insertions, 34 deletions
diff --git a/drivers/qmimodem/qmi.c b/drivers/qmimodem/qmi.c index fc4534a2..e66e8d8f 100644 --- a/drivers/qmimodem/qmi.c +++ b/drivers/qmimodem/qmi.c @@ -260,6 +260,10 @@ static gboolean __service_compare_shared(gpointer key, gpointer value, struct qmi_service *service = value; uint8_t type = GPOINTER_TO_UINT(user_data); + /* ignore those that are in process of creation */ + if (GPOINTER_TO_UINT(key) & 0x80000000) + return FALSE; + if (service->type == type) return TRUE; @@ -736,6 +740,10 @@ static void service_notify(gpointer key, gpointer value, gpointer user_data) struct qmi_result *result = user_data; GList *list; + /* ignore those that are in process of creation */ + if (GPOINTER_TO_UINT(key) & 0x80000000) + return; + for (list = g_list_first(service->notify_list); list; list = g_list_next(list)) { struct qmi_notify *notify = list->data; @@ -1967,12 +1975,58 @@ static void service_create_data_free(gpointer user_data) g_free(data); } +struct service_create_shared_data { + struct discovery super; + struct qmi_service *service; + struct qmi_device *device; + qmi_create_func_t func; + void *user_data; + qmi_destroy_func_t destroy; + guint timeout; +}; + +static gboolean service_create_shared_reply(gpointer user_data) +{ + struct service_create_shared_data *data = user_data; + + data->timeout = 0; + data->func(data->service, data->user_data); + + __qmi_device_discovery_complete(data->device, &data->super); + + return FALSE; +} + +static void service_create_shared_pending_reply(struct qmi_device *device, + unsigned int type, + struct qmi_service *service) +{ + gpointer key = GUINT_TO_POINTER(type | 0x80000000); + GList **shared = g_hash_table_lookup(device->service_list, key); + GList *l; + + g_hash_table_steal(device->service_list, key); + + for (l = *shared; l; l = l->next) { + struct service_create_shared_data *shared_data = l->data; + + shared_data->service = qmi_service_ref(service); + shared_data->timeout = g_timeout_add( + 0, service_create_shared_reply, shared_data); + } + + g_list_free(*shared); + g_free(shared); +} + static gboolean service_create_reply(gpointer user_data) { struct service_create_data *data = user_data; struct qmi_device *device = data->device; struct qmi_request *req; + service_create_shared_pending_reply(device, data->type, NULL); + /* remove request from queues */ req = find_control_request(device, data->tid); @@ -2039,6 +2093,8 @@ static void service_create_callback(uint16_t message, uint16_t length, GUINT_TO_POINTER(hash_id), service); done: + service_create_shared_pending_reply(device, data->type, service); + data->func(service, data->user_data); qmi_service_unref(service); @@ -2052,15 +2108,23 @@ static bool service_create(struct qmi_device *device, struct service_create_data *data; unsigned char client_req[] = { 0x01, 0x01, 0x00, type }; struct qmi_request *req; + GList **shared; + unsigned int type_val = type; int i; - data = g_try_new0(struct service_create_data, 1); - if (!data) + if (!device->version_list) return false; - if (!device->version_list) + shared = g_try_new0(GList *, 1); + if (!shared) return false; + data = g_try_new0(struct service_create_data, 1); + if (!data) { + g_free(shared); + return false; + } + data->super.destroy = service_create_data_free; data->device = device; data->type = type; @@ -2088,19 +2152,13 @@ static bool service_create(struct qmi_device *device, __qmi_device_discovery_started(device, &data->super); + /* Mark service creation as pending */ + g_hash_table_insert(device->service_list, + GUINT_TO_POINTER(type_val | 0x80000000), shared); + return true; } -struct service_create_shared_data { - struct discovery super; - struct qmi_service *service; - struct qmi_device *device; - qmi_create_func_t func; - void *user_data; - qmi_destroy_func_t destroy; - guint timeout; -}; - static void service_create_shared_data_free(gpointer user_data) { struct service_create_shared_data *data = user_data; @@ -2118,23 +2176,11 @@ static void service_create_shared_data_free(gpointer user_data) g_free(data); } -static gboolean service_create_shared_reply(gpointer user_data) +bool qmi_service_create_shared(struct qmi_device *device, uint8_t type, + qmi_create_func_t func, void *user_data, + qmi_destroy_func_t destroy) { - struct service_create_shared_data *data = user_data; - - data->timeout = 0; - data->func(data->service, data->user_data); - - __qmi_device_discovery_complete(data->device, &data->super); - - return FALSE; -} - -bool qmi_service_create_shared(struct qmi_device *device, - uint8_t type, qmi_create_func_t func, - void *user_data, qmi_destroy_func_t destroy) -{ - struct qmi_service *service; + gpointer service; unsigned int type_val = type; if (!device || !func) @@ -2143,8 +2189,14 @@ bool qmi_service_create_shared(struct qmi_device *device, if (type == QMI_SERVICE_CONTROL) return false; - service = g_hash_table_find(device->service_list, + service = g_hash_table_lookup(device->service_list, + GUINT_TO_POINTER(type_val | 0x80000000)); + if (!service) { + service = g_hash_table_find(device->service_list, __service_compare_shared, GUINT_TO_POINTER(type_val)); + } else + type_val |= 0x80000000; + if (service) { struct service_create_shared_data *data; @@ -2153,17 +2205,27 @@ bool qmi_service_create_shared(struct qmi_device *device, return false; data->super.destroy = service_create_shared_data_free; - data->service = qmi_service_ref(service); data->device = device; data->func = func; data->user_data = user_data; data->destroy = destroy; - data->timeout = g_timeout_add(0, - service_create_shared_reply, data); + if (!data) + return false; + + if (!(type_val & 0x80000000)) { + data->service = qmi_service_ref(service); + data->timeout = g_timeout_add( + 0, service_create_shared_reply, data); + } else { + GList **l = service; + + *l = g_list_prepend(*l, data); + } + __qmi_device_discovery_started(device, &data->super); - return 0; + return true; } return service_create(device, type, func, user_data, destroy); |