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