uqmid: service: add indications support
authorAlexander Couzens <[email protected]>
Fri, 19 Apr 2024 12:31:13 +0000 (14:31 +0200)
committerDavid Bauer <[email protected]>
Sat, 31 May 2025 20:41:00 +0000 (22:41 +0200)
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 <[email protected]>
uqmid/ddev.c
uqmid/services.c
uqmid/services.h

index 5bfc3c0317f5fa7cccee5bf156e012addbcc7f84..c9a69a94e1b9a10227752bd3f17f4401b8f83016 100644 (file)
@@ -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);
        }
 }
-
index 1d50d3a03e24a0b75b5241b5b91f8005107de38e..edd425212b4fa4a963c8fd919d112d25b50aacc2 100644 (file)
@@ -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;
+}
index ed5594edd0637dfa2d0b03b4ecd08e4d6be9debc..fa203c76d9cff119f3851622c1ef634b573a2b36 100644 (file)
@@ -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 */