0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/debugfs.h>
0011 #include <linux/device.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/qrtr.h>
0014 #include <linux/net.h>
0015 #include <linux/completion.h>
0016 #include <linux/idr.h>
0017 #include <linux/string.h>
0018 #include <net/sock.h>
0019 #include <linux/soc/qcom/qmi.h>
0020
0021 #define PING_REQ1_TLV_TYPE 0x1
0022 #define PING_RESP1_TLV_TYPE 0x2
0023 #define PING_OPT1_TLV_TYPE 0x10
0024 #define PING_OPT2_TLV_TYPE 0x11
0025
0026 #define DATA_REQ1_TLV_TYPE 0x1
0027 #define DATA_RESP1_TLV_TYPE 0x2
0028 #define DATA_OPT1_TLV_TYPE 0x10
0029 #define DATA_OPT2_TLV_TYPE 0x11
0030
0031 #define TEST_MED_DATA_SIZE_V01 8192
0032 #define TEST_MAX_NAME_SIZE_V01 255
0033
0034 #define TEST_PING_REQ_MSG_ID_V01 0x20
0035 #define TEST_DATA_REQ_MSG_ID_V01 0x21
0036
0037 #define TEST_PING_REQ_MAX_MSG_LEN_V01 266
0038 #define TEST_DATA_REQ_MAX_MSG_LEN_V01 8456
0039
0040 struct test_name_type_v01 {
0041 u32 name_len;
0042 char name[TEST_MAX_NAME_SIZE_V01];
0043 };
0044
0045 static struct qmi_elem_info test_name_type_v01_ei[] = {
0046 {
0047 .data_type = QMI_DATA_LEN,
0048 .elem_len = 1,
0049 .elem_size = sizeof(u8),
0050 .array_type = NO_ARRAY,
0051 .tlv_type = QMI_COMMON_TLV_TYPE,
0052 .offset = offsetof(struct test_name_type_v01,
0053 name_len),
0054 },
0055 {
0056 .data_type = QMI_UNSIGNED_1_BYTE,
0057 .elem_len = TEST_MAX_NAME_SIZE_V01,
0058 .elem_size = sizeof(char),
0059 .array_type = VAR_LEN_ARRAY,
0060 .tlv_type = QMI_COMMON_TLV_TYPE,
0061 .offset = offsetof(struct test_name_type_v01,
0062 name),
0063 },
0064 {}
0065 };
0066
0067 struct test_ping_req_msg_v01 {
0068 char ping[4];
0069
0070 u8 client_name_valid;
0071 struct test_name_type_v01 client_name;
0072 };
0073
0074 static struct qmi_elem_info test_ping_req_msg_v01_ei[] = {
0075 {
0076 .data_type = QMI_UNSIGNED_1_BYTE,
0077 .elem_len = 4,
0078 .elem_size = sizeof(char),
0079 .array_type = STATIC_ARRAY,
0080 .tlv_type = PING_REQ1_TLV_TYPE,
0081 .offset = offsetof(struct test_ping_req_msg_v01,
0082 ping),
0083 },
0084 {
0085 .data_type = QMI_OPT_FLAG,
0086 .elem_len = 1,
0087 .elem_size = sizeof(u8),
0088 .array_type = NO_ARRAY,
0089 .tlv_type = PING_OPT1_TLV_TYPE,
0090 .offset = offsetof(struct test_ping_req_msg_v01,
0091 client_name_valid),
0092 },
0093 {
0094 .data_type = QMI_STRUCT,
0095 .elem_len = 1,
0096 .elem_size = sizeof(struct test_name_type_v01),
0097 .array_type = NO_ARRAY,
0098 .tlv_type = PING_OPT1_TLV_TYPE,
0099 .offset = offsetof(struct test_ping_req_msg_v01,
0100 client_name),
0101 .ei_array = test_name_type_v01_ei,
0102 },
0103 {}
0104 };
0105
0106 struct test_ping_resp_msg_v01 {
0107 struct qmi_response_type_v01 resp;
0108
0109 u8 pong_valid;
0110 char pong[4];
0111
0112 u8 service_name_valid;
0113 struct test_name_type_v01 service_name;
0114 };
0115
0116 static struct qmi_elem_info test_ping_resp_msg_v01_ei[] = {
0117 {
0118 .data_type = QMI_STRUCT,
0119 .elem_len = 1,
0120 .elem_size = sizeof(struct qmi_response_type_v01),
0121 .array_type = NO_ARRAY,
0122 .tlv_type = PING_RESP1_TLV_TYPE,
0123 .offset = offsetof(struct test_ping_resp_msg_v01,
0124 resp),
0125 .ei_array = qmi_response_type_v01_ei,
0126 },
0127 {
0128 .data_type = QMI_OPT_FLAG,
0129 .elem_len = 1,
0130 .elem_size = sizeof(u8),
0131 .array_type = NO_ARRAY,
0132 .tlv_type = PING_OPT1_TLV_TYPE,
0133 .offset = offsetof(struct test_ping_resp_msg_v01,
0134 pong_valid),
0135 },
0136 {
0137 .data_type = QMI_UNSIGNED_1_BYTE,
0138 .elem_len = 4,
0139 .elem_size = sizeof(char),
0140 .array_type = STATIC_ARRAY,
0141 .tlv_type = PING_OPT1_TLV_TYPE,
0142 .offset = offsetof(struct test_ping_resp_msg_v01,
0143 pong),
0144 },
0145 {
0146 .data_type = QMI_OPT_FLAG,
0147 .elem_len = 1,
0148 .elem_size = sizeof(u8),
0149 .array_type = NO_ARRAY,
0150 .tlv_type = PING_OPT2_TLV_TYPE,
0151 .offset = offsetof(struct test_ping_resp_msg_v01,
0152 service_name_valid),
0153 },
0154 {
0155 .data_type = QMI_STRUCT,
0156 .elem_len = 1,
0157 .elem_size = sizeof(struct test_name_type_v01),
0158 .array_type = NO_ARRAY,
0159 .tlv_type = PING_OPT2_TLV_TYPE,
0160 .offset = offsetof(struct test_ping_resp_msg_v01,
0161 service_name),
0162 .ei_array = test_name_type_v01_ei,
0163 },
0164 {}
0165 };
0166
0167 struct test_data_req_msg_v01 {
0168 u32 data_len;
0169 u8 data[TEST_MED_DATA_SIZE_V01];
0170
0171 u8 client_name_valid;
0172 struct test_name_type_v01 client_name;
0173 };
0174
0175 static struct qmi_elem_info test_data_req_msg_v01_ei[] = {
0176 {
0177 .data_type = QMI_DATA_LEN,
0178 .elem_len = 1,
0179 .elem_size = sizeof(u32),
0180 .array_type = NO_ARRAY,
0181 .tlv_type = DATA_REQ1_TLV_TYPE,
0182 .offset = offsetof(struct test_data_req_msg_v01,
0183 data_len),
0184 },
0185 {
0186 .data_type = QMI_UNSIGNED_1_BYTE,
0187 .elem_len = TEST_MED_DATA_SIZE_V01,
0188 .elem_size = sizeof(u8),
0189 .array_type = VAR_LEN_ARRAY,
0190 .tlv_type = DATA_REQ1_TLV_TYPE,
0191 .offset = offsetof(struct test_data_req_msg_v01,
0192 data),
0193 },
0194 {
0195 .data_type = QMI_OPT_FLAG,
0196 .elem_len = 1,
0197 .elem_size = sizeof(u8),
0198 .array_type = NO_ARRAY,
0199 .tlv_type = DATA_OPT1_TLV_TYPE,
0200 .offset = offsetof(struct test_data_req_msg_v01,
0201 client_name_valid),
0202 },
0203 {
0204 .data_type = QMI_STRUCT,
0205 .elem_len = 1,
0206 .elem_size = sizeof(struct test_name_type_v01),
0207 .array_type = NO_ARRAY,
0208 .tlv_type = DATA_OPT1_TLV_TYPE,
0209 .offset = offsetof(struct test_data_req_msg_v01,
0210 client_name),
0211 .ei_array = test_name_type_v01_ei,
0212 },
0213 {}
0214 };
0215
0216 struct test_data_resp_msg_v01 {
0217 struct qmi_response_type_v01 resp;
0218
0219 u8 data_valid;
0220 u32 data_len;
0221 u8 data[TEST_MED_DATA_SIZE_V01];
0222
0223 u8 service_name_valid;
0224 struct test_name_type_v01 service_name;
0225 };
0226
0227 static struct qmi_elem_info test_data_resp_msg_v01_ei[] = {
0228 {
0229 .data_type = QMI_STRUCT,
0230 .elem_len = 1,
0231 .elem_size = sizeof(struct qmi_response_type_v01),
0232 .array_type = NO_ARRAY,
0233 .tlv_type = DATA_RESP1_TLV_TYPE,
0234 .offset = offsetof(struct test_data_resp_msg_v01,
0235 resp),
0236 .ei_array = qmi_response_type_v01_ei,
0237 },
0238 {
0239 .data_type = QMI_OPT_FLAG,
0240 .elem_len = 1,
0241 .elem_size = sizeof(u8),
0242 .array_type = NO_ARRAY,
0243 .tlv_type = DATA_OPT1_TLV_TYPE,
0244 .offset = offsetof(struct test_data_resp_msg_v01,
0245 data_valid),
0246 },
0247 {
0248 .data_type = QMI_DATA_LEN,
0249 .elem_len = 1,
0250 .elem_size = sizeof(u32),
0251 .array_type = NO_ARRAY,
0252 .tlv_type = DATA_OPT1_TLV_TYPE,
0253 .offset = offsetof(struct test_data_resp_msg_v01,
0254 data_len),
0255 },
0256 {
0257 .data_type = QMI_UNSIGNED_1_BYTE,
0258 .elem_len = TEST_MED_DATA_SIZE_V01,
0259 .elem_size = sizeof(u8),
0260 .array_type = VAR_LEN_ARRAY,
0261 .tlv_type = DATA_OPT1_TLV_TYPE,
0262 .offset = offsetof(struct test_data_resp_msg_v01,
0263 data),
0264 },
0265 {
0266 .data_type = QMI_OPT_FLAG,
0267 .elem_len = 1,
0268 .elem_size = sizeof(u8),
0269 .array_type = NO_ARRAY,
0270 .tlv_type = DATA_OPT2_TLV_TYPE,
0271 .offset = offsetof(struct test_data_resp_msg_v01,
0272 service_name_valid),
0273 },
0274 {
0275 .data_type = QMI_STRUCT,
0276 .elem_len = 1,
0277 .elem_size = sizeof(struct test_name_type_v01),
0278 .array_type = NO_ARRAY,
0279 .tlv_type = DATA_OPT2_TLV_TYPE,
0280 .offset = offsetof(struct test_data_resp_msg_v01,
0281 service_name),
0282 .ei_array = test_name_type_v01_ei,
0283 },
0284 {}
0285 };
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 static ssize_t ping_write(struct file *file, const char __user *user_buf,
0302 size_t count, loff_t *ppos)
0303 {
0304 struct qmi_handle *qmi = file->private_data;
0305 struct test_ping_req_msg_v01 req = {};
0306 struct qmi_txn txn;
0307 int ret;
0308
0309 memcpy(req.ping, "ping", sizeof(req.ping));
0310
0311 ret = qmi_txn_init(qmi, &txn, NULL, NULL);
0312 if (ret < 0)
0313 return ret;
0314
0315 ret = qmi_send_request(qmi, NULL, &txn,
0316 TEST_PING_REQ_MSG_ID_V01,
0317 TEST_PING_REQ_MAX_MSG_LEN_V01,
0318 test_ping_req_msg_v01_ei, &req);
0319 if (ret < 0) {
0320 qmi_txn_cancel(&txn);
0321 return ret;
0322 }
0323
0324 ret = qmi_txn_wait(&txn, 5 * HZ);
0325 if (ret < 0)
0326 count = ret;
0327
0328 return count;
0329 }
0330
0331 static const struct file_operations ping_fops = {
0332 .open = simple_open,
0333 .write = ping_write,
0334 };
0335
0336 static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
0337 struct qmi_txn *txn, const void *data)
0338 {
0339 const struct test_ping_resp_msg_v01 *resp = data;
0340
0341 if (!txn) {
0342 pr_err("spurious ping response\n");
0343 return;
0344 }
0345
0346 if (resp->resp.result == QMI_RESULT_FAILURE_V01)
0347 txn->result = -ENXIO;
0348 else if (!resp->pong_valid || memcmp(resp->pong, "pong", 4))
0349 txn->result = -EINVAL;
0350
0351 complete(&txn->completion);
0352 }
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368 static ssize_t data_write(struct file *file, const char __user *user_buf,
0369 size_t count, loff_t *ppos)
0370
0371 {
0372 struct qmi_handle *qmi = file->private_data;
0373 struct test_data_resp_msg_v01 *resp;
0374 struct test_data_req_msg_v01 *req;
0375 struct qmi_txn txn;
0376 int ret;
0377
0378 req = kzalloc(sizeof(*req), GFP_KERNEL);
0379 if (!req)
0380 return -ENOMEM;
0381
0382 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
0383 if (!resp) {
0384 kfree(req);
0385 return -ENOMEM;
0386 }
0387
0388 req->data_len = min_t(size_t, sizeof(req->data), count);
0389 if (copy_from_user(req->data, user_buf, req->data_len)) {
0390 ret = -EFAULT;
0391 goto out;
0392 }
0393
0394 ret = qmi_txn_init(qmi, &txn, test_data_resp_msg_v01_ei, resp);
0395 if (ret < 0)
0396 goto out;
0397
0398 ret = qmi_send_request(qmi, NULL, &txn,
0399 TEST_DATA_REQ_MSG_ID_V01,
0400 TEST_DATA_REQ_MAX_MSG_LEN_V01,
0401 test_data_req_msg_v01_ei, req);
0402 if (ret < 0) {
0403 qmi_txn_cancel(&txn);
0404 goto out;
0405 }
0406
0407 ret = qmi_txn_wait(&txn, 5 * HZ);
0408 if (ret < 0) {
0409 goto out;
0410 } else if (!resp->data_valid ||
0411 resp->data_len != req->data_len ||
0412 memcmp(resp->data, req->data, req->data_len)) {
0413 pr_err("response data doesn't match expectation\n");
0414 ret = -EINVAL;
0415 goto out;
0416 }
0417
0418 ret = count;
0419
0420 out:
0421 kfree(resp);
0422 kfree(req);
0423
0424 return ret;
0425 }
0426
0427 static const struct file_operations data_fops = {
0428 .open = simple_open,
0429 .write = data_write,
0430 };
0431
0432 static const struct qmi_msg_handler qmi_sample_handlers[] = {
0433 {
0434 .type = QMI_RESPONSE,
0435 .msg_id = TEST_PING_REQ_MSG_ID_V01,
0436 .ei = test_ping_resp_msg_v01_ei,
0437 .decoded_size = sizeof(struct test_ping_req_msg_v01),
0438 .fn = ping_pong_cb
0439 },
0440 {}
0441 };
0442
0443 struct qmi_sample {
0444 struct qmi_handle qmi;
0445
0446 struct dentry *de_dir;
0447 struct dentry *de_data;
0448 struct dentry *de_ping;
0449 };
0450
0451 static struct dentry *qmi_debug_dir;
0452
0453 static int qmi_sample_probe(struct platform_device *pdev)
0454 {
0455 struct sockaddr_qrtr *sq;
0456 struct qmi_sample *sample;
0457 char path[20];
0458 int ret;
0459
0460 sample = devm_kzalloc(&pdev->dev, sizeof(*sample), GFP_KERNEL);
0461 if (!sample)
0462 return -ENOMEM;
0463
0464 ret = qmi_handle_init(&sample->qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01,
0465 NULL,
0466 qmi_sample_handlers);
0467 if (ret < 0)
0468 return ret;
0469
0470 sq = dev_get_platdata(&pdev->dev);
0471 ret = kernel_connect(sample->qmi.sock, (struct sockaddr *)sq,
0472 sizeof(*sq), 0);
0473 if (ret < 0) {
0474 pr_err("failed to connect to remote service port\n");
0475 goto err_release_qmi_handle;
0476 }
0477
0478 snprintf(path, sizeof(path), "%d:%d", sq->sq_node, sq->sq_port);
0479
0480 sample->de_dir = debugfs_create_dir(path, qmi_debug_dir);
0481 if (IS_ERR(sample->de_dir)) {
0482 ret = PTR_ERR(sample->de_dir);
0483 goto err_release_qmi_handle;
0484 }
0485
0486 sample->de_data = debugfs_create_file("data", 0600, sample->de_dir,
0487 sample, &data_fops);
0488 if (IS_ERR(sample->de_data)) {
0489 ret = PTR_ERR(sample->de_data);
0490 goto err_remove_de_dir;
0491 }
0492
0493 sample->de_ping = debugfs_create_file("ping", 0600, sample->de_dir,
0494 sample, &ping_fops);
0495 if (IS_ERR(sample->de_ping)) {
0496 ret = PTR_ERR(sample->de_ping);
0497 goto err_remove_de_data;
0498 }
0499
0500 platform_set_drvdata(pdev, sample);
0501
0502 return 0;
0503
0504 err_remove_de_data:
0505 debugfs_remove(sample->de_data);
0506 err_remove_de_dir:
0507 debugfs_remove(sample->de_dir);
0508 err_release_qmi_handle:
0509 qmi_handle_release(&sample->qmi);
0510
0511 return ret;
0512 }
0513
0514 static int qmi_sample_remove(struct platform_device *pdev)
0515 {
0516 struct qmi_sample *sample = platform_get_drvdata(pdev);
0517
0518 debugfs_remove(sample->de_ping);
0519 debugfs_remove(sample->de_data);
0520 debugfs_remove(sample->de_dir);
0521
0522 qmi_handle_release(&sample->qmi);
0523
0524 return 0;
0525 }
0526
0527 static struct platform_driver qmi_sample_driver = {
0528 .probe = qmi_sample_probe,
0529 .remove = qmi_sample_remove,
0530 .driver = {
0531 .name = "qmi_sample_client",
0532 },
0533 };
0534
0535 static int qmi_sample_new_server(struct qmi_handle *qmi,
0536 struct qmi_service *service)
0537 {
0538 struct platform_device *pdev;
0539 struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
0540 int ret;
0541
0542 pdev = platform_device_alloc("qmi_sample_client", PLATFORM_DEVID_AUTO);
0543 if (!pdev)
0544 return -ENOMEM;
0545
0546 ret = platform_device_add_data(pdev, &sq, sizeof(sq));
0547 if (ret)
0548 goto err_put_device;
0549
0550 ret = platform_device_add(pdev);
0551 if (ret)
0552 goto err_put_device;
0553
0554 service->priv = pdev;
0555
0556 return 0;
0557
0558 err_put_device:
0559 platform_device_put(pdev);
0560
0561 return ret;
0562 }
0563
0564 static void qmi_sample_del_server(struct qmi_handle *qmi,
0565 struct qmi_service *service)
0566 {
0567 struct platform_device *pdev = service->priv;
0568
0569 platform_device_unregister(pdev);
0570 }
0571
0572 static struct qmi_handle lookup_client;
0573
0574 static const struct qmi_ops lookup_ops = {
0575 .new_server = qmi_sample_new_server,
0576 .del_server = qmi_sample_del_server,
0577 };
0578
0579 static int qmi_sample_init(void)
0580 {
0581 int ret;
0582
0583 qmi_debug_dir = debugfs_create_dir("qmi_sample", NULL);
0584 if (IS_ERR(qmi_debug_dir)) {
0585 pr_err("failed to create qmi_sample dir\n");
0586 return PTR_ERR(qmi_debug_dir);
0587 }
0588
0589 ret = platform_driver_register(&qmi_sample_driver);
0590 if (ret)
0591 goto err_remove_debug_dir;
0592
0593 ret = qmi_handle_init(&lookup_client, 0, &lookup_ops, NULL);
0594 if (ret < 0)
0595 goto err_unregister_driver;
0596
0597 qmi_add_lookup(&lookup_client, 15, 0, 0);
0598
0599 return 0;
0600
0601 err_unregister_driver:
0602 platform_driver_unregister(&qmi_sample_driver);
0603 err_remove_debug_dir:
0604 debugfs_remove(qmi_debug_dir);
0605
0606 return ret;
0607 }
0608
0609 static void qmi_sample_exit(void)
0610 {
0611 qmi_handle_release(&lookup_client);
0612
0613 platform_driver_unregister(&qmi_sample_driver);
0614
0615 debugfs_remove(qmi_debug_dir);
0616 }
0617
0618 module_init(qmi_sample_init);
0619 module_exit(qmi_sample_exit);
0620
0621 MODULE_DESCRIPTION("Sample QMI client driver");
0622 MODULE_LICENSE("GPL v2");