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