blob: b701be85d099169337cb2b05f33888ec8be94d3a [file] [log] [blame]
Karthikeyan Ramasubramaniana9859e82012-07-12 13:10:42 -06001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <linux/delay.h>
18#include <linux/debugfs.h>
19#include <linux/qmi_encdec.h>
20
21#include <asm/uaccess.h>
22
23#include <mach/msm_qmi_interface.h>
24
25#include "kernel_test_service_v01.h"
26
27#define TEST_SERVICE_SVC_ID 0x0000000f
28#define TEST_SERVICE_INS_ID 1
29
30static int test_rep_cnt = 10;
31module_param_named(rep_cnt, test_rep_cnt, int, S_IRUGO | S_IWUSR | S_IWGRP);
32
33static int test_data_sz = 50;
34module_param_named(data_sz, test_data_sz, int, S_IRUGO | S_IWUSR | S_IWGRP);
35
36static int test_clnt_debug_mask;
37module_param_named(debug_mask, test_clnt_debug_mask,
38 int, S_IRUGO | S_IWUSR | S_IWGRP);
39
40#define D(x...) do { \
41 if (test_clnt_debug_mask) \
42 pr_debug(x); \
43} while (0)
44
45/* Variable to initiate the test through debugfs interface */
46static struct dentry *test_dent;
47
48/* Test client port for IPC Router */
49static struct qmi_handle *test_clnt;
50static int test_clnt_reset;
51
52/* Reader thread to receive responses & indications */
53static void test_clnt_recv_msg(struct work_struct *work);
54static DECLARE_DELAYED_WORK(work_recv_msg, test_clnt_recv_msg);
55static void test_clnt_svc_arrive(struct work_struct *work);
56static DECLARE_DELAYED_WORK(work_svc_arrive, test_clnt_svc_arrive);
57static void test_clnt_svc_exit(struct work_struct *work);
58static DECLARE_DELAYED_WORK(work_svc_exit, test_clnt_svc_exit);
59static struct workqueue_struct *test_clnt_workqueue;
60
61/* Variable to hold the test result */
62static int test_res;
63
Zaheerulla Meeraef869c2013-05-27 20:03:30 +053064static unsigned int callback_count;
65static void test_async_resp_cb(struct qmi_handle *handle,
66 unsigned int msg_id, void *msg,
67 void *resp_cb_data, int stat)
68{
69 callback_count++;
70 if (stat == 0)
71 D("%s invoked %d time(s): [RESP_LEN] = %d, [RESP_VALID] = %d",
72 __func__, callback_count,
73 ((struct test_data_resp_msg_v01 *)msg)->data_len,
74 ((struct test_data_resp_msg_v01 *)msg)->data_valid);
75 else if (stat < 0)
76 pr_err("%s: Request Failed [MSG_ID]: %d, [ERR_ID]: %d, [Callback_count]: %d",
77 __func__, msg_id, stat, callback_count);
78
79 kfree(msg);
80 kfree(resp_cb_data);
81}
82
Karthikeyan Ramasubramaniana9859e82012-07-12 13:10:42 -060083static int test_qmi_ping_pong_send_sync_msg(void)
84{
85 struct test_ping_req_msg_v01 req;
86 struct test_ping_resp_msg_v01 resp;
87 struct msg_desc req_desc, resp_desc;
88 int rc;
89
90 memcpy(req.ping, "ping", sizeof(req.ping));
91 req.client_name_valid = 0;
92
93 req_desc.max_msg_len = TEST_PING_REQ_MAX_MSG_LEN_V01;
94 req_desc.msg_id = TEST_PING_REQ_MSG_ID_V01;
95 req_desc.ei_array = test_ping_req_msg_v01_ei;
96
97 resp_desc.max_msg_len = TEST_PING_REQ_MAX_MSG_LEN_V01;
98 resp_desc.msg_id = TEST_PING_REQ_MSG_ID_V01;
99 resp_desc.ei_array = test_ping_resp_msg_v01_ei;
100
101 rc = qmi_send_req_wait(test_clnt, &req_desc, &req, sizeof(req),
102 &resp_desc, &resp, sizeof(resp), 0);
103 if (rc < 0) {
104 pr_err("%s: send req failed %d\n", __func__, rc);
105 return rc;
106 }
107
108 D("%s: Received %s response\n", __func__, resp.pong);
109 return rc;
110}
111
112static int test_qmi_data_send_sync_msg(unsigned int data_len)
113{
114 struct test_data_req_msg_v01 *req;
115 struct test_data_resp_msg_v01 *resp;
116 struct msg_desc req_desc, resp_desc;
117 int rc, i;
118
119 req = kzalloc(sizeof(struct test_data_req_msg_v01), GFP_KERNEL);
120 if (!req) {
121 pr_err("%s: Data req msg alloc failed\n", __func__);
122 return -ENOMEM;
123 }
124
125 resp = kzalloc(sizeof(struct test_data_resp_msg_v01), GFP_KERNEL);
126 if (!resp) {
127 pr_err("%s: Data resp msg alloc failed\n", __func__);
128 kfree(req);
129 return -ENOMEM;
130 }
131
132 req->data_len = data_len;
133 for (i = 0; i < data_len; i = i + sizeof(int))
134 memcpy(req->data + i, (uint8_t *)&i, sizeof(int));
135 req->client_name_valid = 0;
136
137 req_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
138 req_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01;
139 req_desc.ei_array = test_data_req_msg_v01_ei;
140
141 resp_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
142 resp_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01;
143 resp_desc.ei_array = test_data_resp_msg_v01_ei;
144
145 rc = qmi_send_req_wait(test_clnt, &req_desc, req, sizeof(*req),
146 &resp_desc, resp, sizeof(*resp), 0);
147 if (rc < 0) {
148 pr_err("%s: send req failed\n", __func__);
149 goto data_send_err;
150 }
151
152 D("%s: data_valid %d\n", __func__, resp->data_valid);
153 D("%s: data_len %d\n", __func__, resp->data_len);
154data_send_err:
155 kfree(resp);
156 kfree(req);
157 return rc;
158}
159
Zaheerulla Meeraef869c2013-05-27 20:03:30 +0530160static int test_qmi_data_send_async_msg(unsigned int data_len)
161{
162 struct test_data_req_msg_v01 *req;
163 struct test_data_resp_msg_v01 *resp;
164 struct msg_desc req_desc, *resp_desc;
165 int rc, i;
166
167 req = kzalloc(sizeof(struct test_data_req_msg_v01), GFP_KERNEL);
168 if (!req) {
169 pr_err("%s: Data req msg alloc failed\n", __func__);
170 return -ENOMEM;
171 }
172
173 resp = kzalloc(sizeof(struct test_data_resp_msg_v01), GFP_KERNEL);
174 if (!resp) {
175 pr_err("%s: Data resp msg alloc failed\n", __func__);
176 kfree(req);
177 return -ENOMEM;
178 }
179
180 resp_desc = kzalloc(sizeof(struct msg_desc), GFP_KERNEL);
181 if (!resp_desc) {
182 pr_err("%s: Resp_desc msg alloc failed\n", __func__);
183 kfree(req);
184 kfree(resp);
185 return -ENOMEM;
186 }
187
188 req->data_len = data_len;
189 for (i = 0; i < data_len; i = i + sizeof(int))
190 memcpy(req->data + i, (uint8_t *)&i, sizeof(int));
191 req->client_name_valid = 0;
192
193 req_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
194 req_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01;
195 req_desc.ei_array = test_data_req_msg_v01_ei;
196
197 resp_desc->max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
198 resp_desc->msg_id = TEST_DATA_REQ_MSG_ID_V01;
199 resp_desc->ei_array = test_data_resp_msg_v01_ei;
200
201 rc = qmi_send_req_nowait(test_clnt, &req_desc, req, sizeof(*req),
202 resp_desc, resp, sizeof(*resp),
203 test_async_resp_cb, (void *)resp_desc);
204 if (rc < 0) {
205 pr_err("%s: send req failed\n", __func__);
206 kfree(resp);
207 kfree(resp_desc);
208 }
209 kfree(req);
210 return rc;
211}
212
Karthikeyan Ramasubramaniana9859e82012-07-12 13:10:42 -0600213static void test_clnt_recv_msg(struct work_struct *work)
214{
215 int rc;
216
Zaheerulla Meeraef869c2013-05-27 20:03:30 +0530217 do {
218 D("%s: Notified about a Receive Event", __func__);
219 } while ((rc = qmi_recv_msg(test_clnt)) == 0);
220
221 if (rc != -ENOMSG)
Karthikeyan Ramasubramaniana9859e82012-07-12 13:10:42 -0600222 pr_err("%s: Error receiving message\n", __func__);
223}
224
225static void test_clnt_notify(struct qmi_handle *handle,
226 enum qmi_event_type event, void *notify_priv)
227{
228 switch (event) {
229 case QMI_RECV_MSG:
230 queue_delayed_work(test_clnt_workqueue,
231 &work_recv_msg, 0);
232 break;
233 default:
234 break;
235 }
236}
237
238static void test_clnt_svc_arrive(struct work_struct *work)
239{
240 int rc;
241
242 D("%s begins\n", __func__);
243
244 /* Create a Local client port for QMI communication */
245 test_clnt = qmi_handle_create(test_clnt_notify, NULL);
246 if (!test_clnt) {
247 pr_err("%s: QMI client handle alloc failed\n", __func__);
248 return;
249 }
250
251 D("%s: Lookup server name\n", __func__);
252 rc = qmi_connect_to_service(test_clnt, TEST_SERVICE_SVC_ID,
253 TEST_SERVICE_INS_ID);
254 if (rc < 0) {
255 pr_err("%s: Server not found\n", __func__);
256 qmi_handle_destroy(test_clnt);
257 test_clnt = NULL;
258 return;
259 }
260 test_clnt_reset = 0;
261 D("%s complete\n", __func__);
262}
263
264static void test_clnt_svc_exit(struct work_struct *work)
265{
266 D("%s begins\n", __func__);
267
268 qmi_handle_destroy(test_clnt);
269 test_clnt_reset = 1;
270 test_clnt = NULL;
271
272 D("%s complete\n", __func__);
273}
274
275static int test_clnt_svc_event_notify(struct notifier_block *this,
276 unsigned long code,
277 void *_cmd)
278{
279 D("%s: event %ld\n", __func__, code);
280 switch (code) {
281 case QMI_SERVER_ARRIVE:
282 queue_delayed_work(test_clnt_workqueue,
283 &work_svc_arrive, 0);
284 break;
285 case QMI_SERVER_EXIT:
286 queue_delayed_work(test_clnt_workqueue,
287 &work_svc_exit, 0);
288 break;
289 default:
290 break;
291 }
292 return 0;
293}
294
295static int test_qmi_open(struct inode *ip, struct file *fp)
296{
297 if (!test_clnt) {
298 pr_err("%s Test client is not initialized\n", __func__);
299 return -ENODEV;
300 }
301 return 0;
302}
303
304static ssize_t test_qmi_read(struct file *fp, char __user *buf,
305 size_t count, loff_t *pos)
306{
307 char _buf[16];
308 snprintf(_buf, sizeof(_buf), "%d\n", test_res);
309 test_res = 0;
310 return simple_read_from_buffer(buf, count, pos,
311 _buf, strnlen(_buf, 16));
312}
313
314static int test_qmi_release(struct inode *ip, struct file *fp)
315{
316 return 0;
317}
318
319static ssize_t test_qmi_write(struct file *fp, const char __user *buf,
320 size_t count, loff_t *pos)
321{
322 unsigned char cmd[64];
323 int len;
324 int i;
325
326 if (count < 1)
327 return 0;
328
329 len = min(count, (sizeof(cmd) - 1));
330
331 if (copy_from_user(cmd, buf, len))
332 return -EFAULT;
333
334 cmd[len] = 0;
335 if (cmd[len-1] == '\n') {
336 cmd[len-1] = 0;
337 len--;
338 }
339
340 if (!strncmp(cmd, "ping_pong", sizeof(cmd))) {
341 for (i = 0; i < test_rep_cnt; i++) {
342 test_res = test_qmi_ping_pong_send_sync_msg();
343 if (test_res == -ENETRESET || test_clnt_reset) {
344 do {
345 msleep(50);
346 } while (test_clnt_reset);
347 }
348 }
349 } else if (!strncmp(cmd, "data", sizeof(cmd))) {
350 for (i = 0; i < test_rep_cnt; i++) {
351 test_res = test_qmi_data_send_sync_msg(test_data_sz);
352 if (test_res == -ENETRESET || test_clnt_reset) {
353 do {
354 msleep(50);
355 } while (test_clnt_reset);
356 }
357 }
Zaheerulla Meeraef869c2013-05-27 20:03:30 +0530358 } else if (!strncmp(cmd, "data_async", sizeof(cmd))) {
359 int i;
360 callback_count = 0;
361 for (i = 0; i < test_rep_cnt; i++) {
362 test_res = test_qmi_data_send_async_msg(test_data_sz);
363 if (test_res == -ENETRESET || test_clnt_reset) {
364 --i;
365 do {
366 msleep(50);
367 } while (test_clnt_reset);
368 } else if (test_res < 0) {
369 --i;
370 pr_err("%s: Error sending txn, aborting now",
371 __func__);
372 break;
373 }
374 }
375 while (callback_count < i) {
376 if (test_clnt_reset) {
377 pr_err("%s: Service Exited", __func__);
378 break;
379 }
380 msleep(50);
381 }
382 D("%s complete\n", __func__);
383 callback_count = 0;
Karthikeyan Ramasubramaniana9859e82012-07-12 13:10:42 -0600384 } else {
385 test_res = -EINVAL;
386 }
387 return count;
388}
389
390static struct notifier_block test_clnt_nb = {
391 .notifier_call = test_clnt_svc_event_notify,
392};
393
394static const struct file_operations debug_ops = {
395 .owner = THIS_MODULE,
396 .open = test_qmi_open,
397 .read = test_qmi_read,
398 .write = test_qmi_write,
399 .release = test_qmi_release,
400};
401
402static int __init test_qmi_init(void)
403{
404 int rc;
405
406 test_clnt_workqueue = create_singlethread_workqueue("test_clnt");
407 if (!test_clnt_workqueue)
408 return -EFAULT;
409
410 rc = qmi_svc_event_notifier_register(TEST_SERVICE_SVC_ID,
411 TEST_SERVICE_INS_ID, &test_clnt_nb);
412 if (rc < 0) {
413 pr_err("%s: notifier register failed\n", __func__);
414 destroy_workqueue(test_clnt_workqueue);
415 return rc;
416 }
417
418 test_dent = debugfs_create_file("test_qmi_client", 0444, 0,
419 NULL, &debug_ops);
420 if (IS_ERR(test_dent)) {
421 pr_err("%s: unable to create debugfs %ld\n",
422 __func__, IS_ERR(test_dent));
423 test_dent = NULL;
424 qmi_svc_event_notifier_unregister(TEST_SERVICE_SVC_ID,
425 TEST_SERVICE_INS_ID, &test_clnt_nb);
426 destroy_workqueue(test_clnt_workqueue);
427 return -EFAULT;
428 }
429
430 return 0;
431}
432
433static void __exit test_qmi_exit(void)
434{
435 qmi_svc_event_notifier_unregister(TEST_SERVICE_SVC_ID,
436 TEST_SERVICE_INS_ID, &test_clnt_nb);
437 destroy_workqueue(test_clnt_workqueue);
438 debugfs_remove(test_dent);
439}
440
441module_init(test_qmi_init);
442module_exit(test_qmi_exit);
443
444MODULE_DESCRIPTION("TEST QMI Client Driver");
445MODULE_LICENSE("GPL v2");