8 #define __qmi_service(_n) [__##_n] = _n
9 static const uint8_t qmi_services[__QMI_SERVICE_LAST] = {
20 void dump_packet(const char *prefix, void *ptr, int len)
22 unsigned char *data = ptr;
25 fprintf(stderr, "%s:", prefix);
26 for (i = 0; i < len; i++)
27 fprintf(stderr, " %02x", data[i]);
28 fprintf(stderr, "\n");
33 qmi_get_service_idx(QmiService svc)
37 for (i = 0; i < ARRAY_SIZE(qmi_services); i++)
38 if (qmi_services[i] == svc)
44 static void __qmi_request_complete(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
56 tlv_buf = qmi_msg_get_tlv_buf(msg, &tlv_len);
57 req->ret = qmi_check_message_status(tlv_buf, tlv_len);
62 req->cb(qmi, req, msg);
65 *req->complete = true;
66 uloop_cancelled = true;
70 static void qmi_process_msg(struct qmi_dev *qmi, struct qmi_msg *msg)
72 struct qmi_request *req;
75 if (msg->qmux.service == QMI_SERVICE_CTL)
76 tid = msg->ctl.transaction;
78 tid = le16_to_cpu(msg->svc.transaction);
80 list_for_each_entry(req, &qmi->req, list) {
81 if (req->service != msg->qmux.service)
87 __qmi_request_complete(qmi, req, msg);
92 static void qmi_notify_read(struct ustream *us, int bytes)
94 struct qmi_dev *qmi = container_of(us, struct qmi_dev, sf.stream);
101 buf = ustream_get_read_buf(us, &len);
105 if (len < offsetof(struct qmi_msg, flags))
108 msg = (struct qmi_msg *) buf;
109 msg_len = le16_to_cpu(msg->qmux.len) + 1;
113 dump_packet("Received packet", msg, msg_len);
114 qmi_process_msg(qmi, msg);
115 ustream_consume(us, msg_len);
119 int qmi_request_start(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, request_cb cb)
121 int len = qmi_complete_request_message(msg);
126 memset(req, 0, sizeof(*req));
128 req->service = msg->qmux.service;
129 if (req->service == QMI_SERVICE_CTL) {
130 tid = qmi->ctl_tid++;
131 msg->ctl.transaction = tid;
133 int idx = qmi_get_service_idx(req->service);
138 tid = qmi->service_data[idx].tid++;
139 msg->svc.transaction = cpu_to_le16(tid);
140 msg->qmux.client = qmi->service_data[idx].client_id;
146 list_add(&req->list, &qmi->req);
148 dump_packet("Send packet", msg, len);
149 ustream_write(&qmi->sf.stream, (void *) msg, len, false);
153 void qmi_request_cancel(struct qmi_dev *qmi, struct qmi_request *req)
156 __qmi_request_complete(qmi, req, NULL);
159 int qmi_request_wait(struct qmi_dev *qmi, struct qmi_request *req)
161 bool complete = false;
168 *req->complete = true;
170 req->complete = &complete;
172 cancelled = uloop_cancelled;
173 uloop_cancelled = false;
175 uloop_cancelled = cancelled;
178 if (req->complete == &complete)
179 req->complete = NULL;
184 struct qmi_connect_request {
185 struct qmi_request req;
189 static void qmi_connect_service_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
191 struct qmi_ctl_allocate_cid_response res;
192 struct qmi_connect_request *creq = container_of(req, struct qmi_connect_request, req);
197 qmi_parse_ctl_allocate_cid_response(msg, &res);
198 creq->cid = res.data.allocation_info.cid;
201 int qmi_service_connect(struct qmi_dev *qmi, QmiService svc, int client_id)
203 struct qmi_ctl_allocate_cid_request creq = {
204 QMI_INIT(service, svc)
206 struct qmi_connect_request req;
207 int idx = qmi_get_service_idx(svc);
208 struct qmi_msg *msg = &msgbuf.msg;
213 if (qmi->service_connected & (1 << idx))
217 qmi_set_ctl_allocate_cid_request(msg, &creq);
218 qmi_request_start(qmi, &req.req, msg, qmi_connect_service_cb);
219 qmi_request_wait(qmi, &req.req);
227 qmi->service_data[idx].connected = true;
228 qmi->service_data[idx].client_id = client_id;
229 qmi->service_data[idx].tid = 1;
230 qmi->service_connected |= (1 << idx);
235 static void __qmi_service_disconnect(struct qmi_dev *qmi, int idx)
237 int client_id = qmi->service_data[idx].client_id;
238 struct qmi_ctl_release_cid_request creq = {
239 QMI_INIT_SEQUENCE(release_info,
240 .service = qmi_services[idx],
244 struct qmi_request req;
245 struct qmi_msg *msg = &msgbuf.msg;
247 qmi->service_connected &= ~(1 << idx);
248 qmi->service_data[idx].client_id = -1;
249 qmi->service_data[idx].tid = 0;
251 qmi_set_ctl_release_cid_request(msg, &creq);
252 qmi_request_start(qmi, &req, msg, NULL);
253 qmi_request_wait(qmi, &req);
256 static void qmi_close_all_services(struct qmi_dev *qmi)
258 uint32_t connected = qmi->service_connected;
261 for (idx = 0; connected; idx++, connected >>= 1) {
262 if (!(connected & 1))
265 if (qmi->service_keep_cid & (1 << idx))
268 __qmi_service_disconnect(qmi, idx);
272 int qmi_service_get_client_id(struct qmi_dev *qmi, QmiService svc)
274 int idx = qmi_get_service_idx(svc);
279 qmi->service_keep_cid |= (1 << idx);
280 return qmi->service_data[idx].client_id;
283 int qmi_device_open(struct qmi_dev *qmi, const char *path)
285 struct ustream *us = &qmi->sf.stream;
290 fd = open(path, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
294 us->notify_read = qmi_notify_read;
295 ustream_fd_init(&qmi->sf, fd);
296 INIT_LIST_HEAD(&qmi->req);
302 void qmi_device_close(struct qmi_dev *qmi)
304 struct qmi_request *req;
307 qmi_close_all_services(qmi);
308 ustream_free(&qmi->sf.stream);
309 close(qmi->sf.fd.fd);
311 while (!list_empty(&qmi->req)) {
312 req = list_first_entry(&qmi->req, struct qmi_request, list);
313 qmi_request_cancel(qmi, req);
317 QmiService qmi_service_get_by_name(const char *str)
319 static const struct {
323 { "dms", QMI_SERVICE_DMS },
324 { "nas", QMI_SERVICE_NAS },
325 { "pds", QMI_SERVICE_PDS },
326 { "wds", QMI_SERVICE_WDS },
327 { "wms", QMI_SERVICE_WMS },
331 for (i = 0; i < ARRAY_SIZE(services); i++) {
332 if (!strcasecmp(str, services[i].name))
333 return services[i].svc;