1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2011-03-12     Yi Qiu      first version
9  * 2021-02-23     Leslie Lee  provide possibility for multi usb host
10  */
11 
12 #include <rtthread.h>
13 #include <rtservice.h>
14 #include <drivers/usb_host.h>
15 
16 static rt_list_t _driver_list;
17 static rt_bool_t _driver_list_created = RT_FALSE;
18 
19 /**
20  * This function will initilize the usb class driver related data structure,
21  * and it should be invoked in the usb system initialization.
22  *
23  * @return the error code, RT_EOK on successfully.
24  */
rt_usbh_class_driver_init(void)25 rt_err_t rt_usbh_class_driver_init(void)
26 {
27     if (_driver_list_created == RT_FALSE)
28     {
29         rt_list_init(&_driver_list);
30         _driver_list_created = RT_TRUE;
31     }
32     return RT_EOK;
33 }
34 
35 /**
36  * This function will register an usb class driver to the class driver manager.
37  *
38  * @param drv the pointer of the usb class driver.
39  *
40  * @return the error code, RT_EOK on successfully.
41  */
42 
rt_usbh_class_driver_register(ucd_t drv)43 rt_err_t rt_usbh_class_driver_register(ucd_t drv)
44 {
45     if (drv == RT_NULL) return -RT_ERROR;
46 
47     if (rt_usbh_class_driver_find(drv->class_code, drv->subclass_code) == RT_NULL)
48     {
49         /* insert class driver into driver list */
50         rt_list_insert_after(&_driver_list, &(drv->list));
51     }
52 
53     return RT_EOK;
54 }
55 
56 /**
57  * This function will removes a previously registed usb class driver.
58  *
59  * @param drv the pointer of the usb class driver structure.
60  *
61  * @return the error code, RT_EOK on successfully.
62  */
rt_usbh_class_driver_unregister(ucd_t drv)63 rt_err_t rt_usbh_class_driver_unregister(ucd_t drv)
64 {
65     RT_ASSERT(drv != RT_NULL);
66 
67     /* remove class driver from driver list */
68     rt_list_remove(&(drv->list));
69 
70     return RT_EOK;
71 }
72 
73 /**
74  * This function will run an usb class driver.
75  *
76  * @param drv the pointer of usb class driver.
77  * @param args the parameter of run function.
78  *
79  * @return the error code, RT_EOK on successfully.
80  */
rt_usbh_class_driver_enable(ucd_t drv,void * args)81 rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args)
82 {
83     RT_ASSERT(drv != RT_NULL);
84 
85     if(drv->enable != RT_NULL)
86         drv->enable(args);
87 
88     return RT_EOK;
89 }
90 
91 /**
92  * This function will stop a usb class driver.
93  *
94  * @param drv the pointer of usb class driver structure.
95  * @param args the argument of the stop function.
96  *
97  * @return the error code, RT_EOK on successfully.
98  */
rt_usbh_class_driver_disable(ucd_t drv,void * args)99 rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args)
100 {
101     RT_ASSERT(drv != RT_NULL);
102 
103     if(drv->disable != RT_NULL)
104         drv->disable(args);
105 
106     return RT_EOK;
107 }
108 
109 
110 /**
111  * This function finds a usb class driver by specified class code and subclass code.
112  *
113  * @param class_code the usb class driver's class code.
114  * @param subclass_code the usb class driver's sub class code.
115  *
116  * @return the registered usb class driver on successful, or RT_NULL on failure.
117  */
rt_usbh_class_driver_find(int class_code,int subclass_code)118 ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code)
119 {
120     struct rt_list_node *node;
121 
122     /* enter critical */
123     if (rt_thread_self() != RT_NULL)
124         rt_enter_critical();
125 
126     /* try to find driver object */
127     for (node = _driver_list.next; node != &_driver_list; node = node->next)
128     {
129         ucd_t drv =
130             (ucd_t)rt_list_entry(node, struct uclass_driver, list);
131         if (drv->class_code == class_code)
132         {
133             /* leave critical */
134             if (rt_thread_self() != RT_NULL)
135                 rt_exit_critical();
136 
137             return drv;
138         }
139     }
140 
141     /* leave critical */
142     if (rt_thread_self() != RT_NULL)
143         rt_exit_critical();
144 
145     /* not found */
146     return RT_NULL;
147 }
148