1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <stddef.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <stdlib.h>
9 
10 #if AOS_COMP_CLI
11 #include "aos/cli.h"
12 #endif
13 #include "aos/list.h"
14 
15 #include <drivers/char/u_device.h>
16 #include <drivers/char/u_driver.h>
17 #include <drivers/char/u_bus.h>
18 #include <drivers/spinlock.h>
19 
20 #define G_ROOT_PATH "/dev"
21 
22 int g_ddkc_log_level = DDKC_LOG_WARN;
23 static dlist_t g_dev_node_list;
24 static u_dev_node_t *g_root_dev_node = NULL;
25 
26 char ddkc_level_tag[] = {
27 	'L',
28 	'D',
29 	'I',
30 	'W',
31 	'E'
32 };
33 
34 /**
35  * dump device's information, name, id, parent, bus, driver, drv_data included
36  * @param dev - pointer to target device
37  * @return 0 for success; netative for failure
38  */
u_device_dump(struct u_device * dev)39 int u_device_dump(struct u_device *dev) {
40 
41 	if (!dev) {
42 		ddkc_err("dev is NULL\r\n");
43 		return -1;
44 	}
45 
46 	ddkc_info("dev:%p, dev->name:%s, id:%d, dev_id:%d, parent:%p, bus:%p, drv:%p, drv_data:%p\r\n",
47 	          dev, dev->name,
48 	          dev->id, dev->dev_id,
49 	          dev->parent, dev->bus, dev->drv, dev->driver_data);
50 
51 	return 0;
52 }
53 
54 /**
55  * initialize u_device's private info
56  *
57  * @param dev - pointer to target device
58  * @return 0 for success; netative for failure
59  */
u_device_initialize(struct u_device * dev)60 int u_device_initialize(struct u_device *dev) {
61 	u_device_private_t *p = NULL;
62 
63 	/* dev is not NULL, guaranteed by caller */
64 	dev->drv = NULL;
65 
66 	/* device's parent and bus should be setup before call u_device_initialize */
67 	//dev->parent = NULL;
68 	//dev->bus = NULL;
69 	p = (u_device_private_t *)malloc(sizeof(u_device_private_t));
70 	if (!p) {
71 		ddkc_err("malloc for u_device_private_t failed\r\n");
72 		return -ENOMEM;
73 	}
74 
75 	p->name = NULL;
76 	spin_lock_init(&p->lock);
77 	dlist_init(&p->bus_node);
78 	dlist_init(&p->drv_node);
79 	dlist_init(&p->child_head);
80 	dlist_init(&p->parent_node);
81 	p->dev = dev;
82 	dev->p = p;
83 
84 	return 0;
85 }
86 
87 /**
88  * add device into bus device list
89  * conditions to check in u_device_add:
90  * 1. dev is not NULL
91  * 2. dev->bus is assigned correctly
92  * 3. dev->p is allocated and initialized
93  *
94  * @param dev - pointer to target device
95  * @return 0 for success; netative for failure
96  */
u_device_add(struct u_device * dev)97 int u_device_add(struct u_device *dev) {
98 	u_device_private_t *p = NULL;
99 	int r = 0;
100 	int len = 0;
101 	/* dev is not NULL, guaranteed by caller */
102 
103 	if (!dev || !dev->p || !dev->bus) {
104 		ddkc_err("invalid dev:%p or dev->p:%p or dev->bus:%p\r\n", dev, dev ? dev->p : NULL, dev ? dev->bus : NULL);
105 		return -EINVAL;
106 	}
107 
108 	if (!dev->bus->name || (dev->id >= MAX_DEV_ID_NUM)){
109 		ddkc_err("invalid bus name:%p or dev->id:%d\r\n", dev->bus->name, dev->id);
110 		return -EINVAL;
111 	}
112 
113 	p = dev->p;
114 	len = strlen(dev->bus->name) + MAX_DEV_ID_DIGS + 1; // 1 is for '\0'
115 	p->name = (char *)malloc(len);
116 	if (!p->name) {
117 		ddkc_err("malloc for dev->p->name failed, len:%d\r\n", len);
118 		return -ENOMEM;
119 	}
120 
121 	/* name dev's name with <bus_name><dev_id> */
122     memset(p->name, 0, len);
123 	snprintf(p->name, len, "%s%d", dev->bus->name, dev->id);
124 
125 	/* add device into its parent's child_head */
126 	if (dev->parent) {
127         unsigned long flags;
128 
129 		spin_lock_irqsave(&dev->parent->p->lock, flags);
130 		dlist_add_tail(&p->parent_node, &dev->parent->p->child_head);
131 		spin_unlock_irqrestore(&dev->parent->p->lock, flags);
132 	}
133 
134 	/* add this device into target bus */
135 	r = u_bus_add_device(dev);
136 	if (r)
137 		goto dev_add_error;
138 
139 	/* it is not necessary to check u_bus_try_init_device's return value */
140 	u_bus_try_init_device(dev);
141 
142 	return 0;
143 
144 dev_add_error:
145 	if (p->name) {
146 		free(p->name);
147 		p->name = NULL;
148 	}
149 
150 	return r;
151 }
152 
153 /**
154  * register a device into system
155  *
156  * @param dev - pointer to target device
157  * @return 0 for success; netative for failure
158  */
u_device_register(struct u_device * dev)159 int u_device_register(struct u_device *dev) {
160 
161 	if (!dev) {
162 		ddkc_err("invalid dev:%p\r\n", dev);
163 		return -EINVAL;
164 	}
165 
166 	u_device_initialize(dev);
167 	return u_device_add(dev);
168 }
169 
170 /**
171  * check whether a device is registered or not
172  * @param dev - pointer to the device to be checked
173  *
174  * @return 0 for success; netative for failure
175  */
u_device_is_registered(struct u_device * dev)176 int u_device_is_registered(struct u_device *dev) {
177 	u_device_private_t *devp = dev->p;
178 
179 	if (!devp || dlist_empty(&devp->bus_node))
180 		return 0;
181 	return 1;
182 }
183 
u_dev_node_get_pathname_length(u_dev_node_t * dev_node)184 unsigned int u_dev_node_get_pathname_length(u_dev_node_t *dev_node) {
185 	unsigned int length = 0;
186 #if 0
187 	u_dev_node_t *parent = dev_node;
188 
189 	do {
190 		if(!strlen(parent->name))
191 			break;
192 		length += strlen(parent->name) + 1;
193 
194 		parent = dev_node->parent;
195 	} while (parent);
196 #else
197 	/* 2 is for '/' and '\0' */
198 	length = strlen(dev_node->name) + strlen(dev_node->parent->path_name) + 2;
199 #endif
200 	return length;
201 }
202 
u_dev_node_get_pathname(u_dev_node_t * dev_node)203 char *u_dev_node_get_pathname(u_dev_node_t *dev_node) {
204 	char *pathname = NULL;
205 	unsigned int len = 0;
206 	unsigned int length = u_dev_node_get_pathname_length(dev_node);
207 
208 	pathname = malloc(length);
209 	if (!pathname) {
210 		ddkc_err("malloc for pathname failed, len[%d]\r\n", length);
211 		return NULL;
212 	}
213 	memset(pathname, 0, length);
214 #if 0
215 	u_dev_node_t *parent = dev_node;
216 
217 	length -= 2;
218 
219 	do {
220 		len = strlen(parent->name);
221 		if(!len)
222 			break;
223 		strncpy(pathname[length - len], parent->name, len);
224 		length -= len;
225 		pathname[length--] = '/';
226 		parent = dev_node->parent;
227 	} while (parent);
228 #else
229 	ddkc_dbg("pathname length:%d\r\n", length);
230 	ddkc_dbg("parent pathname:%s\r\n", dev_node->parent->path_name);
231 	ddkc_dbg("node pathname:%p - %s\r\n", dev_node->name, dev_node->name);
232 	len = strlen(dev_node->parent->path_name);
233 	if (len) {
234 		strncpy(pathname, dev_node->parent->path_name, len);
235 		pathname[len++] = '/';
236 	}
237 	strncpy(pathname + len, dev_node->name, strlen(dev_node->name));
238 #endif
239 	ddkc_info("pathname:%s\r\n", pathname);
240 
241 	return pathname;
242 }
243 
u_device_node_create(struct u_dev_node * parent,unsigned int dev_id,void * drv_data,char * name)244 struct u_dev_node * u_device_node_create(struct u_dev_node *parent, unsigned int dev_id, void *drv_data, char *name) {
245 	u_dev_node_t *dev_node = NULL;
246 
247 	if (!name) {
248 		ddkc_err("name should not be NULL\r\n");
249 		return NULL;
250 	}
251 
252 	/**
253 	 * //TODO: need to do sanity check
254 	 * 1. whether dev_id is already binded with exist device node?
255 	 * 2. whether name is already binded to parent?
256 	 */
257 
258 	// manage all device, registered with u_device_node_create, into one list,
259 	// <pathname, dev_id> is in this list
260 	dev_node = malloc(sizeof(u_dev_node_t) + strlen(name) + 1);
261 	memset(dev_node, 0, sizeof(u_dev_node_t) + strlen(name) + 1);
262 	dlist_init(&dev_node->node);
263 
264 	dev_node->dev_id = dev_id;
265 	if (parent)
266 		dev_node->parent = parent;
267 	else
268 		dev_node->parent = g_root_dev_node;
269 
270 	if (drv_data)
271 		dev_node->drv_data = drv_data;
272 
273 	strncpy(dev_node->name, name, strlen(name));
274 	dev_node->name[strlen(name)] = '\0';
275 
276 	// compose device pathname
277 	dev_node->path_name = u_dev_node_get_pathname(dev_node);
278 
279 	ddkc_info("path_name:%s added\r\n", dev_node->path_name);
280 
281 	// enqueue to global device node
282 	dlist_add(&dev_node->node, &g_dev_node_list);
283 
284 	/* TODO: send IPC message to notify VFS new device node is created */
285 
286 	return dev_node;
287 }
288 
u_device_node_delete(unsigned int dev_id)289 int u_device_node_delete(unsigned int dev_id) {
290 	u_dev_node_t *dev_node = NULL;
291 	struct dlist_s *node = NULL;
292 
293 	dlist_for_each_entry_safe(&g_dev_node_list, node, dev_node, u_dev_node_t, node) {
294 		if (dev_node->dev_id == dev_id) {
295 			dlist_del(&dev_node->node);
296 			// free full path name memory
297 			if (dev_node->path_name)
298 				free(dev_node->path_name);
299 			// free device node struct
300 			free(dev_node);
301 		}
302 	}
303 	return 0;
304 }
305 
306 #if 0
307 struct u_dev_node * u_device_node_find_by_devid(dev_t dev_id) {
308 	struct u_dev_node *parent;
309 	u_dev_node_t *dev_node = NULL;
310 	struct dlist_s *node = NULL;
311 
312 	dlist_for_each_entry_safe(&g_dev_node_list, node, dev_node, u_dev_node_t, node) {
313 		if (dev_node->dev_id == dev_id) {
314 			return dev_node;
315 		}
316 	}
317 	return NULL;
318 }
319 #endif
320 
u_device_node_find_by_pathname(char * path_name)321 struct u_dev_node * u_device_node_find_by_pathname(char *path_name) {
322 	dlist_t *root = NULL;
323 	u_dev_node_t *dev_node = NULL;
324 
325 	if (!path_name || !g_root_dev_node) {
326 		ddkc_warn("invalid pathname[%p] or root dev node[%p]\r\n", path_name, g_root_dev_node);
327 		return NULL;
328 	}
329 	root = &g_root_dev_node->node;
330 	dlist_for_each_entry(root, dev_node, u_dev_node_t, node) {
331 		if (!strcmp(path_name, dev_node->path_name)) {
332 			ddkc_dbg("dev_node with pathname[%s] found\r\n", dev_node->path_name);
333 			return dev_node;
334 		}
335 	}
336 	ddkc_dbg("dev_node with pathname[%s] not found\r\n", path_name);
337 	return NULL;
338 }
339 
u_device_node_find_by_nodename(char * node_name)340 struct u_dev_node * u_device_node_find_by_nodename(char *node_name) {
341 	dlist_t *root = NULL;
342 	u_dev_node_t *dev_node = NULL;
343 
344 	if (!node_name || !g_root_dev_node) {
345 		ddkc_warn("invalid node_name[%p] or root dev node[%p]\r\n", node_name, g_root_dev_node);
346 		return NULL;
347 	}
348 	root = &g_root_dev_node->node;
349 	dlist_for_each_entry(root, dev_node, u_dev_node_t, node) {
350 		// exclude "/dev/" from dev_node->path_name
351 		if (!strcmp(node_name, dev_node->path_name + sizeof(G_ROOT_PATH) + 1)) {
352 			ddkc_dbg("dev_node with node_name[%s] found\r\n", dev_node->path_name);
353 			return dev_node;
354 		}
355 	}
356 	ddkc_dbg("dev_node with node_name[%s] not found\r\n", node_name);
357 	return NULL;
358 }
359 
u_device_node_find_by_dev(struct u_device * u_dev)360 struct u_dev_node * u_device_node_find_by_dev(struct u_device *u_dev) {
361 	dlist_t *root = NULL;
362 	u_dev_node_t *dev_node = NULL;
363 
364 	if (!u_dev || !g_root_dev_node) {
365 		ddkc_warn("invalid dev[%p] or root dev node[%p]\r\n", u_dev, g_root_dev_node);
366 		return NULL;
367 	}
368 
369 	root = &g_dev_node_list;
370 	dlist_for_each_entry(root, dev_node, u_dev_node_t, node) {
371 		if (u_dev == dev_node->dev) {
372 			ddkc_dbg("dev_node with u_dev[%p] found\r\n", u_dev);
373 			return dev_node;
374 		}
375 	}
376 	ddkc_dbg("dev_node with u_dev[%p] not found\r\n", u_dev);
377 	return NULL;
378 }
379 
u_device_root_node_init(void)380 int u_device_root_node_init(void) {
381 	char *root_path = G_ROOT_PATH;
382 	unsigned int len = sizeof(u_dev_node_t) + strlen(root_path) + 1;
383 
384 	dlist_init(&g_dev_node_list);
385 
386 	g_root_dev_node = malloc(len);
387 	if (!g_root_dev_node) {
388 		ddkc_err("fail to malloc for root device node\r\n");
389 		return -ENOMEM;
390 	}
391 
392 	memset(g_root_dev_node, 0, len);
393 	dlist_init(&g_root_dev_node->node);
394 
395 	strncpy(g_root_dev_node->name, root_path, strlen(root_path) + 1);
396 	g_root_dev_node->name[strlen(root_path)] = '\0';
397 
398 	g_root_dev_node->path_name = g_root_dev_node->name;
399 
400 	dlist_add(&g_root_dev_node->node, &g_dev_node_list);
401 
402 	ddkc_dbg("root device node initialized\r\n");
403 
404 	return 0;
405 }
406 
407 /**
408  * delete device from system
409  *
410  * @param dev - pointer to device to be deleted
411  * @return 0 for success; negative for failure
412  */
u_device_del(struct u_device * dev)413 int u_device_del(struct u_device *dev) {
414 	if (!dev)
415 		return -EINVAL;
416 
417 	if (dev->p) {
418 		unsigned long flags;
419 		u_driver_t *drv = NULL;
420 		u_device_private_t *p = dev->p;
421 
422 		//dlist_del(p->bus_node); /* already done in u_bus_del_device */
423 		drv = dev->drv;
424 		if (drv && drv->p) {
425 			// remove drv_node from driver's device list
426 			u_driver_private_t *drv_p = drv->p;
427 
428 			spin_lock_irqsave(&drv_p->lock, flags);
429 			dlist_del(&p->drv_node);
430 			spin_unlock_irqrestore(&drv_p->lock, flags);
431 		}
432 
433 		spin_lock_irqsave(&dev->parent->p->lock, flags);
434 		dlist_del(&p->parent_node);
435 		// TODO: should detach all child in child_head
436 		//dlist_del(p->child_head);
437 		spin_unlock_irqrestore(&dev->parent->p->lock, flags);
438 
439 		if (p->name) {
440 			free(p->name);
441 			p->name = NULL;
442 		}
443 
444 		free(p);
445 		dev->p = NULL;
446 	}
447 
448 	return 0;
449 }
450 
451 /**
452  * unregister device from system
453  * @param dev - pointer to target device to be unregistered
454  * @return 0 for success; negative for failure
455  */
u_device_unregister(struct u_device * dev)456 int u_device_unregister(struct u_device *dev) {
457 	return u_device_del(dev);
458 }
459 
460 #if AOS_COMP_CLI
461 /**
462  * service handler - change log level of udevice
463  *
464  */
u_device_loglevel_cmd(char * wbuf,int len,int argc,char ** argv)465 static void u_device_loglevel_cmd(char *wbuf, int len, int argc, char **argv) {
466 
467     if (argc < 1) {
468 	    ddkc_err("arg too short, current loglevel:%d\r\n", g_ddkc_log_level);
469 	    return;
470     }
471 
472     switch (*argv[1]) {
473         case 'l':
474         case 'L':
475             g_ddkc_log_level = DDKC_LOG_LOUD;
476             break;
477         case 'd':
478         case 'D':
479             g_ddkc_log_level = DDKC_LOG_DEBUG;
480             break;
481         case 'i':
482         case 'I':
483             g_ddkc_log_level = DDKC_LOG_INFO;
484             break;
485         case 'w':
486         case 'W':
487             g_ddkc_log_level = DDKC_LOG_WARN;
488             break;
489         case 'e':
490         case 'E':
491 	        g_ddkc_log_level = DDKC_LOG_ERROR;
492             break;
493         default:
494             break;
495     }
496     ddkc_err("loglevel set to %d\r\n", g_ddkc_log_level);
497 
498     return;
499 }
500 
501 struct cli_command u_device_test_cmds[] = {
502     {"udev_loglevel",         "adjust udevice log level", u_device_loglevel_cmd},
503 };
504 
u_devicd_test_cmd_init(void)505 static int u_devicd_test_cmd_init(void) {
506 	ddkc_dbg("registering udevice commands\r\n");
507     return aos_cli_register_commands(&u_device_test_cmds[0],
508                                      sizeof(u_device_test_cmds)/sizeof(u_device_test_cmds[0]));
509 }
510 #endif /* AOS_COMP_CLI */
511 
u_device_init(void)512 int u_device_init(void) {
513 	#if AOS_COMP_CLI
514     u_devicd_test_cmd_init();
515 	#endif
516     return u_device_root_node_init();
517 }
518 
519 #include "drivers/u_ld.h"
520 CORE_DRIVER_ENTRY(u_device_init)
521