1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2022-02-16     Tuber             first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "board.h"
14 #include "drv_usbh.h"
15 
16 #ifdef BSP_USING_USBH
17 
18 static struct rt_completion urb_completion;
19 
20 //USB接收缓存区
21 __align(4) UINT8 usb_rx_buf[MAX_PACKET_SIZE];   // IN, must even address
22 __align(4) UINT8 usb_tx_buf[MAX_PACKET_SIZE];   // OUT, must even address
23 
24 static struct uhcd uhcd;
25 
drv_reset_port(rt_uint8_t port)26 static rt_err_t drv_reset_port(rt_uint8_t port)
27 {
28     //关闭中断
29     R8_USB_INT_EN = 0x00;
30 
31     R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | (0x00 & MASK_USB_ADDR);   //设置地址
32     R8_UHOST_CTRL &= ~RB_UH_PORT_EN;    // 关掉端口
33 
34     //判断设备速度
35     if (R8_USB_MIS_ST & RB_UMS_DM_LEVEL)
36     {
37         //低速
38         R8_USB_CTRL |= RB_UC_LOW_SPEED; // 默认为低速
39         R8_UHOST_CTRL = (R8_UHOST_CTRL | RB_UH_LOW_SPEED) | RB_UH_BUS_RESET;    // 默认为低速,开始复位
40     }
41     else
42     {
43         //全速
44         R8_USB_CTRL &= ~ RB_UC_LOW_SPEED;   // 默认为全速
45         R8_UHOST_CTRL = (R8_UHOST_CTRL & ~RB_UH_LOW_SPEED) | RB_UH_BUS_RESET;   // 默认为全速,开始复位
46     }
47 
48     rt_thread_mdelay(15); // 复位时间10mS到20mS
49     R8_UHOST_CTRL = R8_UHOST_CTRL & ~ RB_UH_BUS_RESET;  // 结束复位
50     rt_thread_mdelay(1);
51     R8_UHOST_CTRL |= RB_UH_PORT_EN; //打开端口
52     R8_USB_INT_FG = RB_UIF_DETECT;  // 清中断标志
53     //打开中断
54     R8_USB_INT_EN = RB_UIF_TRANSFER | RB_UIE_DETECT;
55 
56     return RT_EOK;
57 }
58 
drv_pipe_xfer(upipe_t pipe,rt_uint8_t token,void * buffer,int nbytes,int timeouts)59 static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
60 {
61     rt_err_t res;
62     UINT16 i;
63     UINT16 retry_count = 3;
64     rt_uint8_t usb_pid, res_pid;
65     UINT8 *tog = (UINT8 *)pipe->user_data;
66 
67     //设置目标usb地址
68     R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | (pipe->inst->address & MASK_USB_ADDR);
69 
70     //判断是in还是out操作
71     if (pipe->ep.bEndpointAddress & USB_DIR_IN)
72     {
73         usb_pid = USB_PID_IN; //in
74         R8_UH_TX_LEN = 0x00;
75     }
76     else
77     {
78         usb_pid = (token == USBH_PID_SETUP) ? USB_PID_SETUP : USB_PID_OUT; //setup/out
79         rt_memcpy(usb_tx_buf, buffer, nbytes);
80         R8_UH_TX_LEN = nbytes;
81     }
82 
83     //设置数据TOG
84     switch (usb_pid)
85     {
86     case USB_PID_IN:
87         if (nbytes == 0) *tog = USB_PID_DATA1; //状态反馈
88         R8_UH_RX_CTRL = (*tog == USB_PID_DATA1) ? RB_UH_R_TOG : 0x00;
89         break;
90 
91     case USB_PID_OUT:
92         if (nbytes == 0) *tog = USB_PID_DATA1; //状态反馈
93         R8_UH_TX_CTRL = (*tog == USB_PID_DATA1) ? RB_UH_T_TOG : 0x00;
94         break;
95 
96     case USB_PID_SETUP:
97         *(UINT8 *)pipe->inst->pipe_ep0_out->user_data = USB_PID_DATA0;
98         *(UINT8 *)pipe->inst->pipe_ep0_in->user_data = USB_PID_DATA1;
99         R8_UH_TX_CTRL = (*tog == USB_PID_DATA1) ? RB_UH_T_TOG : 0x00;
100         break;
101     }
102 
103     //usb枚举的时候加大重试次数,提高usb设备枚举成功率
104     if ((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_CONTROL)
105     {
106         retry_count = 1000;
107     }
108 
109     for (i = 0; i < retry_count; i++)
110     {
111         //传输
112         R8_UH_EP_PID = (usb_pid << 4) | (pipe->ep.bEndpointAddress & 0x0F);
113         res = rt_completion_wait(&urb_completion, timeouts);
114         if (res != RT_EOK)
115         {
116             return res;
117         }
118 
119         //判断是否需要反转数据
120         if (R8_USB_INT_ST & RB_UIS_TOG_OK)
121         {
122             *tog = (*tog == USB_PID_DATA0) ? USB_PID_DATA1 : USB_PID_DATA0;//翻转
123         }
124 
125         res_pid = R8_USB_INT_ST & MASK_UIS_H_RES;
126 
127         switch (res_pid)
128         {
129         case USB_PID_ACK://发送成功
130             pipe->status = UPIPE_STATUS_OK;
131             if (pipe->callback != RT_NULL) pipe->callback(pipe);
132             return nbytes;
133         case USB_PID_DATA0: //收到数据
134         case USB_PID_DATA1: //收到数据
135             pipe->status = UPIPE_STATUS_OK;
136             if (pipe->callback != RT_NULL) pipe->callback(pipe);
137             //拷贝数据到buffer
138             if (usb_pid == USB_PID_IN)
139             {
140                 rt_memcpy(buffer, usb_rx_buf, R8_USB_RX_LEN);
141                 return R8_USB_RX_LEN;
142             }
143             return nbytes;
144         case USB_PID_NAK: //数据未就绪
145             if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
146             {
147                 rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
148             }
149             rt_thread_mdelay(1);
150             continue;//重试
151         case USB_PID_STALL: //传输停止
152             pipe->status = UPIPE_STATUS_STALL;
153             if (pipe->callback != RT_NULL) pipe->callback(pipe);
154             return 0;
155         default:
156             break;
157         }
158     }
159 
160     pipe->status = UPIPE_STATUS_ERROR;
161 
162     if (pipe->callback != RT_NULL) pipe->callback(pipe);
163     return -RT_ERROR;
164 }
165 
drv_open_pipe(upipe_t pipe)166 static rt_err_t drv_open_pipe(upipe_t pipe)
167 {
168     pipe->pipe_index = pipe->inst->address & MASK_USB_ADDR;
169     pipe->user_data = rt_malloc(sizeof(UINT8));
170 
171     //默认发送DATA0
172     if (pipe->ep.bEndpointAddress & USB_DIR_IN)
173     {
174         *(UINT8 *)pipe->user_data = USB_PID_DATA0;
175     }
176     else
177     {
178         *(UINT8 *)pipe->user_data = USB_PID_DATA0;
179     }
180 
181 
182     return RT_EOK;
183 }
184 
drv_close_pipe(upipe_t pipe)185 static rt_err_t drv_close_pipe(upipe_t pipe)
186 {
187     rt_free(pipe->user_data);
188 
189     return RT_EOK;
190 }
191 
192 static struct uhcd_ops uhcd_ops =
193 {
194     drv_reset_port,
195     drv_pipe_xfer,
196     drv_open_pipe,
197     drv_close_pipe,
198 };
199 
hcd_init(rt_device_t dev)200 static rt_err_t hcd_init(rt_device_t dev)
201 {
202     R16_PIN_ANALOG_IE |= RB_PIN_USB_IE;
203 
204     R8_USB_CTRL = RB_UC_HOST_MODE;
205     R8_UHOST_CTRL = 0;
206     R8_USB_DEV_AD = 0x00;
207 
208     R8_UH_EP_MOD = RB_UH_EP_TX_EN | RB_UH_EP_RX_EN;
209     R16_UH_RX_DMA = (UINT16)(UINT32)usb_rx_buf;
210     R16_UH_TX_DMA = (UINT16)(UINT32)usb_tx_buf;
211 
212     R8_USB_CTRL =  RB_UC_HOST_MODE | RB_UC_INT_BUSY | RB_UC_DMA_EN;
213     R8_UH_SETUP = RB_UH_SOF_EN;
214     R8_USB_INT_FG = 0xFF;
215 
216     R8_USB_INT_EN = RB_UIF_TRANSFER | RB_UIE_DETECT;
217 
218     //开启中断
219     NVIC_EnableIRQ(USB_IRQn);
220 
221     rt_completion_init(&urb_completion);
222 
223     return RT_EOK;
224 }
225 
USB_IRQHandler()226 void USB_IRQHandler()
227 {
228     rt_interrupt_enter();
229 
230     //USB连接断开中断
231     if (R8_USB_INT_FG & RB_UIF_DETECT)
232     {
233         R8_USB_INT_FG = RB_UIF_DETECT;//清除中断
234 
235         //检查USB设备连接状态
236         if ((R8_USB_MIS_ST & RB_UMS_DEV_ATTACH) != 0)
237         {
238             rt_usbh_root_hub_connect_handler(&uhcd, 1, RT_FALSE);
239             rt_kprintf("usb: up\n");
240         }
241         else
242         {
243             rt_usbh_root_hub_disconnect_handler(&uhcd, 1);
244             rt_kprintf("usb: down\n");
245         }
246     }
247 
248     if (R8_USB_INT_FG & RB_UIF_TRANSFER)
249     {
250         R8_UH_EP_PID = 0x00; //停止发送
251 
252         R8_USB_INT_FG = RB_UIF_TRANSFER;//清除中断
253 
254         rt_completion_done(&urb_completion);
255     }
256 
257     if (R8_USB_INT_FG & RB_UIF_SUSPEND)
258     {
259         R8_USB_INT_FG = RB_UIF_SUSPEND;//清除中断
260     }
261 
262     if (R8_USB_INT_FG & RB_UIF_HST_SOF)
263     {
264         R8_USB_INT_FG = RB_UIF_HST_SOF;//清除中断
265     }
266 
267     if (R8_USB_INT_FG & RB_UIF_FIFO_OV)
268     {
269         R8_USB_INT_FG = RB_UIF_FIFO_OV;//清除中断
270     }
271 
272     rt_interrupt_leave();
273 }
274 
rt_hw_usbh_init(void)275 int rt_hw_usbh_init(void)
276 {
277     rt_err_t res = -RT_ERROR;
278 
279     rt_memset((void *)&uhcd, 0, sizeof(struct uhcd));
280     uhcd.parent.type = RT_Device_Class_USBHost;
281     uhcd.parent.init = hcd_init;
282     uhcd.ops = &uhcd_ops;
283     uhcd.num_ports = 1;
284 
285     res = rt_device_register(&uhcd.parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
286 
287     if (res != RT_EOK)
288     {
289         rt_kprintf("register usb host failed res = %d\r\n", res);
290         return -RT_ERROR;
291     }
292 
293     rt_usb_host_init("usbh");
294 
295     return RT_EOK;
296 }
297 INIT_DEVICE_EXPORT(rt_hw_usbh_init);
298 #endif /* BSP_USING_USBH */
299 
300