1 /*
2 * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <linux/seq_file.h>
20 #include <linux/slab.h>
21 #include <linux/miscdevice.h>
22
23 #include "securec.h"
24 #include "hi_osal.h"
25 #include "hiproc.h"
26
27
28 typedef struct {
29 wait_queue_head_t wq_for_read;
30 wait_queue_head_t wq_for_write;
31 wait_queue_head_t wq_for_cmd;
32 } proc_k_para;
33 static hi_s32 g_cmd_condition = 0;
34 static hi_s32 g_read_condition = 0;
35 static hi_s32 g_write_condition = 0;
36 static hi_s32 g_cmd_exit_condition = 0;
37
38 typedef struct entrylist {
39 hi_u32 private_data;
40 hi_char entry_name[MAX_PROC_NAME_LEN];
41 struct entrylist *next;
42 } hi_entry_list;
43
44 static hi_entry_list *g_proc_head = HI_NULL;
45
46 static osal_mutex g_mutex = {
47 .mutex = HI_NULL
48 };
49
50 static hi_proc_para proc_wait;
51 static proc_k_para g_proc_k_para;
52
53 static hi_s32 g_dbg_flag = 1;
54 #define hiproc_dbg(params...) do { \
55 if (g_dbg_flag) { \
56 osal_printk(params); \
57 } \
58 } while (0)
59
60 hi_void osal_proc_exit(hi_void);
61 static hi_s32 proc_read(void *seqfile, void *private);
62 static hi_s32 proc_write(osal_proc_entry *entry, const hi_char *buf, hi_s32 count, hi_s64 *ppos);
63
add_list(const hi_char *name, const hi_u32 private_data)64 static hi_entry_list *add_list(const hi_char *name, const hi_u32 private_data)
65 {
66 hi_entry_list *tmp;
67 tmp = (hi_entry_list *)osal_kmalloc(0, sizeof(hi_entry_list), OSAL_GFP_KERNEL);
68 if (tmp == NULL) {
69 return tmp;
70 }
71 (void)memset_s(tmp->entry_name, sizeof(tmp->entry_name), 0, sizeof(tmp->entry_name));
72 (void)memcpy_s(tmp->entry_name, sizeof(tmp->entry_name), name, strlen(name) + 1);
73 tmp->private_data = private_data;
74 tmp->next = g_proc_head;
75 g_proc_head = tmp;
76 return tmp;
77 }
78
get_list_and_delete_node(const hi_u32 private_data)79 static hi_void get_list_and_delete_node(const hi_u32 private_data)
80 {
81 hi_entry_list *tmp = g_proc_head;
82 hi_entry_list *pre = g_proc_head;
83 hi_entry_list *tmp1 = HI_NULL;
84 while (tmp != HI_NULL) {
85 if (tmp->private_data == private_data) {
86 if (tmp == pre) { // del head
87 g_proc_head = tmp->next;
88 tmp1 = g_proc_head;
89 pre = g_proc_head;
90 } else {
91 pre->next = tmp->next;
92 tmp1 = pre->next;
93 }
94 osal_proc_remove(tmp->entry_name, strlen(tmp->entry_name));
95 osal_kfree(0, tmp);
96 tmp = tmp1;
97 continue;
98 }
99 pre = tmp;
100 tmp = tmp->next;
101 }
102 return;
103 }
104
del_list_node(const hi_u32 private_data, const hi_char *name)105 static hi_s32 del_list_node(const hi_u32 private_data, const hi_char *name)
106 {
107 hi_entry_list *tmp = g_proc_head;
108 hi_entry_list *pre = g_proc_head;
109 while (tmp != HI_NULL) {
110 if (tmp->private_data == private_data && (!strncmp(tmp->entry_name, name, strlen(name)))) {
111 if (tmp == pre) { // del head
112 g_proc_head = tmp->next;
113 } else {
114 pre->next = tmp->next;
115 }
116 osal_kfree(0, tmp);
117 tmp = HI_NULL;
118 return HI_SUCCESS;
119 }
120 pre = tmp;
121 tmp = tmp->next;
122 }
123 return HI_FAILURE;
124 }
125
del_listnull126 static hi_void del_list(hi_void)
127 {
128 hi_entry_list *tmp = g_proc_head;
129 hi_entry_list *tmp2 = HI_NULL;
130
131 while (tmp != HI_NULL) {
132 tmp2 = tmp->next;
133 osal_kfree(0, tmp);
134 tmp = tmp2;
135 }
136 g_proc_head = HI_NULL;
137 }
138
hiproc_open(hi_void *private_data)139 static hi_s32 hiproc_open(hi_void *private_data)
140 {
141 hiproc_dbg("Enter hiproc_open\n");
142 osal_mutex_init(&g_mutex);
143 init_waitqueue_head(&g_proc_k_para.wq_for_read);
144 init_waitqueue_head(&g_proc_k_para.wq_for_write);
145 init_waitqueue_head(&g_proc_k_para.wq_for_cmd);
146 return HI_SUCCESS;
147 }
148
hiproc_release(hi_void *private_data)149 static hi_s32 hiproc_release(hi_void *private_data)
150 {
151 hiproc_dbg("Enter hiproc_release\n");
152 get_list_and_delete_node((hi_u32)(uintptr_t)private_data);
153 return HI_SUCCESS;
154 }
155
check_validate_name(char const *name)156 static int check_validate_name(char const *name)
157 {
158 unsigned int index;
159
160 for (index = 0; (index < MAX_PROC_NAME_LEN - 1) && (*(name + index) != '\0'); index++) {
161 if ((*(name + index) >= 'a' && *(name + index) <= 'z') ||
162 (*(name + index) >= '0' && *(name + index) <= '9') || // number 0~9
163 *(name + index) == '_') {
164 continue;
165 } else {
166 return HI_FAILURE;
167 }
168 }
169 return HI_SUCCESS;
170 }
171
hiproc_create_proc_entry(unsigned int cmd, hi_void *para, hi_void *private_data)172 static hi_s32 hiproc_create_proc_entry(unsigned int cmd, hi_void *para, hi_void *private_data)
173 {
174 hi_proc_name *proc_name = NULL;
175 osal_proc_entry *entry_info = HI_NULL;
176 proc_name = (hi_proc_name *)((uintptr_t)para);
177 proc_name->name[sizeof(proc_name->name) - 1] = '\0';
178 if (check_validate_name(proc_name->name) != HI_SUCCESS) {
179 osal_printk("[%s,line:%d]Error: invalied name.\n", HIPROC_PFX, __LINE__);
180 return HI_FAILURE;
181 }
182 entry_info = osal_proc_add(proc_name->name, strlen(proc_name->name));
183 if (entry_info == HI_NULL) {
184 osal_printk("[%s,line:%d]Error: can't create proc entry\n", HIPROC_PFX, __LINE__);
185 return HI_FAILURE;
186 }
187 add_list(entry_info->name, (hi_u32)(uintptr_t)private_data);
188 entry_info->read = proc_read;
189 entry_info->write = proc_write;
190 return HI_SUCCESS;
191 }
192
hiproc_remove_proc_entry(unsigned int cmd, hi_void *para, hi_void *private_data)193 static hi_s32 hiproc_remove_proc_entry(unsigned int cmd, hi_void *para, hi_void *private_data)
194 {
195 hi_proc_name *proc_name = NULL;
196 hi_s32 ret;
197 proc_name = (hi_proc_name *)((uintptr_t)para);
198 proc_name->name[sizeof(proc_name->name) - 1] = '\0';
199 if (check_validate_name(proc_name->name) != HI_SUCCESS) {
200 osal_printk("[%s,line:%d]Error: invalied name.\n", HIPROC_PFX, __LINE__);
201 return HI_FAILURE;
202 }
203 osal_proc_remove(proc_name->name, strlen(proc_name->name));
204 ret = del_list_node((hi_u32)(uintptr_t)private_data, proc_name->name);
205 if (ret != 0) {
206 osal_printk("hiproc delete entry failed\n");
207 return HI_FAILURE;
208 }
209 return HI_SUCCESS;
210 }
211
hiproc_get_cmd(unsigned int cmd, hi_void *para, hi_void *private_data)212 static hi_s32 hiproc_get_cmd(unsigned int cmd, hi_void *para, hi_void *private_data)
213 {
214 hi_proc_para *user_proc_info = HI_NULL;
215 wait_event_interruptible(g_proc_k_para.wq_for_cmd, g_cmd_condition != 0);
216 if (g_cmd_exit_condition == 1) {
217 g_cmd_condition = 0;
218 g_cmd_exit_condition = 0;
219 return HI_FAILURE;
220 }
221 g_cmd_condition = 0;
222
223 user_proc_info = (hi_proc_para *)((uintptr_t)para);
224 if (((strlen(proc_wait.cmd) > 0) && (strlen(proc_wait.entry.name) > 0))) {
225 (void)memcpy_s(&(user_proc_info->cmd), sizeof(user_proc_info->cmd), proc_wait.cmd,
226 sizeof(proc_wait.cmd));
227 (void)memcpy_s(&(user_proc_info->entry), sizeof(osal_proc_entry), &(proc_wait.entry),
228 sizeof(osal_proc_entry));
229 (void)memcpy_s(&(user_proc_info->write_buf.buf), sizeof(user_proc_info->write_buf.buf),
230 proc_wait.write_buf.buf, sizeof(user_proc_info->write_buf.buf));
231 user_proc_info->write_buf.ppos = proc_wait.write_buf.ppos;
232 user_proc_info->write_buf.count = proc_wait.write_buf.count;
233 } else {
234 return HI_FAILURE;
235 }
236 return HI_SUCCESS;
237 }
238
hiproc_wake_read_task(unsigned int cmd, hi_void *para, hi_void *private_data)239 static hi_s32 hiproc_wake_read_task(unsigned int cmd, hi_void *para, hi_void *private_data)
240 {
241 hi_proc_show_buf *show_buf = HI_NULL;
242 show_buf = (hi_proc_show_buf *)((uintptr_t)para);
243 if (strlen(proc_wait.entry.name) <= 0) {
244 osal_printk("entry info is HI_NULL\n");
245 return HI_FAILURE;
246 }
247 if (proc_wait.entry.read != HI_NULL) {
248 osal_printk("entry read is not NULL\n");
249 return HI_FAILURE;
250 }
251 if (show_buf == HI_NULL) {
252 osal_printk("show_buf is HI_NULL\n");
253 return HI_FAILURE;
254 }
255 if (show_buf->size > HI_PROC_BUF_SIZE) {
256 osal_printk("show_buf (size = %u) is overflow\n", show_buf->size);
257 return HI_FAILURE;
258 }
259 if (show_buf->buf == HI_NULL) {
260 osal_printk("show_buf is NULL\n");
261 return HI_FAILURE;
262 }
263 proc_wait.entry.read = osal_kmalloc(0, show_buf->size, OSAL_GFP_KERNEL);
264 if (proc_wait.entry.read) {
265 if (osal_copy_from_user(proc_wait.entry.read, (hi_void __user *)show_buf->buf, show_buf->size)) {
266 osal_kfree(0, proc_wait.entry.read);
267 proc_wait.entry.read = HI_NULL;
268 }
269 }
270 g_read_condition = 1;
271 wake_up_interruptible(&(g_proc_k_para.wq_for_read));
272 return HI_SUCCESS;
273 }
274
hiproc_wake_write_task(unsigned int cmd, hi_void *para, hi_void *private_data)275 static hi_s32 hiproc_wake_write_task(unsigned int cmd, hi_void *para, hi_void *private_data)
276 {
277 g_write_condition = 1;
278 wake_up_interruptible(&(g_proc_k_para.wq_for_write));
279 return HI_SUCCESS;
280 }
281
hiproc_wake_get_cmd(unsigned int cmd, hi_void *para, hi_void *private_data)282 static hi_s32 hiproc_wake_get_cmd(unsigned int cmd, hi_void *para, hi_void *private_data)
283 {
284 g_cmd_condition = 1;
285 g_cmd_exit_condition = 1;
286 wake_up_interruptible(&(g_proc_k_para.wq_for_cmd));
287 return HI_SUCCESS;
288 }
289
290 static osal_ioctl_cmd g_hiproc_cmd[] = {
291 {USER_CREATE_PROC_ENTRY, hiproc_create_proc_entry},
292 {USER_REMOVE_PROC_ENTRY, hiproc_remove_proc_entry},
293 {USER_PROC_GET_CMD, hiproc_get_cmd},
294 {USER_PROC_WAKE_READ_TASK, hiproc_wake_read_task},
295 {USER_PROC_WAKE_WRITE_TASK, hiproc_wake_write_task},
296 {USER_PROC_WAKE_GET_CMD, hiproc_wake_get_cmd},
297 };
298
299 static osal_fileops g_hiproc_fops = {
300 .open = hiproc_open,
301 .release = hiproc_release,
302 .cmd_list = g_hiproc_cmd,
303 .cmd_cnt = sizeof(g_hiproc_cmd) / sizeof(g_hiproc_cmd[0]),
304 };
305
306 static osal_dev g_hiproc_dev = {
307 .name = HIPROC_DEVICE_NAME,
308 .minor = MISC_DYNAMIC_MINOR,
309 .fops = &g_hiproc_fops,
310 };
311
hiproc_initnull312 static hi_s32 hiproc_init(hi_void)
313 {
314 if (osal_dev_register(&g_hiproc_dev) != 0) {
315 osal_printk("[%s,line:%d]Error: can't register\n", HIPROC_PFX, __LINE__);
316 return HI_FAILURE;
317 }
318
319 hiproc_dbg("hi_proc init ok. ver=%s, %s.\n", __DATE__, __TIME__);
320 return HI_SUCCESS;
321 }
322
proc_read(void *seqfile, void *private)323 static hi_s32 proc_read(void *seqfile, void *private)
324 {
325 struct seq_file *s = seqfile;
326 osal_proc_entry *entry_info = s->private;
327 DEFINE_WAIT(wait);
328
329 osal_mutex_lock(&g_mutex);
330 /* only these two parameters are used */
331 (void)memcpy_s(&(proc_wait.entry.name), sizeof(proc_wait.entry.name), entry_info->name,
332 sizeof(proc_wait.entry.name));
333 (void)memcpy_s(&(proc_wait.cmd), sizeof(proc_wait.cmd), HI_USER_PROC_READ_CMD, strlen(HI_USER_PROC_READ_CMD) + 1);
334
335 g_cmd_condition = 1;
336 wake_up_interruptible(&(g_proc_k_para.wq_for_cmd));
337 wait_event_interruptible(g_proc_k_para.wq_for_read, g_read_condition != 0);
338 g_read_condition = 0;
339
340 if (proc_wait.entry.read != HI_NULL) {
341 osal_proc_print(seqfile, "%s", (hi_char *)proc_wait.entry.read);
342 osal_kfree(0, proc_wait.entry.read);
343 proc_wait.entry.read = HI_NULL;
344 }
345 (void)memset_s(&(proc_wait.entry), sizeof(osal_proc_entry), 0, sizeof(osal_proc_entry));
346 (void)memset_s(&(proc_wait.cmd), sizeof(proc_wait.cmd), 0, sizeof(proc_wait.cmd));
347 osal_mutex_unlock(&g_mutex);
348 return HI_SUCCESS;
349 }
350
proc_write(osal_proc_entry *entry, const hi_char *buf, hi_s32 count, hi_s64 *ppos)351 static hi_s32 proc_write(osal_proc_entry *entry, const hi_char *buf, hi_s32 count, hi_s64 *ppos)
352 {
353 DEFINE_WAIT(wait);
354 osal_mutex_lock(&g_mutex);
355 (void)memcpy_s(&(proc_wait.cmd), sizeof(proc_wait.cmd), HI_USER_PROC_WRITE_CMD, strlen(HI_USER_PROC_WRITE_CMD) + 1);
356 (void)memcpy_s(&(proc_wait.entry), sizeof(osal_proc_entry), entry, sizeof(osal_proc_entry));
357 osal_copy_from_user(proc_wait.write_buf.buf, buf, sizeof(proc_wait.write_buf.buf));
358 proc_wait.write_buf.ppos = *ppos;
359 proc_wait.write_buf.count = count;
360
361 g_cmd_condition = 1;
362 wake_up_interruptible(&(g_proc_k_para.wq_for_cmd));
363 wait_event_interruptible(g_proc_k_para.wq_for_write, g_write_condition != 0);
364 g_write_condition = 0;
365
366 (void)memset_s(&(proc_wait.entry), sizeof(osal_proc_entry), 0, sizeof(osal_proc_entry));
367 (void)memset_s(&(proc_wait.cmd), sizeof(proc_wait.cmd), 0, sizeof(proc_wait.cmd));
368 (void)memset_s(proc_wait.write_buf.buf, sizeof(proc_wait.write_buf.buf), 0, sizeof(proc_wait.write_buf.buf));
369 proc_wait.write_buf.ppos = 0;
370 proc_wait.write_buf.count = 0;
371 osal_mutex_unlock(&g_mutex);
372 return count;
373 }
374
drv_common_module_initnull375 static hi_s32 drv_common_module_init(hi_void)
376 {
377 hi_s32 ret;
378
379 hiproc_dbg("Enter drv_common_module_init\n");
380 ret = hiproc_init();
381 if (ret != 0) {
382 osal_printk("%s - drv_common_module_init error!\n", __FUNCTION__);
383 }
384 return ret;
385 }
386
drv_common_module_exitnull387 static hi_void drv_common_module_exit(hi_void)
388 {
389 hiproc_dbg("Enter drv_common_module_exit\n");
390 osal_mutex_destory(&g_mutex);
391 osal_dev_unregister(&g_hiproc_dev);
392 del_list();
393 return;
394 }
395
396 module_init(drv_common_module_init);
397 module_exit(drv_common_module_exit);
398