1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <assert.h>
6 #include <ulog/ulog.h>
7 #include "device/aos_device.h"
8 #include <drivers/u_ld.h>
9 #include <devicevfs/devicevfs.h>
10 #include <stdlib.h>
11 
12 #include "k_api.h"
13 
14 #define TAG "aos_device_bridge"
15 
16 #define device_init     (dev->init)
17 #define device_open     (dev->open)
18 #define device_close    (dev->close)
19 #define device_read     (dev->read)
20 #define device_write    (dev->write)
21 #define device_control  (dev->control)
22 
23 extern struct file_ops m_dev_fops;
24 extern void aos_object_detach(aos_object_t object);
25 
26 #ifndef AOS_DEVICE_BRIDGE_USE_VFS
27 
bridge_device_probe(struct u_platform_device * pdev)28 static int bridge_device_probe (struct u_platform_device *pdev) {
29     LOGW(TAG, "%s", __func__);
30     return 0;
31 }
32 
bridge_device_remove(struct u_platform_device * pdev)33 static int bridge_device_remove (struct u_platform_device *pdev) {
34     LOGW(TAG, "%s", __func__);
35     return 0;
36 }
37 
bridge_device_shutdown(struct u_platform_device * pdev)38 static void bridge_device_shutdown (struct u_platform_device *pdev) {
39     LOGW(TAG, "%s", __func__);
40     return;
41 }
42 
bridge_device_suspend(struct u_platform_device * pdev,int state)43 static int bridge_device_suspend (struct u_platform_device *pdev, int /*pm_message_t */state) {
44     LOGW(TAG, "%s", __func__);
45     return 0;
46 }
47 
bridge_device_resume(struct u_platform_device * pdev)48 static int bridge_device_resume (struct u_platform_device *pdev) {
49     LOGW(TAG, "%s", __func__);
50     return 0;
51 }
52 
bridge_device_init(struct u_platform_device * pdev)53 int bridge_device_init (struct u_platform_device *pdev) {
54     return 0;
55 }
56 
bridge_device_deinit(struct u_platform_device * pdev)57 int bridge_device_deinit (struct u_platform_device *pdev) {
58     return 0;
59 }
60 
bridge_device_pm(struct u_platform_device * pdev,u_pm_ops_t state)61 int bridge_device_pm (struct u_platform_device *pdev, u_pm_ops_t state) {
62     return 0;
63 }
64 
65 static struct subsys_drv bridge_device_drv = {
66     .drv_name = "bridge_drv",
67     .init = bridge_device_init,
68     .deinit = bridge_device_deinit,
69     .pm = bridge_device_pm,
70 #if 0
71     .probe = bridge_device_probe,
72     .remove = bridge_device_remove,
73     .shutdown = bridge_device_shutdown,
74     .suspend = bridge_device_suspend,
75     .resume = bridge_device_resume,
76 #endif
77 };
78 
aos_device_bridge_reg(const char * name,subsys_file_ops_t * fops,aos_device_t udata)79 static int aos_device_bridge_reg(const char *name, subsys_file_ops_t *fops, aos_device_t udata)
80 {
81     int ret = 0;
82     int node_name_len = 0;
83     struct subsys_dev *ppsdev = NULL;
84 
85     LOGI(TAG, "vfs driver init starts");
86 
87     node_name_len = strlen(name) + 2 + 1; // 2 for %d, 1 for '\0'
88     LOGI(TAG, "node_name_len:%d", node_name_len);
89 
90     ppsdev = malloc(sizeof(struct subsys_dev) + node_name_len);
91     if (!ppsdev) {
92         LOGI(TAG, "malloc failed, ppsdev:%p", ppsdev);
93         goto err;
94     }
95 
96     memset(ppsdev, 0x0, sizeof(struct subsys_dev)+node_name_len);
97 
98     ppsdev->node_name = (char *)((ppsdev) + 1);
99     snprintf((ppsdev)->node_name, node_name_len, "%s", name);
100     LOGD(TAG, "ppsdev:%p, (ppsdev) + 1:%p, node_name:%s, sizeof(struct subsys_dev):%d",
101          ppsdev, (ppsdev) + 1, (ppsdev)->node_name, sizeof(struct subsys_dev));
102     ppsdev->permission = 0;
103     // please refer to definitions in enum SUBSYS_BUS_TYPE
104     ppsdev->type = BUS_TYPE_PLATFORM;
105     // user_data will be passed to open operation via node->i_arg
106     ppsdev->user_data = (void *)udata;
107     udata->user_data2 = ppsdev;
108 
109     ret = aos_dev_reg(ppsdev, fops, &bridge_device_drv);
110     if (ret) {
111         LOGE(TAG, "aos_dev_reg for failed, ret:%d", ret);
112         goto err;
113     }
114 
115     LOGI(TAG, "%s vfs driver init finish, ret:%d", __func__, ret);
116     return 0;
117 
118 err:
119     if (ppsdev) {
120         // shall uninstall devices who are already registered
121         aos_dev_unreg(ppsdev);
122         LOGI(TAG, "free memory");
123         free(ppsdev);
124         ppsdev = NULL;
125     }
126 
127     LOGE(TAG, "%s vfs driver init failed, ret:%d", __func__, ret);
128 
129     return ret;
130 }
131 #endif
132 
133 /**
134  * This function registers a device driver with specified name.
135  *
136  * @param dev the pointer of device driver structure
137  * @param name the device's name
138  * @param flags the capabilities flag of device
139  *
140  * @return the error code, 0 on initialization successfully.
141  */
aos_device_register(aos_device_t dev,const char * name,uint16_t flags)142 int aos_device_register(aos_device_t dev,
143                         const char *name,
144                         uint16_t flags)
145 {
146     if (dev == NULL)
147         return -1;
148 
149     if (aos_device_find(name) != NULL)
150         return -1;
151 
152     aos_object_init(&(dev->parent), AOS_Object_Class_Device, name);
153     dev->flag = flags;
154     dev->ref_count = 0;
155     dev->open_flag = 0;
156 
157 #ifdef AOS_DEVICE_BRIDGE_USE_VFS
158     if (0 != aos_register_driver(name, &m_dev_fops, (void *)dev)) {
159 #else
160     LOGD(TAG, "%s dev %p name %s", __func__, dev, name);
161     if (0 != aos_device_bridge_reg(name, &m_dev_fops, dev)) {
162 #endif
163         return -1;
164     }
165 
166     return 0;
167 }
168 
169 /**
170  * This function removes a previously registered device driver
171  *
172  * @param dev the pointer of device driver structure
173  *
174  * @return the error code, 0 on successfully.
175  */
176 int aos_device_unregister(aos_device_t dev)
177 {
178     struct subsys_dev *ppsdev;
179 
180     DEV_ASSERT(dev != NULL);
181     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
182     DEV_ASSERT(aos_object_is_systemobject(&dev->parent));
183 
184     ppsdev = dev->user_data2;
185     if (ppsdev) {
186         aos_dev_unreg(ppsdev);
187         free(ppsdev);
188         ppsdev = NULL;
189     }
190 
191     aos_object_detach(&(dev->parent));
192 
193     return 0;
194 }
195 
196 /**
197  * This function finds a device driver by specified name.
198  *
199  * @param name the device driver's name
200  *
201  * @return the registered device driver on successful, or NULL on failure.
202  */
203 aos_device_t aos_device_find(const char *name)
204 {
205     struct aos_object *object;
206     dlist_t *node;
207     struct aos_object_information *information;
208 
209     CPSR_ALLOC();
210 
211     RHINO_CRITICAL_ENTER();
212 
213     /* try to find device object */
214     information = aos_object_get_information(AOS_Object_Class_Device);
215     DEV_ASSERT(information != NULL);
216     for (node  = information->object_list.next;
217          node != &(information->object_list);
218          node  = node->next)
219     {
220         object = dlist_entry(node, struct aos_object, list);
221         if (strncmp(object->name, name, AOS_OBJ_NAME_MAX) == 0)
222         {
223             /* leave critical */
224             RHINO_CRITICAL_EXIT();
225 
226             return (aos_device_t)object;
227         }
228     }
229 
230     /* leave critical */
231     RHINO_CRITICAL_EXIT();
232 
233     /* not found */
234     return NULL;
235 }
236 
237 /**
238  * This function creates a device object with user data size.
239  *
240  * @param type, the kind type of this device object.
241  * @param attach_size, the size of user data.
242  *
243  * @return the allocated device object, or NULL when failed.
244  */
245 aos_device_t aos_device_create(int type, int attach_size)
246 {
247     int size;
248     aos_device_t device;
249 
250     size = AOS_ALIGN(sizeof(struct aos_device), AOS_ALIGN_SIZE);
251     attach_size = AOS_ALIGN(attach_size, AOS_ALIGN_SIZE);
252     /* use the total size */
253     size += attach_size;
254 
255     device = (aos_device_t)aos_malloc(size);
256     if (device)
257     {
258         memset(device, 0x0, sizeof(struct aos_device));
259         device->type = (enum aos_device_class_type)type;
260     }
261 
262     return device;
263 }
264 
265 /**
266  * This function destroy the specific device object.
267  *
268  * @param dev, the specific device object.
269  */
270 void aos_device_destroy(aos_device_t dev)
271 {
272     DEV_ASSERT(dev != NULL);
273     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
274     DEV_ASSERT(aos_object_is_systemobject(&dev->parent) == false);
275 
276     aos_object_detach(&(dev->parent));
277 
278     /* release this device object */
279     aos_free(dev);
280 }
281 
282 /**
283  * This function will initialize the specified device
284  *
285  * @param dev the pointer of device driver structure
286  *
287  * @return the result
288  */
289 int aos_device_init(aos_device_t dev)
290 {
291     int result = 0;
292 
293     DEV_ASSERT(dev != NULL);
294 
295     /* get device_init handler */
296     if (device_init != NULL)
297     {
298         if (!(dev->flag & AOS_DEVICE_FLAG_ACTIVATED))
299         {
300             result = device_init(dev);
301             if (result != 0)
302             {
303                 LOGD(TAG,"To initialize device:%s failed. The error code is %d",
304                         dev->parent.name, result);
305             }
306             else
307             {
308                 dev->flag |= AOS_DEVICE_FLAG_ACTIVATED;
309             }
310         }
311     }
312 
313     return result;
314 }
315 
316 /**
317  * This function will open a device
318  *
319  * @param dev the pointer of device driver structure
320  * @param oflag the flags for device open
321  *
322  * @return the result
323  */
324 int aos_device_open(aos_device_t dev, uint16_t oflag)
325 {
326     int result = 0;
327 
328     DEV_ASSERT(dev != NULL);
329     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
330 
331     /* if device is not initialized, initialize it. */
332     if (!(dev->flag & AOS_DEVICE_FLAG_ACTIVATED))
333     {
334         if (device_init != NULL)
335         {
336             result = device_init(dev);
337             if (result != 0)
338             {
339                 //printf("To initialize device:%s failed. The error code is %d\n",dev->parent.name, result);
340                 return result;
341             }
342         }
343 
344         dev->flag |= AOS_DEVICE_FLAG_ACTIVATED;
345     }
346 
347     /* device is a stand alone device and opened */
348     if ((dev->flag & AOS_DEVICE_FLAG_STANDALONE) &&
349         (dev->open_flag & AOS_DEVICE_OFLAG_OPEN))
350     {
351         return -1; // EBUSY
352     }
353 
354     /* call device_open interface */
355     if (device_open != NULL)
356     {
357         result = device_open(dev, oflag);
358     } else {
359         /* set open flag */
360         dev->open_flag = (oflag & AOS_DEVICE_OFLAG_MASK);
361     }
362 
363     /* set open flag */
364     if (result == 0) {
365         dev->open_flag |= AOS_DEVICE_OFLAG_OPEN;
366 
367         dev->ref_count++;
368         /* don't let bad things happen silently. If you are bitten by this assert,
369          * please set the ref_count to a bigger type. */
370         DEV_ASSERT(dev->ref_count != 0);
371     }
372 
373     return result;
374 }
375 
376 /**
377  * This function will close a device
378  *
379  * @param dev the pointer of device driver structure
380  *
381  * @return the result
382  */
383 int aos_device_close(aos_device_t dev)
384 {
385     int result = 0;
386 
387     DEV_ASSERT(dev != NULL);
388     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
389 
390     if (dev->ref_count == 0)
391         return -1;
392 
393     dev->ref_count--;
394 
395     if (dev->ref_count != 0)
396         return 0;
397 
398     /* call device_close interface */
399     if (device_close != NULL) {
400         result = device_close(dev);
401     }
402 
403     /* set open flag */
404     if (result == 0)
405         dev->open_flag = AOS_DEVICE_OFLAG_CLOSE;
406 
407     return result;
408 }
409 
410 /**
411  * This function will read some data from a device.
412  *
413  * @param dev the pointer of device driver structure
414  * @param pos the position of reading
415  * @param buffer the data buffer to save read data
416  * @param size the size of buffer
417  *
418  * @return the actually read size on successful, otherwise negative returned.
419  *
420  * @note since 0.4.0, the unit of size/pos is a block for block device.
421  */
422 size_t aos_device_read(aos_device_t dev,
423                       long    pos,
424                       void       *buffer,
425                       size_t   size)
426 {
427     DEV_ASSERT(dev != NULL);
428     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
429 
430     if (dev->ref_count == 0) {
431         return 0;
432     }
433 
434     /* call device_read interface */
435     if (device_read != NULL)
436     {
437         return device_read(dev, pos, buffer, size);
438     }
439 
440     return 0;
441 }
442 
443 /**
444  * This function will write some data to a device.
445  *
446  * @param dev the pointer of device driver structure
447  * @param pos the position of written
448  * @param buffer the data buffer to be written to device
449  * @param size the size of buffer
450  *
451  * @return the actually written size on successful, otherwise negative returned.
452  *
453  * @note since 0.4.0, the unit of size/pos is a block for block device.
454  */
455 size_t aos_device_write(aos_device_t dev,
456                         long    pos,
457                         const void *buffer,
458                         size_t   size)
459 {
460     DEV_ASSERT(dev != NULL);
461     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
462 
463     if (dev->ref_count == 0) {
464         /* set error code -ENOSYS */
465         return 0;
466     }
467 
468     /* call device_write interface */
469     if (device_write != NULL) {
470         return device_write(dev, pos, buffer, size);
471     }
472 
473     /* set error code -ENOSYS */
474 
475     return 0;
476 }
477 
478 /**
479  * This function will perform a variety of control functions on devices.
480  *
481  * @param dev the pointer of device driver structure
482  * @param cmd the command sent to device
483  * @param arg the argument of command
484  *
485  * @return the result
486  */
487 int aos_device_control(aos_device_t dev, int cmd, void *arg)
488 {
489     LOGD(TAG, "%s entry, cmd %d, dev %p", __func__, cmd, dev);
490     DEV_ASSERT(dev != NULL);
491     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
492 
493     /* call device_write interface */
494     if (device_control != NULL)
495     {
496         return device_control(dev, cmd, arg);
497     } else {
498         LOGD(TAG, "%s dev %p device_control is NULL\r\n", __func__, dev);
499     }
500 
501     return -1;
502 }
503 
504 /**
505  * This function will set the reception indication callback function. This callback function
506  * is invoked when this device receives data.
507  *
508  * @param dev the pointer of device driver structure
509  * @param rx_ind the indication callback function
510  *
511  * @return 0
512  */
513 int aos_device_set_rx_indicate(aos_device_t dev,
514                           int (*rx_ind)(aos_device_t dev, size_t size))
515 {
516     DEV_ASSERT(dev != NULL);
517     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
518 
519     dev->rx_indicate = rx_ind;
520 
521     return 0;
522 }
523 
524 
525 /**
526  * This function will set the indication callback function when device has
527  * written data to physical hardware.
528  *
529  * @param dev the pointer of device driver structure
530  * @param tx_done the indication callback function
531  *
532  * @return 0
533  */
534 int aos_device_set_tx_complete(aos_device_t dev,
535                            int (*tx_done)(aos_device_t dev, void *buffer))
536 {
537     DEV_ASSERT(dev != NULL);
538     DEV_ASSERT(aos_object_get_type(&dev->parent) == AOS_Object_Class_Device);
539 
540     dev->tx_complete = tx_done;
541 
542     return 0;
543 }
544