Loading drivers/soc/qcom/service-notifier.c +179 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/err.h> #include <linux/debugfs.h> #include <linux/uaccess.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> Loading Loading @@ -60,6 +62,7 @@ #define QMI_STATE_MAX_VAL QMI_SERVREG_NOTIF_SERVICE_STATE_ENUM_TYPE_MAX_VAL_V01 #define SERVER_TIMEOUT 500 #define MAX_STRING_LEN 100 /* * Per user service data structure Loading Loading @@ -659,3 +662,179 @@ int service_notif_unregister_notifier(void *service_notif_handle, &service_notif->service_notif_rcvr_list, nb); } EXPORT_SYMBOL(service_notif_unregister_notifier); struct service_notifier_test_data { char service_path[MAX_STRING_LEN]; int instance_id; struct notifier_block nb; void *service_notif_handle; }; static struct service_notifier_test_data test_data; static void print_service_provider_state(int notification, char *type) { if (notification == SERVREG_NOTIF_SERVICE_STATE_DOWN_V01) pr_info("%s: Service %s down!\n", type, test_data.service_path); else if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01) pr_info("%s: Service %s up!\n", type, test_data.service_path); else if (notification == SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01) pr_info("%s: Service %s state uninit!\n", type, test_data.service_path); else pr_info("%s: Service %s state Unknown 0x%x!\n", type, test_data.service_path, notification); } static int nb_callback(struct notifier_block *nb, unsigned long notification, void *data) { print_service_provider_state((int)notification, "Notification:"); return 0; } static ssize_t show_service_path(struct seq_file *f, void *unused) { if (test_data.service_notif_handle) seq_printf(f, "Service Path: %s\n", test_data.service_path); else seq_puts(f, "No existing notifier\n"); return 0; } static ssize_t set_service_notifier_register(struct file *fp, const char __user *buf, size_t count, loff_t *ppos) { int curr_state = INT_MAX, rc; if (!buf) return -EIO; if (test_data.service_notif_handle) { service_notif_unregister_notifier( test_data.service_notif_handle, &test_data.nb); test_data.service_notif_handle = NULL; pr_info("Unregistering existing notifier for %s\n", test_data.service_path); } rc = simple_write_to_buffer(test_data.service_path, MAX_STRING_LEN, ppos, buf, count - 1); if (rc != count - 1) { pr_err("Unable to read data into kernel buffer\n"); goto err; } test_data.nb.notifier_call = nb_callback; test_data.service_notif_handle = service_notif_register_notifier( test_data.service_path, test_data.instance_id, &test_data.nb, &curr_state); if (!IS_ERR(test_data.service_notif_handle)) { pr_info("Notifier Registered for service %s\n", test_data.service_path); print_service_provider_state(curr_state, "Initial State"); return count; } err: test_data.service_notif_handle = NULL; pr_err("Unable to register notifier for %s\n", test_data.service_path); return -EIO; } static int open_service_notifier_register(struct inode *inode, struct file *f) { return single_open(f, (void *) show_service_path, inode->i_private); } static const struct file_operations service_notifier_register_fops = { .open = open_service_notifier_register, .read = seq_read, .write = set_service_notifier_register, .llseek = seq_lseek, .release = seq_release, }; static ssize_t show_service_notifier_id(struct seq_file *f, void *unused) { seq_printf(f, "Service instance ID: %d\n", test_data.instance_id); return 0; } static ssize_t set_service_notifier_id(struct file *fp, const char __user *buf, size_t count, loff_t *unused) { int val, rc; char kbuf[MAX_STRING_LEN]; if (MAX_STRING_LEN < count) { rc = -EIO; goto err; } rc = copy_from_user(kbuf, buf, count); if (rc != 0) { rc = -EFAULT; goto err; } kbuf[count - 1] = '\0'; rc = kstrtoint(kbuf, 0, &val); if (rc < 0) goto err; test_data.instance_id = val; return count; err: pr_err("Invalid input parameters: rc = %d\n", rc); return rc; } static int open_service_notifier_id(struct inode *inode, struct file *f) { return single_open(f, (void *) show_service_notifier_id, inode->i_private); } static const struct file_operations service_notifier_id_fops = { .open = open_service_notifier_id, .read = seq_read, .write = set_service_notifier_id, .llseek = seq_lseek, .release = seq_release, }; static struct dentry *service_notifier_dir; static struct dentry *service_path_file; static struct dentry *service_id_file; static int __init service_notifier_init(void) { service_notifier_dir = debugfs_create_dir("service_notifier", NULL); if (service_notifier_dir) { service_path_file = debugfs_create_file("service_path", S_IRUGO | S_IWUSR, service_notifier_dir, NULL, &service_notifier_register_fops); if (!service_path_file) goto err; service_id_file = debugfs_create_file("service_id", S_IRUGO | S_IWUSR, service_notifier_dir, NULL, &service_notifier_id_fops); if (!service_id_file) goto err; } return 0; err: debugfs_remove_recursive(service_notifier_dir); return 0; } static void __exit service_notifier_exit(void) { debugfs_remove_recursive(service_notifier_dir); test_data.nb.notifier_call = nb_callback; } module_init(service_notifier_init); module_exit(service_notifier_exit); Loading
drivers/soc/qcom/service-notifier.c +179 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/err.h> #include <linux/debugfs.h> #include <linux/uaccess.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> Loading Loading @@ -60,6 +62,7 @@ #define QMI_STATE_MAX_VAL QMI_SERVREG_NOTIF_SERVICE_STATE_ENUM_TYPE_MAX_VAL_V01 #define SERVER_TIMEOUT 500 #define MAX_STRING_LEN 100 /* * Per user service data structure Loading Loading @@ -659,3 +662,179 @@ int service_notif_unregister_notifier(void *service_notif_handle, &service_notif->service_notif_rcvr_list, nb); } EXPORT_SYMBOL(service_notif_unregister_notifier); struct service_notifier_test_data { char service_path[MAX_STRING_LEN]; int instance_id; struct notifier_block nb; void *service_notif_handle; }; static struct service_notifier_test_data test_data; static void print_service_provider_state(int notification, char *type) { if (notification == SERVREG_NOTIF_SERVICE_STATE_DOWN_V01) pr_info("%s: Service %s down!\n", type, test_data.service_path); else if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01) pr_info("%s: Service %s up!\n", type, test_data.service_path); else if (notification == SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01) pr_info("%s: Service %s state uninit!\n", type, test_data.service_path); else pr_info("%s: Service %s state Unknown 0x%x!\n", type, test_data.service_path, notification); } static int nb_callback(struct notifier_block *nb, unsigned long notification, void *data) { print_service_provider_state((int)notification, "Notification:"); return 0; } static ssize_t show_service_path(struct seq_file *f, void *unused) { if (test_data.service_notif_handle) seq_printf(f, "Service Path: %s\n", test_data.service_path); else seq_puts(f, "No existing notifier\n"); return 0; } static ssize_t set_service_notifier_register(struct file *fp, const char __user *buf, size_t count, loff_t *ppos) { int curr_state = INT_MAX, rc; if (!buf) return -EIO; if (test_data.service_notif_handle) { service_notif_unregister_notifier( test_data.service_notif_handle, &test_data.nb); test_data.service_notif_handle = NULL; pr_info("Unregistering existing notifier for %s\n", test_data.service_path); } rc = simple_write_to_buffer(test_data.service_path, MAX_STRING_LEN, ppos, buf, count - 1); if (rc != count - 1) { pr_err("Unable to read data into kernel buffer\n"); goto err; } test_data.nb.notifier_call = nb_callback; test_data.service_notif_handle = service_notif_register_notifier( test_data.service_path, test_data.instance_id, &test_data.nb, &curr_state); if (!IS_ERR(test_data.service_notif_handle)) { pr_info("Notifier Registered for service %s\n", test_data.service_path); print_service_provider_state(curr_state, "Initial State"); return count; } err: test_data.service_notif_handle = NULL; pr_err("Unable to register notifier for %s\n", test_data.service_path); return -EIO; } static int open_service_notifier_register(struct inode *inode, struct file *f) { return single_open(f, (void *) show_service_path, inode->i_private); } static const struct file_operations service_notifier_register_fops = { .open = open_service_notifier_register, .read = seq_read, .write = set_service_notifier_register, .llseek = seq_lseek, .release = seq_release, }; static ssize_t show_service_notifier_id(struct seq_file *f, void *unused) { seq_printf(f, "Service instance ID: %d\n", test_data.instance_id); return 0; } static ssize_t set_service_notifier_id(struct file *fp, const char __user *buf, size_t count, loff_t *unused) { int val, rc; char kbuf[MAX_STRING_LEN]; if (MAX_STRING_LEN < count) { rc = -EIO; goto err; } rc = copy_from_user(kbuf, buf, count); if (rc != 0) { rc = -EFAULT; goto err; } kbuf[count - 1] = '\0'; rc = kstrtoint(kbuf, 0, &val); if (rc < 0) goto err; test_data.instance_id = val; return count; err: pr_err("Invalid input parameters: rc = %d\n", rc); return rc; } static int open_service_notifier_id(struct inode *inode, struct file *f) { return single_open(f, (void *) show_service_notifier_id, inode->i_private); } static const struct file_operations service_notifier_id_fops = { .open = open_service_notifier_id, .read = seq_read, .write = set_service_notifier_id, .llseek = seq_lseek, .release = seq_release, }; static struct dentry *service_notifier_dir; static struct dentry *service_path_file; static struct dentry *service_id_file; static int __init service_notifier_init(void) { service_notifier_dir = debugfs_create_dir("service_notifier", NULL); if (service_notifier_dir) { service_path_file = debugfs_create_file("service_path", S_IRUGO | S_IWUSR, service_notifier_dir, NULL, &service_notifier_register_fops); if (!service_path_file) goto err; service_id_file = debugfs_create_file("service_id", S_IRUGO | S_IWUSR, service_notifier_dir, NULL, &service_notifier_id_fops); if (!service_id_file) goto err; } return 0; err: debugfs_remove_recursive(service_notifier_dir); return 0; } static void __exit service_notifier_exit(void) { debugfs_remove_recursive(service_notifier_dir); test_data.nb.notifier_call = nb_callback; } module_init(service_notifier_init); module_exit(service_notifier_exit);