From ada5284a431cdfcda3e3532173595bbbd134ae22 Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Fri, 19 Apr 2024 14:31:13 +0200 Subject: [PATCH] uqmid: service: add indications support QMI allow baseband services to send indications (events) towards uqmid. To some indication uqmid has to register first, other indications are sent as soon the service has been opened. Signed-off-by: Alexander Couzens --- uqmid/ddev.c | 46 ++++++++++++++++++++++------------- uqmid/services.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ uqmid/services.h | 23 ++++++++++++++++++ 3 files changed, 114 insertions(+), 17 deletions(-) diff --git a/uqmid/ddev.c b/uqmid/ddev.c index 5bfc3c0..c9a69a9 100644 --- a/uqmid/ddev.c +++ b/uqmid/ddev.c @@ -53,23 +53,29 @@ qmi_process_msg(struct qmi_dev *qmi, struct qmi_msg *msg) struct qmi_service *service; struct qmi_request *req; uint16_t tid; + bool resp, ind; - /* FIXME: indications? */ - - if (msg->qmux.service == QMI_SERVICE_CTL) + if (msg->qmux.service == QMI_SERVICE_CTL) { modem_log(qmi->modem, LOGL_DEBUG, "Process message from srv %d msg %04x flag: %02x tid: %02x", msg->qmux.service, le16_to_cpu(msg->ctl.message), msg->flags, msg->ctl.transaction); - else + tid = msg->ctl.transaction; + ind = msg->flags & QMI_CTL_FLAG_INDICATION; + resp = msg->flags & QMI_CTL_FLAG_RESPONSE; + if (!ind && !resp) { + /* TODO: error_log("Invalid message received") */ + return; + } + } else { modem_log(qmi->modem, LOGL_DEBUG, "Process message from srv %d msg %04x flag: %02x tid: %04x", msg->qmux.service, le16_to_cpu(msg->svc.message), msg->flags, msg->svc.transaction); - - if (msg->flags != QMI_CTL_FLAG_RESPONSE && msg->flags != QMI_SERVICE_FLAG_RESPONSE) - return; - - if (msg->qmux.service == QMI_SERVICE_CTL) - tid = msg->ctl.transaction; - else tid = le16_to_cpu(msg->svc.transaction); + ind = msg->flags & QMI_SERVICE_FLAG_INDICATION; + resp = msg->flags & QMI_SERVICE_FLAG_RESPONSE; + if (!ind && !resp) { + /* TODO: error_log("Invalid message received") */ + return; + } + } service = uqmi_service_find(qmi, msg->qmux.service); if (!service) { @@ -77,12 +83,19 @@ qmi_process_msg(struct qmi_dev *qmi, struct qmi_msg *msg) return; } - list_for_each_entry(req, &service->reqs, list) { - if (req->tid != tid) - continue; + /* Hopefully an indication *and* response isn't possible */ + if (ind) { + uqmi_service_handle_indication(service, msg); + } - __qmi_request_complete(service, req, msg); - return; + if (resp) { + list_for_each_entry(req, &service->reqs, list) { + if (req->tid != tid) + continue; + + __qmi_request_complete(service, req, msg); + return; + } } /* error_log("Couldn't find a tid for incoming message") */ @@ -221,4 +234,3 @@ void qmi_device_close(struct qmi_dev *qmi, int timeout_ms) uloop_timeout_set(&qmi->shutdown, timeout_ms); } } - diff --git a/uqmid/services.c b/uqmid/services.c index 1d50d3a..edd4252 100644 --- a/uqmid/services.c +++ b/uqmid/services.c @@ -54,6 +54,7 @@ uqmi_service_create(struct qmi_dev *qmi, int service_id) service->client_id = -1; list_add(&service->list, &qmi->services); + INIT_LIST_HEAD(&service->indications); INIT_LIST_HEAD(&service->reqs); return service; @@ -242,3 +243,64 @@ void uqmi_service_close(struct qmi_service *service) /* Control service is special */ uqmi_ctrl_release_clientid(service); } + +int uqmi_service_register_indication(struct qmi_service *service, uint16_t qmi_ind, indication_cb cb, void *cb_data) +{ + struct qmi_indication *indication; + + indication = talloc_zero(service, struct qmi_indication); + if (!indication) + return 1; + + indication->cb = cb; + indication->cb_data = cb_data; + indication->qmi_ind = qmi_ind; + list_add(&indication->list, &service->indications); + + return 0; +} + +int uqmi_service_remove_indication(struct qmi_service *service, uint16_t qmi_ind, indication_cb cb, void *cb_data) +{ + struct qmi_indication *indication, *tmp; + + list_for_each_entry_safe(indication, tmp, &service->indications, list) { + if (qmi_ind != indication->qmi_ind) + continue; + + if (indication->cb != cb) + continue; + + if (indication->cb_data != cb_data) + continue; + + list_del(&indication->list); + } + + return 0; +} + +int uqmi_service_handle_indication(struct qmi_service *service, struct qmi_msg *msg) +{ + uint16_t qmi_ind; + bool handled = false; + struct qmi_indication *indication, *tmp; + + if (msg->qmux.service == QMI_SERVICE_CTL) + qmi_ind = msg->ctl.message; + else + qmi_ind = msg->svc.message; + + + list_for_each_entry_safe(indication, tmp, &service->indications, list) { + if (qmi_ind != indication->qmi_ind) + continue; + + if (indication->cb) { + indication->cb(service, msg, indication->cb_data); + handled = true; + } + } + + return handled ? 0 : 1; +} diff --git a/uqmid/services.h b/uqmid/services.h index ed5594e..fa203c7 100644 --- a/uqmid/services.h +++ b/uqmid/services.h @@ -51,6 +51,23 @@ struct qmi_service { /* contains all pending requests */ struct list_head reqs; + + /* contains indication registers + * a sorted llist by qmi msg id + */ + struct list_head indications; +}; + +typedef void (*indication_cb)(struct qmi_service *service, struct qmi_msg *msg, void *data); +struct qmi_indication { + /* a sorted linked list by qmi_ind in indications */ + struct list_head list; + /* qmi_ind the qmi message id. + * Multiple callbacks can receive the same indication + */ + uint16_t qmi_ind; + indication_cb cb; + void *cb_data; }; struct qmi_service *uqmi_service_find(struct qmi_dev *qmi, int service_id); @@ -70,4 +87,10 @@ struct qmi_service *uqmi_service_create(struct qmi_dev *qmi, int service_id); void uqmi_service_get_client_id_cb(struct qmi_service *service, uint16_t client_id); void uqmi_service_close_cb(struct qmi_service *service); +/* indications */ + +int uqmi_service_register_indication(struct qmi_service *service, uint16_t indication, indication_cb cb, void *cb_data); +int uqmi_service_remove_indication(struct qmi_service *service, uint16_t indication, indication_cb cb, void *cb_data); +int uqmi_service_handle_indication(struct qmi_service *service, struct qmi_msg *msg); + #endif /* __UQMID_QMI_DEV_H */ -- 2.30.2