1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-02-28     leo          first version
9  * 2024-02-26     shelton      update drv_pipe_xfer
10  * 2024-12-18     shelton      update drv_pipe_xfer
11  */
12 
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 #include "drv_common.h"
16 
17 #if defined(BSP_USING_HOST_USBOTG1) || defined(BSP_USING_HOST_USBOTG2)
18 #include "usbh_int.h"
19 #include "drv_usbotg.h"
20 #include "drv_config.h"
21 
22 //#define DRV_DEBUG
23 #define LOG_TAG             "drv.usb.fsh"
24 #include <drv_log.h>
25 
26 static struct rt_completion urb_completion;
27 static volatile rt_bool_t connect_status = RT_FALSE;
28 static struct at32_usbotg *p_usbotg_instance = RT_NULL;
29 
30 enum
31 {
32 #ifdef BSP_USING_HOST_USBOTG1
33     USBOTG1_INDEX,
34 #endif
35 #ifdef BSP_USING_HOST_USBOTG2
36     USBOTG2_INDEX,
37 #endif
38 };
39 
40 static struct at32_usbotg usbotgh_config[] = {
41 #ifdef BSP_USING_HOST_USBOTG1
42     USBOTG1_CONFIG,
43 #endif
44 #ifdef BSP_USING_HOST_USBOTG2
45     USBOTG2_CONFIG,
46 #endif
47 };
48 
49 #ifdef BSP_USING_HOST_USBOTG1
OTGFS1_IRQHandler(void)50 void OTGFS1_IRQHandler(void)
51 {
52     /* enter interrupt */
53     rt_interrupt_enter();
54 
55     usbh_irq_handler(p_usbotg_instance->p_otg_core);
56 
57     /* leave interrupt */
58     rt_interrupt_leave();
59 }
60 #endif
61 
62 #ifdef BSP_USING_HOST_USBOTG2
OTGFS2_IRQHandler(void)63 void OTGFS2_IRQHandler(void)
64 {
65     /* enter interrupt */
66     rt_interrupt_enter();
67 
68     usbh_irq_handler(p_usbotg_instance->p_otg_core);
69 
70     /* leave interrupt */
71     rt_interrupt_leave();
72 }
73 #endif
74 
usbh_connect_callback(usbh_core_type * uhost)75 void usbh_connect_callback(usbh_core_type *uhost)
76 {
77     uhcd_t hcd = (uhcd_t)uhost->pdata;
78     if (!connect_status)
79     {
80         connect_status = RT_TRUE;
81         LOG_D("usb connected");
82         rt_usbh_root_hub_connect_handler(hcd, 1, RT_FALSE);
83     }
84 }
85 
usbh_disconnect_callback(usbh_core_type * uhost)86 void usbh_disconnect_callback(usbh_core_type *uhost)
87 {
88     uhcd_t hcd = (uhcd_t)uhost->pdata;
89     if (connect_status)
90     {
91         connect_status = RT_FALSE;
92         LOG_D("usb disconnnect");
93         rt_usbh_root_hub_disconnect_handler(hcd, 1);
94     }
95 }
96 
usbd_notify_urbchange_callback(usbh_core_type * uhost,uint8_t chnum,urb_sts_type sts)97 void usbd_notify_urbchange_callback(usbh_core_type *uhost, uint8_t chnum, urb_sts_type sts)
98 {
99     rt_completion_done(&urb_completion);
100 }
101 
drv_reset_port(rt_uint8_t port)102 static rt_err_t drv_reset_port(rt_uint8_t port)
103 {
104     LOG_D("reset port");
105     usbh_reset_port(&p_usbotg_instance->p_otg_core->host);
106     return RT_EOK;
107 }
108 
drv_pipe_xfer(upipe_t pipe,rt_uint8_t token,void * buffer,int nbytes,int timeouts)109 static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
110 {
111     int timeout = timeouts;
112     static uint8_t data_pid = 0;
113     uint32_t direction = (pipe->ep.bEndpointAddress & 0x80) >> 7;
114 
115     while(1)
116     {
117         if(!connect_status)
118         {
119             return -1;
120         }
121 
122         rt_completion_init(&urb_completion);
123         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].dir = direction;
124 
125         if(token == 0U)
126         {
127             p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_SETUP;
128             data_pid = 0;
129         }
130 
131         /* endpoint type */
132         switch(pipe->ep.bmAttributes)
133         {
134             /* endpoint is control type */
135             case EPT_CONTROL_TYPE:
136                 if((token == 1U) && (direction == 0U))
137                 {
138                     if(nbytes == 0U)
139                     {
140                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out = 1U;
141                     }
142                     if(p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out == 0U)
143                     {
144                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
145                     }
146                     else
147                     {
148                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
149                     }
150                 }
151                 else if(token == 1U)
152                 {
153                     if(data_pid == 0)
154                     {
155                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
156                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in = 1;
157                         data_pid = 1;
158                     }
159                     else
160                     {
161                         if(nbytes == 0U)
162                         {
163                             p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in = 1U;
164                         }
165                         if(p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in == 0U)
166                         {
167                             p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
168                         }
169                         else
170                         {
171                             p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
172                         }
173                     }
174                 }
175                 break;
176             /* endpoint is bulk type */
177             case EPT_BULK_TYPE:
178                 if(direction == 0U)
179                 {
180                     if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out == 0U)
181                     {
182                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
183                     }
184                     else
185                     {
186                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
187                     }
188                 }
189                 else
190                 {
191                     if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in == 0U)
192                     {
193                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
194                     }
195                     else
196                     {
197                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
198                     }
199                 }
200                 break;
201             /* endpoint is int type */
202             case  EPT_INT_TYPE:
203                 if(direction == 0U)
204                 {
205                     if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out == 0U)
206                     {
207                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
208                     }
209                     else
210                     {
211                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
212                     }
213                 }
214                 else
215                 {
216                     if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in == 0U)
217                     {
218                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
219                     }
220                     else
221                     {
222                         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
223                     }
224                 }
225                 break;
226             /* endpoint is isoc type */
227             case EPT_ISO_TYPE:
228                 p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
229                 break;
230 
231             default:
232                 break;
233         }
234 
235         /* set transfer buffer */
236         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].trans_buf = buffer;
237         /* set transfer len*/
238         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].trans_len = nbytes;
239         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].urb_sts = URB_IDLE;
240         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].ch_num = pipe->pipe_index;
241         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].trans_count = 0;
242         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].state = HCH_IDLE;
243 
244         /* data in/out for host */
245         usbh_in_out_request((&p_usbotg_instance->p_otg_core->host), pipe->pipe_index);
246 
247         rt_completion_wait(&urb_completion, timeout);
248         rt_thread_mdelay(1);
249 
250         if(usbh_get_urb_status((&p_usbotg_instance->p_otg_core->host), pipe->pipe_index) == URB_NOTREADY)
251         {
252             LOG_D("nak");
253             if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
254             {
255                 rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
256             }
257             continue;
258         }
259         else if (usbh_get_urb_status(&p_usbotg_instance->p_otg_core->host, pipe->pipe_index) == URB_STALL)
260         {
261             LOG_D("stall");
262             pipe->status = UPIPE_STATUS_STALL;
263             if (pipe->callback != RT_NULL)
264             {
265                 pipe->callback(pipe);
266             }
267             return -1;
268         }
269         else if (usbh_get_urb_status(&p_usbotg_instance->p_otg_core->host, pipe->pipe_index) == URB_ERROR)
270         {
271             LOG_D("error");
272             pipe->status = UPIPE_STATUS_ERROR;
273             if (pipe->callback != RT_NULL)
274             {
275                 pipe->callback(pipe);
276             }
277             return -1;
278         }
279         else if (usbh_get_urb_status(&p_usbotg_instance->p_otg_core->host, pipe->pipe_index) == URB_DONE)
280         {
281             LOG_D("ok");
282             pipe->status = UPIPE_STATUS_OK;
283             if (pipe->callback != RT_NULL)
284             {
285                 pipe->callback(pipe);
286             }
287             rt_size_t size = (&p_usbotg_instance->p_otg_core->host)->hch[pipe->pipe_index].trans_count;
288             if (pipe->ep.bEndpointAddress & 0x80)
289             {
290                 return size;
291             }
292             else if (pipe->ep.bEndpointAddress & 0x00)
293             {
294                 return size;
295             }
296             return nbytes;
297         }
298         continue;
299     }
300 }
301 
302 static rt_uint16_t pipe_index = 0;
drv_get_free_pipe_index(void)303 static rt_uint8_t  drv_get_free_pipe_index(void)
304 {
305     rt_uint8_t idx;
306     for (idx = 1; idx < 16; idx++)
307     {
308         if (!(pipe_index & (0x01 << idx)))
309         {
310             pipe_index |= (0x01 << idx);
311             return idx;
312         }
313     }
314     return 0xff;
315 }
316 
drv_free_pipe_index(rt_uint8_t index)317 static void drv_free_pipe_index(rt_uint8_t index)
318 {
319     pipe_index &= ~(0x01 << index);
320 }
321 
drv_open_pipe(upipe_t pipe)322 static rt_err_t drv_open_pipe(upipe_t pipe)
323 {
324     pipe->pipe_index = drv_get_free_pipe_index();
325     usbh_hc_open(&p_usbotg_instance->p_otg_core->host,
326                  pipe->pipe_index,
327                  pipe->ep.bEndpointAddress,
328                  pipe->inst->address,
329                  pipe->ep.bmAttributes,
330                  pipe->ep.wMaxPacketSize,
331                  USB_PRTSPD_FULL_SPEED);
332     /* set data0 pid token*/
333     if (p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].dir)
334     {
335         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in = 0;
336     }
337     else
338     {
339         p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out = 0;
340     }
341     return RT_EOK;
342 }
343 
drv_close_pipe(upipe_t pipe)344 static rt_err_t drv_close_pipe(upipe_t pipe)
345 {
346     usb_hch_halt((&p_usbotg_instance->p_otg_core->host)->usb_reg, pipe->pipe_index);
347     drv_free_pipe_index(pipe->pipe_index);
348     return RT_EOK;
349 }
350 
351 static struct uhcd_ops _uhcd_ops =
352 {
353     drv_reset_port,
354     drv_pipe_xfer,
355     drv_open_pipe,
356     drv_close_pipe,
357 };
358 
at32_hcd_init(rt_device_t device)359 static rt_err_t at32_hcd_init(rt_device_t device)
360 {
361     /* usb gpio config */
362     at32_msp_usb_init(device);
363 
364     /* enable otgfs irq */
365     nvic_irq_enable(p_usbotg_instance->irqn, 2, 0);
366 
367     /* init usb */
368     usbh_init(p_usbotg_instance->p_otg_core,
369               p_usbotg_instance->dev_spd,
370               p_usbotg_instance->id);
371     return RT_EOK;
372 }
373 
at32_usbh_register(void)374 int at32_usbh_register(void)
375 {
376     rt_size_t obj_num;
377     rt_err_t result = 0;
378     int index;
379 
380     obj_num = sizeof(usbotgh_config) / sizeof(struct at32_usbotg);
381 
382     for (index = 0; index < obj_num; index++) {
383         uhcd_t uhcd = (uhcd_t)rt_malloc(sizeof(struct uhcd));
384         if (uhcd == RT_NULL)
385         {
386             rt_kprintf("uhcd malloc failed\r\n");
387             return -RT_ERROR;
388         }
389         rt_memset((void *)uhcd, 0, sizeof(struct uhcd));
390 
391         otg_core_type *p_otg_core = (otg_core_type *)rt_malloc(sizeof(otg_core_type));
392         if (p_otg_core == RT_NULL)
393         {
394             rt_kprintf("otg_core malloc failed\r\n");
395             return -RT_ERROR;
396         }
397         rt_memset((void *)p_otg_core, 0, sizeof(otg_core_type));
398 
399         uhcd->parent.type = RT_Device_Class_USBHost;
400         uhcd->parent.init = at32_hcd_init;
401         uhcd->parent.user_data = &(p_otg_core->host);
402 
403         uhcd->ops = &_uhcd_ops;
404         uhcd->num_ports = 1;
405         p_otg_core->host.pdata = uhcd;
406         usbotgh_config[index].p_otg_core = p_otg_core;
407 
408         result = rt_device_register(&uhcd->parent, usbotgh_config[index].name, RT_DEVICE_FLAG_DEACTIVATE);
409         RT_ASSERT(result == RT_EOK);
410 
411         p_usbotg_instance = &usbotgh_config[index];
412 
413         result = rt_usb_host_init(usbotgh_config[index].name);
414         RT_ASSERT(result == RT_EOK);
415     }
416 
417     return result;
418 }
419 
420 INIT_DEVICE_EXPORT(at32_usbh_register);
421 
422 #endif
423