1 /******************************************************************************************************************************************
2 * 文件名称: usbh_core.c
3 * 功能说明:
4 * 技术支持: http://www.synwit.com.cn/e/tool/gbook/?bid=1
5 * 注意事项:
6 * 版本日期: V1.1.0 2020年11月3日
7 * 升级记录:
8 *
9 *
10 *******************************************************************************************************************************************
11 * @attention
12 *
13 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
14 * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
15 * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
16 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
17 * -ECTION WITH THEIR PRODUCTS.
18 *
19 * COPYRIGHT 2012 Synwit Technology
20 *******************************************************************************************************************************************/
21 #include <stdlib.h>
22 #include <string.h>
23 #include "SWM341.h"
24 #include "usbh_core.h"
25 #include "usbh_stdreq.h"
26
27
28 USBH_Info_t USBH_Info;
29
30
31 /******************************************************************************************************************************************
32 * 函数名称: USBH_Init()
33 * 功能说明: USB Host 初始化
34 * 输 入: 无
35 * 输 出: 无
36 * 注意事项: 无
37 ******************************************************************************************************************************************/
USBH_Init(USBH_Class_cb_t * class_cb,USBH_User_cb_t * usr_cb)38 void USBH_Init(USBH_Class_cb_t *class_cb, USBH_User_cb_t *usr_cb)
39 {
40 USBH_HW_Init();
41
42 USBH_DeInit();
43
44 /* Register class and user callbacks */
45 USBH_Info.class_cb = class_cb;
46 USBH_Info.usr_cb = usr_cb;
47
48 /* Upon Init call usr call back */
49 if(USBH_Info.usr_cb->Init)
50 USBH_Info.usr_cb->Init();
51 }
52
53
54 /******************************************************************************************************************************************
55 * 函数名称: USBH_DeInit()
56 * 功能说明: USB Host Re-Initialize
57 * 输 入: 无
58 * 输 出: 无
59 * 注意事项: 无
60 ******************************************************************************************************************************************/
USBH_DeInit(void)61 void USBH_DeInit(void)
62 {
63 USBH->PORTSR = USBH_PORTSR_CONNCHG_Msk | // 清零标志位
64 USBH_PORTSR_RSTCHG_Msk |
65 USBH_PORTSR_ENACHG_Msk;
66
67 USBH_Info.State = HOST_IDLE;
68 USBH_Info.EnumState = ENUM_GET_DEV_DESC;
69
70 USBH_Info.Ctrl.pksz = 8;
71
72 USBH_Info.Ctrl.toggle_in = 0;
73 USBH_Info.Ctrl.toggle_out = 0;
74
75 USBH_Info.Ctrl.state = CTRL_IDLE;
76
77 USBH_Info.Device.Address = 0;
78 }
79
80
81 /******************************************************************************************************************************************
82 * 函数名称: USBH_Process()
83 * 功能说明: USB Host core main state machine process
84 * 输 入: 无
85 * 输 出: 无
86 * 注意事项: 无
87 ******************************************************************************************************************************************/
USBH_Process(void)88 void USBH_Process(void)
89 {
90 static uint32_t frameNbr;
91 USBH_Status status = USBH_FAIL;
92
93 if(USBH_Info.State != HOST_IDLE)
94 {
95 if(!USBH_IsDeviceConnected())
96 USBH_Info.State = HOST_DEV_DETACHED;
97 }
98
99 switch(USBH_Info.State)
100 {
101 case HOST_IDLE:
102 if(USBH_IsDeviceConnected())
103 {
104 USBH_Info.State = HOST_DEV_ATTACHED;
105
106 if(USBH_Info.usr_cb->DeviceAttached)
107 USBH_Info.usr_cb->DeviceAttached();
108
109 frameNbr = USBH->FRAMENR;
110 }
111 break;
112
113 case HOST_DEV_ATTACHED:
114 if(abs((int)frameNbr - (int)USBH->FRAMENR) > 100)
115 {
116 USBH_Info.State = HOST_PORT_RESETED;
117
118 USBH_ResetPort();
119 }
120 break;
121
122 case HOST_PORT_RESETED:
123 if(USBH_IsPortEnabled())
124 {
125 USBH_Info.State = HOST_PORT_ENABLED;
126
127 frameNbr = USBH->FRAMENR;
128 }
129 break;
130
131 case HOST_PORT_ENABLED:
132 if(abs((int)frameNbr - (int)USBH->FRAMENR) > 10)
133 {
134 USBH_Info.State = HOST_ENUMERATION;
135
136 USBH_Info.Device.Speed = USBH_GetDeviceSpeed();
137
138 if(USBH_Info.usr_cb->DeviceSpeedDetected)
139 USBH_Info.usr_cb->DeviceSpeedDetected(USBH_Info.Device.Speed);
140 }
141 break;
142
143 case HOST_ENUMERATION:
144 if(USBH_HandleEnum(&USBH_Info) == USBH_OK)
145 {
146 USBH_Info.State = HOST_USR_INPUT;
147
148 if(USBH_Info.usr_cb->EnumerationDone)
149 USBH_Info.usr_cb->EnumerationDone();
150 }
151 break;
152
153 case HOST_USR_INPUT:
154 /* The function should return user response true to move to class state */
155 if(USBH_Info.usr_cb->UserInput())
156 {
157 if((USBH_Info.class_cb->Init(&USBH_Info)) == USBH_OK)
158 {
159 USBH_Info.State = HOST_CLASS_REQUEST;
160 }
161 }
162 break;
163
164 case HOST_CLASS_REQUEST:
165 /* process class standard control requests state machine */
166 status = USBH_Info.class_cb->Request(&USBH_Info);
167 if(status == USBH_OK)
168 {
169 USBH_Info.State = HOST_CLASS;
170 }
171 else
172 {
173 USBH_ErrorHandle(&USBH_Info, status);
174 }
175 break;
176
177 case HOST_CLASS:
178 /* process class state machine */
179 status = USBH_Info.class_cb->Process(&USBH_Info);
180 USBH_ErrorHandle(&USBH_Info, status);
181 break;
182
183 case HOST_CTRL_XFER:
184 /* process control transfer state machine */
185 USBH_HandleControl(&USBH_Info);
186 break;
187
188 case HOST_DEV_DETACHED:
189 if(USBH_Info.usr_cb->DeviceDisconnected)
190 USBH_Info.usr_cb->DeviceDisconnected();
191
192 /* Re-Initialize Host for new Enumeration */
193 USBH_DeInit();
194 if(USBH_Info.usr_cb->DeInit)
195 USBH_Info.usr_cb->DeInit();
196 USBH_Info.class_cb->DeInit(&USBH_Info);
197
198 USBH_Info.State = HOST_IDLE;
199 break;
200
201 default :
202 break;
203 }
204 }
205
206
207 uint8_t USBH_Cfg_Desc_Buffer[USBH_MAX_CFG_SIZE];
208 uint16_t USBH_Cfg_Desc_Length;
209 /******************************************************************************************************************************************
210 * 函数名称: USBH_HandleEnum()
211 * 功能说明: Handle the USB device enumeration state machine
212 * 输 入: 无
213 * 输 出: 无
214 * 注意事项: 无
215 ******************************************************************************************************************************************/
USBH_HandleEnum(USBH_Info_t * phost)216 USBH_Status USBH_HandleEnum(USBH_Info_t *phost)
217 {
218 USBH_Status status = USBH_BUSY;
219
220 switch(phost->EnumState)
221 {
222 case ENUM_GET_DEV_DESC:
223 if(USBH_GetDescriptor(phost, USB_DESC_DEVICE, 0, (uint8_t *)&phost->Device.Dev_Desc, 8) == USBH_OK)
224 {
225 phost->EnumState = ENUM_GET_FULL_DEV_DESC;
226
227 phost->Ctrl.pksz = phost->Device.Dev_Desc.bMaxPacketSize;
228 }
229 break;
230
231 case ENUM_GET_FULL_DEV_DESC:
232 if(USBH_GetDescriptor(phost, USB_DESC_DEVICE, 0, (uint8_t *)&phost->Device.Dev_Desc, sizeof(USB_DevDesc_t)) == USBH_OK)
233 {
234 phost->EnumState = ENUM_SET_ADDR;
235
236 if(phost->usr_cb->DeviceDescAvailable)
237 phost->usr_cb->DeviceDescAvailable(&phost->Device.Dev_Desc);
238 }
239 break;
240
241 case ENUM_SET_ADDR:
242 if(USBH_SetAddress(phost, USBH_DEVICE_ADDRESS) == USBH_OK)
243 {
244 phost->EnumState = ENUM_GET_CFG_DESC;
245
246 phost->Device.Address = USBH_DEVICE_ADDRESS;
247
248 if(phost->usr_cb->DeviceAddressAssigned)
249 phost->usr_cb->DeviceAddressAssigned();
250 }
251 break;
252
253 case ENUM_GET_CFG_DESC:
254 if(USBH_GetDescriptor(phost, USB_DESC_CONFIG, 0, (uint8_t *)&phost->Device.Cfg_Desc, sizeof(USB_CfgDesc_t)) == USBH_OK)
255 {
256 if(phost->Device.Cfg_Desc.wTotalLength <= USBH_MAX_CFG_SIZE)
257 {
258 phost->EnumState = ENUM_GET_FULL_CFG_DESC;
259 }
260 else
261 {
262 status = USBH_NOT_SUPPORTED;
263 }
264 }
265 break;
266
267 case ENUM_GET_FULL_CFG_DESC:
268 if(USBH_GetDescriptor(phost, USB_DESC_CONFIG, 0, USBH_Cfg_Desc_Buffer, phost->Device.Cfg_Desc.wTotalLength) == USBH_OK)
269 {
270 phost->EnumState = ENUM_GET_VENDOR_STRING_DESC;
271
272 USBH_Cfg_Desc_Length = phost->Device.Cfg_Desc.wTotalLength;
273 USBH_ParseCfgDesc(phost, USBH_Cfg_Desc_Buffer, USBH_Cfg_Desc_Length);
274
275 if(phost->usr_cb->ConfigDescAvailable)
276 phost->usr_cb->ConfigDescAvailable(&phost->Device.Cfg_Desc, phost->Device.Intf_Desc, phost->Device.Ep_Desc[0]);
277 }
278 break;
279
280 case ENUM_GET_VENDOR_STRING_DESC:
281 if(phost->Device.Dev_Desc.iManufacturer != 0)
282 {
283 USBH_Status stat = USBH_GetDescriptor(phost, USB_DESC_STRING, phost->Device.Dev_Desc.iManufacturer, (uint8_t *)phost->Device.strVender, sizeof(phost->Device.strVender));
284 if(stat == USBH_OK)
285 {
286 phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
287
288 if(phost->usr_cb->VendorString)
289 phost->usr_cb->VendorString(phost->Device.strVender);
290 }
291 else if(stat == USBH_NOT_SUPPORTED)
292 {
293 phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
294 }
295 }
296 else
297 {
298 phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
299 }
300 break;
301
302 case ENUM_GET_PRODUCT_STRING_DESC:
303 if(phost->Device.Dev_Desc.iProduct != 0)
304 {
305 USBH_Status stat = USBH_GetDescriptor(phost, USB_DESC_STRING, phost->Device.Dev_Desc.iProduct, (uint8_t *)phost->Device.strProduct, sizeof(phost->Device.strProduct));
306 if(stat == USBH_OK)
307 {
308 phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
309
310 if(phost->usr_cb->ProductString)
311 phost->usr_cb->ProductString(phost->Device.strProduct);
312 }
313 else if(stat == USBH_NOT_SUPPORTED)
314 {
315 phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
316 }
317 }
318 else
319 {
320 phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
321 }
322 break;
323
324 case ENUM_GET_SERIALNUM_STRING_DESC:
325 if(phost->Device.Dev_Desc.iSerialNumber != 0)
326 {
327 USBH_Status stat = USBH_GetDescriptor(phost, USB_DESC_STRING, phost->Device.Dev_Desc.iSerialNumber, (uint8_t *)phost->Device.strSerialNumber, sizeof(phost->Device.strSerialNumber));
328 if(stat == USBH_OK)
329 {
330 phost->EnumState = ENUM_SET_CONFIGURATION;
331
332 if(phost->usr_cb->SerialNumString)
333 phost->usr_cb->SerialNumString(phost->Device.strSerialNumber);
334 }
335 else if(stat == USBH_NOT_SUPPORTED)
336 {
337 phost->EnumState = ENUM_SET_CONFIGURATION;
338 }
339 }
340 else
341 {
342 phost->EnumState = ENUM_SET_CONFIGURATION;
343 }
344 break;
345
346 case ENUM_SET_CONFIGURATION:
347 if(USBH_SetConfiguration(phost, phost->Device.Cfg_Desc.bConfigurationValue) == USBH_OK)
348 {
349 phost->EnumState = ENUM_DEV_CONFIGURED;
350 }
351 break;
352
353 case ENUM_DEV_CONFIGURED:
354 status = USBH_OK;
355 break;
356
357 default:
358 break;
359 }
360
361 return status;
362 }
363
364
365 /******************************************************************************************************************************************
366 * 函数名称: USBH_HandleControl()
367 * 功能说明: Handle the USB control transfer state machine
368 * 输 入: 无
369 * 输 出: 无
370 * 注意事项: 无
371 ******************************************************************************************************************************************/
USBH_HandleControl(USBH_Info_t * phost)372 void USBH_HandleControl(USBH_Info_t *phost)
373 {
374 static uint32_t size;
375 uint32_t real_size;
376 USBH_Resp resp;
377
378 switch(phost->Ctrl.state)
379 {
380 case CTRL_SETUP:
381 if(USBH_SendSetupPacket(phost->Device.Address, (uint8_t *)&phost->Ctrl.setup, 8))
382 {
383 phost->Ctrl.state = CTRL_SETUP_WAIT;
384 }
385 break;
386
387 case CTRL_SETUP_WAIT:
388 resp = USBH_State();
389 if(resp == USBR_ACK)
390 {
391 phost->Ctrl.toggle_in = 1;
392 phost->Ctrl.toggle_out = 1;
393
394 if(phost->Ctrl.setup.wLength != 0)
395 {
396 if(phost->Ctrl.setup.bRequestType & USB_EP_IN)
397 {
398 phost->Ctrl.state = CTRL_DATA_IN;
399 }
400 else
401 {
402 phost->Ctrl.state = CTRL_DATA_OUT;
403 }
404 }
405 else // No Data Stage
406 {
407 if(phost->Ctrl.setup.bRequestType & USB_EP_IN)
408 {
409 phost->Ctrl.state = CTRL_STATUS_OUT;
410 }
411 else
412 {
413 phost->Ctrl.state = CTRL_STATUS_IN;
414 }
415 }
416 }
417 else if(resp == USBR_ERROR)
418 {
419 phost->Ctrl.state = CTRL_SETUP; // retry
420 }
421 break;
422
423 case CTRL_DATA_IN:
424 size = (phost->Ctrl.size > phost->Ctrl.pksz) ? phost->Ctrl.pksz : phost->Ctrl.size;
425 if(USBH_SendInPacket(phost->Device.Address, 0, phost->Ctrl.toggle_in, size))
426 {
427 phost->Ctrl.state = CTRL_DATA_IN_WAIT;
428 }
429 break;
430
431 case CTRL_DATA_IN_WAIT:
432 resp = USBH_State();
433 if(resp == USBR_ACK)
434 {
435 phost->Ctrl.toggle_in ^= 1;
436
437 real_size = USBH_ReadRxBuffer(phost->Ctrl.buff, size);
438 if(real_size < size)
439 {
440 phost->Ctrl.state = CTRL_STATUS_OUT;
441 }
442 else
443 {
444 phost->Ctrl.size -= size;
445 phost->Ctrl.buff += size;
446
447 if(phost->Ctrl.size)
448 {
449 phost->Ctrl.state = CTRL_DATA_IN;
450 }
451 else
452 {
453 phost->Ctrl.state = CTRL_STATUS_OUT;
454 }
455 }
456 }
457 else if(resp == USBR_NAK)
458 {
459 phost->Ctrl.state = CTRL_DATA_IN; // retry
460 }
461 else if(resp == USBR_STALL)
462 {
463 phost->Ctrl.state = CTRL_STALLED;
464 phost->State = phost->StateBkp;
465 }
466 else if(resp == USBR_ERROR)
467 {
468 phost->Ctrl.state = CTRL_ERROR;
469 phost->State = phost->StateBkp;
470 }
471 break;
472
473 case CTRL_DATA_OUT:
474 size = (phost->Ctrl.size > phost->Ctrl.pksz) ? phost->Ctrl.pksz : phost->Ctrl.size;
475 if(USBH_SendOutPacket(phost->Device.Address, 0, phost->Ctrl.toggle_out, phost->Ctrl.buff, size))
476 {
477 phost->Ctrl.state = CTRL_DATA_OUT_WAIT;
478 }
479 break;
480
481 case CTRL_DATA_OUT_WAIT:
482 resp = USBH_State();
483 if(resp == USBR_ACK)
484 {
485 phost->Ctrl.toggle_out ^= 1;
486
487 phost->Ctrl.size -= size;
488 phost->Ctrl.buff += size;
489
490 if(phost->Ctrl.size)
491 {
492 phost->Ctrl.state = CTRL_DATA_OUT;
493 }
494 else
495 {
496 phost->Ctrl.state = CTRL_STATUS_IN;
497 }
498 }
499 else if(resp == USBR_NAK)
500 {
501 phost->Ctrl.state = CTRL_DATA_OUT; // retry
502 }
503 else if(resp == USBR_STALL)
504 {
505 phost->Ctrl.state = CTRL_STALLED;
506 phost->State = phost->StateBkp;
507 }
508 else if(resp == USBR_ERROR)
509 {
510 phost->Ctrl.state = CTRL_ERROR;
511 phost->State = phost->StateBkp;
512 }
513 break;
514
515 case CTRL_STATUS_IN:
516 if(USBH_SendInPacket(phost->Device.Address, 0, phost->Ctrl.toggle_in, 0))
517 {
518 phost->Ctrl.state = CTRL_STATUS_IN_WAIT;
519 }
520 break;
521
522 case CTRL_STATUS_IN_WAIT:
523 resp = USBH_State();
524 if(resp == USBR_ACK)
525 {
526 phost->Ctrl.toggle_in ^= 1;
527
528 phost->Ctrl.state = CTRL_COMPLETE;
529 phost->State = phost->StateBkp;
530 }
531 else if(resp == USBR_NAK)
532 {
533 phost->Ctrl.state = CTRL_STATUS_IN; // retry
534 }
535 else if(resp == USBR_STALL)
536 {
537 phost->Ctrl.state = CTRL_STALLED;
538 phost->State = phost->StateBkp;
539 }
540 else if(resp == USBR_ERROR)
541 {
542 phost->Ctrl.state = CTRL_ERROR;
543 phost->State = phost->StateBkp;
544 }
545 break;
546
547 case CTRL_STATUS_OUT:
548 if(USBH_SendOutPacket(phost->Device.Address, 0, phost->Ctrl.toggle_out, 0, 0))
549 {
550 phost->Ctrl.state = CTRL_STATUS_OUT_WAIT;
551 }
552 break;
553
554 case CTRL_STATUS_OUT_WAIT:
555 resp = USBH_State();
556 if(resp == USBR_ACK)
557 {
558 phost->Ctrl.toggle_out ^= 1;
559
560 phost->Ctrl.state = CTRL_COMPLETE;
561 phost->State = phost->StateBkp;
562 }
563 else if(resp == USBR_NAK)
564 {
565 phost->Ctrl.state = CTRL_STATUS_OUT; // retry
566 }
567 else if(resp == USBR_STALL)
568 {
569 phost->Ctrl.state = CTRL_STALLED;
570 phost->State = phost->StateBkp;
571 }
572 else if(resp == USBR_ERROR)
573 {
574 phost->Ctrl.state = CTRL_ERROR;
575 phost->State = phost->StateBkp;
576 }
577 break;
578
579 default:
580 break;
581 }
582 }
583
584
585 /******************************************************************************************************************************************
586 * 函数名称: USBH_CtrlTransfer()
587 * 功能说明: 控制传输
588 * 输 入: 无
589 * 输 出: 无
590 * 注意事项: 无
591 ******************************************************************************************************************************************/
USBH_CtrlTransfer(USBH_Info_t * phost,uint8_t * buff,uint16_t size)592 USBH_Status USBH_CtrlTransfer(USBH_Info_t *phost, uint8_t *buff, uint16_t size)
593 {
594 USBH_Status status = USBH_BUSY;
595
596 if(phost->Ctrl.state == CTRL_IDLE)
597 {
598 phost->Ctrl.buff = buff;
599 phost->Ctrl.size = size;
600 phost->Ctrl.state = CTRL_SETUP;
601
602 phost->StateBkp = phost->State;
603 phost->State = HOST_CTRL_XFER;
604 }
605 else
606 {
607 switch(phost->Ctrl.state)
608 {
609 case CTRL_COMPLETE: // Commands successfully sent and Response Received
610 status = USBH_OK;
611 phost->Ctrl.state = CTRL_IDLE;
612 break;
613
614 case CTRL_STALLED:
615 status = USBH_NOT_SUPPORTED;
616 phost->Ctrl.state = CTRL_IDLE;
617 break;
618
619 case CTRL_ERROR:
620 status = USBH_FAIL;
621 phost->Ctrl.state = CTRL_IDLE;
622 break;
623
624 default:
625 break;
626 }
627 }
628
629 return status;
630 }
631
632
633 /******************************************************************************************************************************************
634 * 函数名称: USBH_ErrorHandle()
635 * 功能说明: Handles the Error on Host side.
636 * 输 入: 无
637 * 输 出: 无
638 * 注意事项: 无
639 ******************************************************************************************************************************************/
USBH_ErrorHandle(USBH_Info_t * phost,USBH_Status errType)640 void USBH_ErrorHandle(USBH_Info_t *phost, USBH_Status errType)
641 {
642 if(errType == USBH_UNRECOVERED_ERROR)
643 {
644 if(phost->usr_cb->UnrecoveredError)
645 phost->usr_cb->UnrecoveredError();
646
647 goto restart;
648 }
649 else if(errType == USBH_APPLY_DEINIT) // USB host restart requested from application layer
650 {
651 phost->usr_cb->Init();
652
653 goto restart;
654 }
655
656 return;
657
658 restart:
659 /* Re-Initialize Host for new Enumeration */
660 USBH_DeInit();
661 USBH_Info.usr_cb->DeInit();
662 USBH_Info.class_cb->DeInit(&USBH_Info);
663 }
664
665