Loading samples/Kconfig +3 −3 Original line number Diff line number Diff line Loading @@ -62,11 +62,11 @@ config SAMPLE_KDB Build an example of how to dynamically add the hello command to the kdb shell. config SAMPLE_QRTR_CLIENT tristate "Build qrtr client sample -- loadable modules only" config SAMPLE_QMI_CLIENT tristate "Build qmi client sample -- loadable modules only" depends on QCOM_QMI_HELPERS && m help Build an qrtr client sample driver, which demonstrates how to Build an QMI client sample driver, which demonstrates how to communicate with a remote QRTR service, using QMI encoded messages. config SAMPLE_RPMSG_CLIENT Loading samples/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -3,4 +3,4 @@ obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ configfs/ connector/ v4l/ trace_printk/ blackfin/ \ vfio-mdev/ statx/ qrtr/ vfio-mdev/ statx/ qmi/ samples/qmi/Makefile 0 → 100644 +1 −0 Original line number Diff line number Diff line obj-$(CONFIG_SAMPLE_QMI_CLIENT) += qmi_sample_client.o samples/qrtr/qrtr_sample_client.c→samples/qmi/qmi_sample_client.c +160 −132 Original line number Diff line number Diff line /* * Sample QRTR client driver * Sample in-kernel QMI client driver * * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. * Copyright (C) 2017 Linaro Ltd. * * This software is licensed under the terms of the GNU General Public Loading @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/debugfs.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/qrtr.h> Loading Loading @@ -46,7 +47,7 @@ #define TEST_DATA_REQ_MAX_MSG_LEN_V01 8456 struct test_name_type_v01 { uint32_t name_len; u32 name_len; char name[TEST_MAX_NAME_SIZE_V01]; }; Loading @@ -54,7 +55,7 @@ static struct qmi_elem_info test_name_type_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct test_name_type_v01, Loading @@ -75,7 +76,7 @@ static struct qmi_elem_info test_name_type_v01_ei[] = { struct test_ping_req_msg_v01 { char ping[4]; uint8_t client_name_valid; u8 client_name_valid; struct test_name_type_v01 client_name; }; Loading @@ -92,7 +93,7 @@ struct qmi_elem_info test_ping_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = PING_OPT1_TLV_TYPE, .offset = offsetof(struct test_ping_req_msg_v01, Loading @@ -114,10 +115,10 @@ struct qmi_elem_info test_ping_req_msg_v01_ei[] = { struct test_ping_resp_msg_v01 { struct qmi_response_type_v01 resp; uint8_t pong_valid; u8 pong_valid; char pong[4]; uint8_t service_name_valid; u8 service_name_valid; struct test_name_type_v01 service_name; }; Loading @@ -135,7 +136,7 @@ struct qmi_elem_info test_ping_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = PING_OPT1_TLV_TYPE, .offset = offsetof(struct test_ping_resp_msg_v01, Loading @@ -153,7 +154,7 @@ struct qmi_elem_info test_ping_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = PING_OPT2_TLV_TYPE, .offset = offsetof(struct test_ping_resp_msg_v01, Loading @@ -173,10 +174,10 @@ struct qmi_elem_info test_ping_resp_msg_v01_ei[] = { }; struct test_data_req_msg_v01 { uint32_t data_len; uint8_t data[TEST_MED_DATA_SIZE_V01]; u32 data_len; u8 data[TEST_MED_DATA_SIZE_V01]; uint8_t client_name_valid; u8 client_name_valid; struct test_name_type_v01 client_name; }; Loading @@ -184,7 +185,7 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(uint32_t), .elem_size = sizeof(u32), .is_array = NO_ARRAY, .tlv_type = DATA_REQ1_TLV_TYPE, .offset = offsetof(struct test_data_req_msg_v01, Loading @@ -193,7 +194,7 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = TEST_MED_DATA_SIZE_V01, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = VAR_LEN_ARRAY, .tlv_type = DATA_REQ1_TLV_TYPE, .offset = offsetof(struct test_data_req_msg_v01, Loading @@ -202,7 +203,7 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_req_msg_v01, Loading @@ -224,11 +225,11 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { struct test_data_resp_msg_v01 { struct qmi_response_type_v01 resp; uint8_t data_valid; uint32_t data_len; uint8_t data[TEST_MED_DATA_SIZE_V01]; u8 data_valid; u32 data_len; u8 data[TEST_MED_DATA_SIZE_V01]; uint8_t service_name_valid; u8 service_name_valid; struct test_name_type_v01 service_name; }; Loading @@ -246,7 +247,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -255,7 +256,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(uint32_t), .elem_size = sizeof(u32), .is_array = NO_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -264,7 +265,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = TEST_MED_DATA_SIZE_V01, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = VAR_LEN_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -273,7 +274,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = DATA_OPT2_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -293,11 +294,11 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { }; /* * ping_pong_store() - ping_pong attribute store handler * @dev: sample device context * @attr: the ping_pong attribute * @buf: write buffer * @count: length of @buf * ping_write() - ping_pong debugfs file write handler * @file: debugfs file context * @user_buf: reference to the user data (ignored) * @count: number of bytes in @user_buf * @ppos: offset in @file to write * * Returns @count, or negative errno on failure. * Loading @@ -306,11 +307,10 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { * transaction. It serves as an example of how to provide a custom response * handler. */ static ssize_t ping_pong_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t ping_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct qmi_handle *qmi = dev_get_drvdata(dev); struct qmi_handle *qmi = file->private_data; struct test_ping_req_msg_v01 req = {0}; struct qmi_txn txn; int ret; Loading @@ -321,8 +321,7 @@ static ssize_t ping_pong_store(struct device *dev, if (ret < 0) return ret; ret = qmi_send_message(qmi, NULL, &txn, QMI_REQUEST, ret = qmi_send_request(qmi, NULL, &txn, TEST_PING_REQ_MSG_ID_V01, TEST_PING_REQ_MAX_MSG_LEN_V01, test_ping_req_msg_v01_ei, &req); Loading @@ -337,7 +336,11 @@ static ssize_t ping_pong_store(struct device *dev, return count; } static DEVICE_ATTR_WO(ping_pong); static const struct file_operations ping_fops = { .open = simple_open, .write = ping_write, }; static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) Loading @@ -358,11 +361,11 @@ static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, } /* * data_store() - data attribute store handler * @dev: sample device context * @attr: the data attribute * @buf: buffer with message to encode * @count: length of @buf * data_write() - data debugfs file write handler * @file: debugfs file context * @user_buf: reference to the user data * @count: number of bytes in @user_buf * @ppos: offset in @file to write * * Returns @count, or negative errno on failure. * Loading @@ -371,10 +374,11 @@ static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, * transaction. It serves as an example of how to have the QMI helpers decode a * transaction response into a provided object automatically. */ static ssize_t data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t data_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct qmi_handle *qmi = dev_get_drvdata(dev); struct qmi_handle *qmi = file->private_data; struct test_data_resp_msg_v01 *resp; struct test_data_req_msg_v01 *req; struct qmi_txn txn; Loading @@ -391,51 +395,50 @@ static ssize_t data_store(struct device *dev, struct device_attribute *attr, } req->data_len = min_t(size_t, sizeof(req->data), count); memcpy(req->data, buf, req->data_len); if (copy_from_user(req->data, user_buf, req->data_len)) { ret = -EFAULT; goto out; } ret = qmi_txn_init(qmi, &txn, test_data_resp_msg_v01_ei, resp); if (ret < 0) { count = ret; if (ret < 0) goto out; } ret = qmi_send_message(qmi, NULL, &txn, QMI_REQUEST, ret = qmi_send_request(qmi, NULL, &txn, TEST_DATA_REQ_MSG_ID_V01, TEST_DATA_REQ_MAX_MSG_LEN_V01, test_data_req_msg_v01_ei, req); if (ret < 0) { qmi_txn_cancel(&txn); count = ret; goto out; } ret = qmi_txn_wait(&txn, 5 * HZ); if (ret < 0) { count = ret; goto out; } else if (!resp->data_valid || resp->data_len != req->data_len || memcmp(resp->data, req->data, req->data_len)) { pr_err("response data doesn't match expectation\n"); count = -EINVAL; ret = -EINVAL; goto out; } ret = count; out: kfree(resp); kfree(req); return count; return ret; } static DEVICE_ATTR_WO(data); static struct attribute *qrtr_dev_attrs[] = { &dev_attr_ping_pong.attr, &dev_attr_data.attr, NULL static const struct file_operations data_fops = { .open = simple_open, .write = data_write, }; ATTRIBUTE_GROUPS(qrtr_dev); static struct qmi_msg_handler qrtr_sample_handlers[] = { static struct qmi_msg_handler qmi_sample_handlers[] = { { .type = QMI_RESPONSE, .msg_id = TEST_PING_REQ_MSG_ID_V01, Loading @@ -446,67 +449,106 @@ static struct qmi_msg_handler qrtr_sample_handlers[] = { {} }; static int qrtr_sample_probe(struct platform_device *pdev) struct qmi_sample { struct qmi_handle qmi; struct dentry *de_dir; struct dentry *de_data; struct dentry *de_ping; }; static struct dentry *qmi_debug_dir; static int qmi_sample_probe(struct platform_device *pdev) { struct qrtr_handle *qrtr; struct qmi_handle *qmi; struct sockaddr_qrtr *sq; struct qmi_sample *sample; char path[20]; int ret; qmi = devm_kzalloc(&pdev->dev, sizeof(*qmi), GFP_KERNEL); if (!qmi) sample = devm_kzalloc(&pdev->dev, sizeof(*sample), GFP_KERNEL); if (!sample) return -ENOMEM; qrtr = &qmi->qrtr; ret = qmi_client_init(qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01, qrtr_sample_handlers); ret = qmi_handle_init(&sample->qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01, NULL, qmi_sample_handlers); if (ret < 0) return ret; sq = dev_get_platdata(&pdev->dev); ret = kernel_connect(qrtr->sock, (struct sockaddr *)sq, ret = kernel_connect(sample->qmi.sock, (struct sockaddr *)sq, sizeof(*sq), 0); if (ret < 0) { pr_err("failed to connect to remote service port\n"); qmi_client_release(qmi); return ret; goto err_release_qmi_handle; } platform_set_drvdata(pdev, qmi); snprintf(path, sizeof(path), "%d:%d", sq->sq_node, sq->sq_port); sample->de_dir = debugfs_create_dir(path, qmi_debug_dir); if (IS_ERR(sample->de_dir)) { ret = PTR_ERR(sample->de_dir); goto err_release_qmi_handle; } sample->de_data = debugfs_create_file("data", 0600, sample->de_dir, sample, &data_fops); if (IS_ERR(sample->de_data)) { ret = PTR_ERR(sample->de_data); goto err_remove_de_dir; } sample->de_ping = debugfs_create_file("ping", 0600, sample->de_dir, sample, &ping_fops); if (IS_ERR(sample->de_ping)) { ret = PTR_ERR(sample->de_ping); goto err_remove_de_data; } platform_set_drvdata(pdev, sample); return 0; err_remove_de_data: debugfs_remove(sample->de_data); err_remove_de_dir: debugfs_remove(sample->de_dir); err_release_qmi_handle: qmi_handle_release(&sample->qmi); return ret; } static int qrtr_sample_remove(struct platform_device *pdev) static int qmi_sample_remove(struct platform_device *pdev) { struct qmi_handle *qmi = platform_get_drvdata(pdev); struct qmi_sample *sample = platform_get_drvdata(pdev); debugfs_remove(sample->de_ping); debugfs_remove(sample->de_data); debugfs_remove(sample->de_dir); qmi_client_release(qmi); qmi_handle_release(&sample->qmi); return 0; } static struct platform_driver qrtr_sample_driver = { .probe = qrtr_sample_probe, .remove = qrtr_sample_remove, static struct platform_driver qmi_sample_driver = { .probe = qmi_sample_probe, .remove = qmi_sample_remove, .driver = { .name = "qrtr_sample_client", .name = "qmi_sample_client", }, }; static int qrtr_sample_new_server(struct qrtr_handle *qrtr, struct qrtr_service *service) static int qmi_sample_new_server(struct qmi_handle *qmi, struct qmi_service *service) { struct platform_device *pdev; struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port }; char name[32]; int ret; snprintf(name, sizeof(name), "qrtr_sample_client@%d:%d", service->node, service->port); pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); pdev = platform_device_alloc("qmi_sample_client", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; Loading @@ -514,13 +556,11 @@ static int qrtr_sample_new_server(struct qrtr_handle *qrtr, if (ret) goto err_put_device; pdev->dev.groups = qrtr_dev_groups; pdev->driver_override = (char *)qrtr_sample_driver.driver.name; ret = platform_device_add(pdev); if (ret) goto err_put_device; service->cookie = pdev; service->priv = pdev; return 0; Loading @@ -530,74 +570,62 @@ static int qrtr_sample_new_server(struct qrtr_handle *qrtr, return ret; } static void qrtr_sample_del_server(struct qrtr_handle *qrtr, struct qrtr_service *service) static void qmi_sample_del_server(struct qmi_handle *qmi, struct qmi_service *service) { struct platform_device *pdev = service->cookie; struct platform_device *pdev = service->priv; platform_device_unregister(pdev); } static struct qrtr_handle lookup_client; static struct qmi_handle lookup_client; static struct qrtr_handle_ops lookup_ops; static struct qmi_ops lookup_ops = { .new_server = qmi_sample_new_server, .del_server = qmi_sample_del_server, }; static void qrtr_sample_net_reset_work(struct work_struct *work) static int qmi_sample_init(void) { int ret; qrtr_client_release(&lookup_client); ret = qrtr_client_init(&lookup_client, 0, &lookup_ops); if (ret < 0) return; qrtr_client_new_lookup(&lookup_client, 15, 0); } static DECLARE_WORK(net_reset_work, qrtr_sample_net_reset_work); static void qrtr_sample_net_reset(struct qrtr_handle *qrtr) { schedule_work(&net_reset_work); qmi_debug_dir = debugfs_create_dir("qmi_sample", NULL); if (IS_ERR(qmi_debug_dir)) { pr_err("failed to create qmi_sample dir\n"); return PTR_ERR(qmi_debug_dir); } static struct qrtr_handle_ops lookup_ops = { .new_server = qrtr_sample_new_server, .del_server = qrtr_sample_del_server, .net_reset = qrtr_sample_net_reset, }; static int qrtr_sample_init(void) { int ret; ret = platform_driver_register(&qrtr_sample_driver); ret = platform_driver_register(&qmi_sample_driver); if (ret) return ret; goto err_remove_debug_dir; ret = qrtr_client_init(&lookup_client, 0, &lookup_ops); ret = qmi_handle_init(&lookup_client, 0, &lookup_ops, NULL); if (ret < 0) goto err_unregister_driver; qrtr_client_new_lookup(&lookup_client, 15, 0); qmi_add_lookup(&lookup_client, 15, 0, 0); return 0; err_unregister_driver: platform_driver_unregister(&qrtr_sample_driver); platform_driver_unregister(&qmi_sample_driver); err_remove_debug_dir: debugfs_remove(qmi_debug_dir); return ret; } static void qrtr_sample_exit(void) static void qmi_sample_exit(void) { qrtr_client_release(&lookup_client); qmi_handle_release(&lookup_client); platform_driver_unregister(&qmi_sample_driver); platform_driver_unregister(&qrtr_sample_driver); debugfs_remove(qmi_debug_dir); } module_init(qrtr_sample_init); module_exit(qrtr_sample_exit); module_init(qmi_sample_init); module_exit(qmi_sample_exit); MODULE_DESCRIPTION("Sample QRTR client driver"); MODULE_DESCRIPTION("Sample QMI client driver"); MODULE_LICENSE("GPL v2"); samples/qrtr/Makefiledeleted 100644 → 0 +0 −1 Original line number Diff line number Diff line obj-$(CONFIG_SAMPLE_QRTR_CLIENT) += qrtr_sample_client.o Loading
samples/Kconfig +3 −3 Original line number Diff line number Diff line Loading @@ -62,11 +62,11 @@ config SAMPLE_KDB Build an example of how to dynamically add the hello command to the kdb shell. config SAMPLE_QRTR_CLIENT tristate "Build qrtr client sample -- loadable modules only" config SAMPLE_QMI_CLIENT tristate "Build qmi client sample -- loadable modules only" depends on QCOM_QMI_HELPERS && m help Build an qrtr client sample driver, which demonstrates how to Build an QMI client sample driver, which demonstrates how to communicate with a remote QRTR service, using QMI encoded messages. config SAMPLE_RPMSG_CLIENT Loading
samples/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -3,4 +3,4 @@ obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ configfs/ connector/ v4l/ trace_printk/ blackfin/ \ vfio-mdev/ statx/ qrtr/ vfio-mdev/ statx/ qmi/
samples/qmi/Makefile 0 → 100644 +1 −0 Original line number Diff line number Diff line obj-$(CONFIG_SAMPLE_QMI_CLIENT) += qmi_sample_client.o
samples/qrtr/qrtr_sample_client.c→samples/qmi/qmi_sample_client.c +160 −132 Original line number Diff line number Diff line /* * Sample QRTR client driver * Sample in-kernel QMI client driver * * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. * Copyright (C) 2017 Linaro Ltd. * * This software is licensed under the terms of the GNU General Public Loading @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/debugfs.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/qrtr.h> Loading Loading @@ -46,7 +47,7 @@ #define TEST_DATA_REQ_MAX_MSG_LEN_V01 8456 struct test_name_type_v01 { uint32_t name_len; u32 name_len; char name[TEST_MAX_NAME_SIZE_V01]; }; Loading @@ -54,7 +55,7 @@ static struct qmi_elem_info test_name_type_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct test_name_type_v01, Loading @@ -75,7 +76,7 @@ static struct qmi_elem_info test_name_type_v01_ei[] = { struct test_ping_req_msg_v01 { char ping[4]; uint8_t client_name_valid; u8 client_name_valid; struct test_name_type_v01 client_name; }; Loading @@ -92,7 +93,7 @@ struct qmi_elem_info test_ping_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = PING_OPT1_TLV_TYPE, .offset = offsetof(struct test_ping_req_msg_v01, Loading @@ -114,10 +115,10 @@ struct qmi_elem_info test_ping_req_msg_v01_ei[] = { struct test_ping_resp_msg_v01 { struct qmi_response_type_v01 resp; uint8_t pong_valid; u8 pong_valid; char pong[4]; uint8_t service_name_valid; u8 service_name_valid; struct test_name_type_v01 service_name; }; Loading @@ -135,7 +136,7 @@ struct qmi_elem_info test_ping_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = PING_OPT1_TLV_TYPE, .offset = offsetof(struct test_ping_resp_msg_v01, Loading @@ -153,7 +154,7 @@ struct qmi_elem_info test_ping_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = PING_OPT2_TLV_TYPE, .offset = offsetof(struct test_ping_resp_msg_v01, Loading @@ -173,10 +174,10 @@ struct qmi_elem_info test_ping_resp_msg_v01_ei[] = { }; struct test_data_req_msg_v01 { uint32_t data_len; uint8_t data[TEST_MED_DATA_SIZE_V01]; u32 data_len; u8 data[TEST_MED_DATA_SIZE_V01]; uint8_t client_name_valid; u8 client_name_valid; struct test_name_type_v01 client_name; }; Loading @@ -184,7 +185,7 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(uint32_t), .elem_size = sizeof(u32), .is_array = NO_ARRAY, .tlv_type = DATA_REQ1_TLV_TYPE, .offset = offsetof(struct test_data_req_msg_v01, Loading @@ -193,7 +194,7 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = TEST_MED_DATA_SIZE_V01, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = VAR_LEN_ARRAY, .tlv_type = DATA_REQ1_TLV_TYPE, .offset = offsetof(struct test_data_req_msg_v01, Loading @@ -202,7 +203,7 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_req_msg_v01, Loading @@ -224,11 +225,11 @@ struct qmi_elem_info test_data_req_msg_v01_ei[] = { struct test_data_resp_msg_v01 { struct qmi_response_type_v01 resp; uint8_t data_valid; uint32_t data_len; uint8_t data[TEST_MED_DATA_SIZE_V01]; u8 data_valid; u32 data_len; u8 data[TEST_MED_DATA_SIZE_V01]; uint8_t service_name_valid; u8 service_name_valid; struct test_name_type_v01 service_name; }; Loading @@ -246,7 +247,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -255,7 +256,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(uint32_t), .elem_size = sizeof(u32), .is_array = NO_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -264,7 +265,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = TEST_MED_DATA_SIZE_V01, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = VAR_LEN_ARRAY, .tlv_type = DATA_OPT1_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -273,7 +274,7 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(uint8_t), .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = DATA_OPT2_TLV_TYPE, .offset = offsetof(struct test_data_resp_msg_v01, Loading @@ -293,11 +294,11 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { }; /* * ping_pong_store() - ping_pong attribute store handler * @dev: sample device context * @attr: the ping_pong attribute * @buf: write buffer * @count: length of @buf * ping_write() - ping_pong debugfs file write handler * @file: debugfs file context * @user_buf: reference to the user data (ignored) * @count: number of bytes in @user_buf * @ppos: offset in @file to write * * Returns @count, or negative errno on failure. * Loading @@ -306,11 +307,10 @@ struct qmi_elem_info test_data_resp_msg_v01_ei[] = { * transaction. It serves as an example of how to provide a custom response * handler. */ static ssize_t ping_pong_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t ping_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct qmi_handle *qmi = dev_get_drvdata(dev); struct qmi_handle *qmi = file->private_data; struct test_ping_req_msg_v01 req = {0}; struct qmi_txn txn; int ret; Loading @@ -321,8 +321,7 @@ static ssize_t ping_pong_store(struct device *dev, if (ret < 0) return ret; ret = qmi_send_message(qmi, NULL, &txn, QMI_REQUEST, ret = qmi_send_request(qmi, NULL, &txn, TEST_PING_REQ_MSG_ID_V01, TEST_PING_REQ_MAX_MSG_LEN_V01, test_ping_req_msg_v01_ei, &req); Loading @@ -337,7 +336,11 @@ static ssize_t ping_pong_store(struct device *dev, return count; } static DEVICE_ATTR_WO(ping_pong); static const struct file_operations ping_fops = { .open = simple_open, .write = ping_write, }; static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) Loading @@ -358,11 +361,11 @@ static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, } /* * data_store() - data attribute store handler * @dev: sample device context * @attr: the data attribute * @buf: buffer with message to encode * @count: length of @buf * data_write() - data debugfs file write handler * @file: debugfs file context * @user_buf: reference to the user data * @count: number of bytes in @user_buf * @ppos: offset in @file to write * * Returns @count, or negative errno on failure. * Loading @@ -371,10 +374,11 @@ static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, * transaction. It serves as an example of how to have the QMI helpers decode a * transaction response into a provided object automatically. */ static ssize_t data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t data_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct qmi_handle *qmi = dev_get_drvdata(dev); struct qmi_handle *qmi = file->private_data; struct test_data_resp_msg_v01 *resp; struct test_data_req_msg_v01 *req; struct qmi_txn txn; Loading @@ -391,51 +395,50 @@ static ssize_t data_store(struct device *dev, struct device_attribute *attr, } req->data_len = min_t(size_t, sizeof(req->data), count); memcpy(req->data, buf, req->data_len); if (copy_from_user(req->data, user_buf, req->data_len)) { ret = -EFAULT; goto out; } ret = qmi_txn_init(qmi, &txn, test_data_resp_msg_v01_ei, resp); if (ret < 0) { count = ret; if (ret < 0) goto out; } ret = qmi_send_message(qmi, NULL, &txn, QMI_REQUEST, ret = qmi_send_request(qmi, NULL, &txn, TEST_DATA_REQ_MSG_ID_V01, TEST_DATA_REQ_MAX_MSG_LEN_V01, test_data_req_msg_v01_ei, req); if (ret < 0) { qmi_txn_cancel(&txn); count = ret; goto out; } ret = qmi_txn_wait(&txn, 5 * HZ); if (ret < 0) { count = ret; goto out; } else if (!resp->data_valid || resp->data_len != req->data_len || memcmp(resp->data, req->data, req->data_len)) { pr_err("response data doesn't match expectation\n"); count = -EINVAL; ret = -EINVAL; goto out; } ret = count; out: kfree(resp); kfree(req); return count; return ret; } static DEVICE_ATTR_WO(data); static struct attribute *qrtr_dev_attrs[] = { &dev_attr_ping_pong.attr, &dev_attr_data.attr, NULL static const struct file_operations data_fops = { .open = simple_open, .write = data_write, }; ATTRIBUTE_GROUPS(qrtr_dev); static struct qmi_msg_handler qrtr_sample_handlers[] = { static struct qmi_msg_handler qmi_sample_handlers[] = { { .type = QMI_RESPONSE, .msg_id = TEST_PING_REQ_MSG_ID_V01, Loading @@ -446,67 +449,106 @@ static struct qmi_msg_handler qrtr_sample_handlers[] = { {} }; static int qrtr_sample_probe(struct platform_device *pdev) struct qmi_sample { struct qmi_handle qmi; struct dentry *de_dir; struct dentry *de_data; struct dentry *de_ping; }; static struct dentry *qmi_debug_dir; static int qmi_sample_probe(struct platform_device *pdev) { struct qrtr_handle *qrtr; struct qmi_handle *qmi; struct sockaddr_qrtr *sq; struct qmi_sample *sample; char path[20]; int ret; qmi = devm_kzalloc(&pdev->dev, sizeof(*qmi), GFP_KERNEL); if (!qmi) sample = devm_kzalloc(&pdev->dev, sizeof(*sample), GFP_KERNEL); if (!sample) return -ENOMEM; qrtr = &qmi->qrtr; ret = qmi_client_init(qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01, qrtr_sample_handlers); ret = qmi_handle_init(&sample->qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01, NULL, qmi_sample_handlers); if (ret < 0) return ret; sq = dev_get_platdata(&pdev->dev); ret = kernel_connect(qrtr->sock, (struct sockaddr *)sq, ret = kernel_connect(sample->qmi.sock, (struct sockaddr *)sq, sizeof(*sq), 0); if (ret < 0) { pr_err("failed to connect to remote service port\n"); qmi_client_release(qmi); return ret; goto err_release_qmi_handle; } platform_set_drvdata(pdev, qmi); snprintf(path, sizeof(path), "%d:%d", sq->sq_node, sq->sq_port); sample->de_dir = debugfs_create_dir(path, qmi_debug_dir); if (IS_ERR(sample->de_dir)) { ret = PTR_ERR(sample->de_dir); goto err_release_qmi_handle; } sample->de_data = debugfs_create_file("data", 0600, sample->de_dir, sample, &data_fops); if (IS_ERR(sample->de_data)) { ret = PTR_ERR(sample->de_data); goto err_remove_de_dir; } sample->de_ping = debugfs_create_file("ping", 0600, sample->de_dir, sample, &ping_fops); if (IS_ERR(sample->de_ping)) { ret = PTR_ERR(sample->de_ping); goto err_remove_de_data; } platform_set_drvdata(pdev, sample); return 0; err_remove_de_data: debugfs_remove(sample->de_data); err_remove_de_dir: debugfs_remove(sample->de_dir); err_release_qmi_handle: qmi_handle_release(&sample->qmi); return ret; } static int qrtr_sample_remove(struct platform_device *pdev) static int qmi_sample_remove(struct platform_device *pdev) { struct qmi_handle *qmi = platform_get_drvdata(pdev); struct qmi_sample *sample = platform_get_drvdata(pdev); debugfs_remove(sample->de_ping); debugfs_remove(sample->de_data); debugfs_remove(sample->de_dir); qmi_client_release(qmi); qmi_handle_release(&sample->qmi); return 0; } static struct platform_driver qrtr_sample_driver = { .probe = qrtr_sample_probe, .remove = qrtr_sample_remove, static struct platform_driver qmi_sample_driver = { .probe = qmi_sample_probe, .remove = qmi_sample_remove, .driver = { .name = "qrtr_sample_client", .name = "qmi_sample_client", }, }; static int qrtr_sample_new_server(struct qrtr_handle *qrtr, struct qrtr_service *service) static int qmi_sample_new_server(struct qmi_handle *qmi, struct qmi_service *service) { struct platform_device *pdev; struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port }; char name[32]; int ret; snprintf(name, sizeof(name), "qrtr_sample_client@%d:%d", service->node, service->port); pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); pdev = platform_device_alloc("qmi_sample_client", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; Loading @@ -514,13 +556,11 @@ static int qrtr_sample_new_server(struct qrtr_handle *qrtr, if (ret) goto err_put_device; pdev->dev.groups = qrtr_dev_groups; pdev->driver_override = (char *)qrtr_sample_driver.driver.name; ret = platform_device_add(pdev); if (ret) goto err_put_device; service->cookie = pdev; service->priv = pdev; return 0; Loading @@ -530,74 +570,62 @@ static int qrtr_sample_new_server(struct qrtr_handle *qrtr, return ret; } static void qrtr_sample_del_server(struct qrtr_handle *qrtr, struct qrtr_service *service) static void qmi_sample_del_server(struct qmi_handle *qmi, struct qmi_service *service) { struct platform_device *pdev = service->cookie; struct platform_device *pdev = service->priv; platform_device_unregister(pdev); } static struct qrtr_handle lookup_client; static struct qmi_handle lookup_client; static struct qrtr_handle_ops lookup_ops; static struct qmi_ops lookup_ops = { .new_server = qmi_sample_new_server, .del_server = qmi_sample_del_server, }; static void qrtr_sample_net_reset_work(struct work_struct *work) static int qmi_sample_init(void) { int ret; qrtr_client_release(&lookup_client); ret = qrtr_client_init(&lookup_client, 0, &lookup_ops); if (ret < 0) return; qrtr_client_new_lookup(&lookup_client, 15, 0); } static DECLARE_WORK(net_reset_work, qrtr_sample_net_reset_work); static void qrtr_sample_net_reset(struct qrtr_handle *qrtr) { schedule_work(&net_reset_work); qmi_debug_dir = debugfs_create_dir("qmi_sample", NULL); if (IS_ERR(qmi_debug_dir)) { pr_err("failed to create qmi_sample dir\n"); return PTR_ERR(qmi_debug_dir); } static struct qrtr_handle_ops lookup_ops = { .new_server = qrtr_sample_new_server, .del_server = qrtr_sample_del_server, .net_reset = qrtr_sample_net_reset, }; static int qrtr_sample_init(void) { int ret; ret = platform_driver_register(&qrtr_sample_driver); ret = platform_driver_register(&qmi_sample_driver); if (ret) return ret; goto err_remove_debug_dir; ret = qrtr_client_init(&lookup_client, 0, &lookup_ops); ret = qmi_handle_init(&lookup_client, 0, &lookup_ops, NULL); if (ret < 0) goto err_unregister_driver; qrtr_client_new_lookup(&lookup_client, 15, 0); qmi_add_lookup(&lookup_client, 15, 0, 0); return 0; err_unregister_driver: platform_driver_unregister(&qrtr_sample_driver); platform_driver_unregister(&qmi_sample_driver); err_remove_debug_dir: debugfs_remove(qmi_debug_dir); return ret; } static void qrtr_sample_exit(void) static void qmi_sample_exit(void) { qrtr_client_release(&lookup_client); qmi_handle_release(&lookup_client); platform_driver_unregister(&qmi_sample_driver); platform_driver_unregister(&qrtr_sample_driver); debugfs_remove(qmi_debug_dir); } module_init(qrtr_sample_init); module_exit(qrtr_sample_exit); module_init(qmi_sample_init); module_exit(qmi_sample_exit); MODULE_DESCRIPTION("Sample QRTR client driver"); MODULE_DESCRIPTION("Sample QMI client driver"); MODULE_LICENSE("GPL v2");
samples/qrtr/Makefiledeleted 100644 → 0 +0 −1 Original line number Diff line number Diff line obj-$(CONFIG_SAMPLE_QRTR_CLIENT) += qrtr_sample_client.o