1 /*!
2     \file    usbd_transc.c
3     \brief   USB transaction core functions
4 
5     \version 2020-08-04, V1.1.0, firmware for GD32VF103
6     \version 2020-12-11, V1.1.1, firmware for GD32VF103
7 */
8 
9 /*
10     Copyright (c) 2020, GigaDevice Semiconductor Inc.
11 
12     Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14 
15     1. Redistributions of source code must retain the above copyright notice, this
16        list of conditions and the following disclaimer.
17     2. Redistributions in binary form must reproduce the above copyright notice,
18        this list of conditions and the following disclaimer in the documentation
19        and/or other materials provided with the distribution.
20     3. Neither the name of the copyright holder nor the names of its contributors
21        may be used to endorse or promote products derived from this software without
22        specific prior written permission.
23 
24     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGE.
34 */
35 
36 #include "usbd_enum.h"
37 #include "usbd_transc.h"
38 
39 /*!
40     \brief      USB send data in the control transaction
41     \param[in]  udev: pointer to USB device instance
42     \param[out] none
43     \retval     USB device operation cur_status
44 */
usbd_ctl_send(usb_core_driver * udev)45 usbd_status usbd_ctl_send (usb_core_driver *udev)
46 {
47     usb_transc *transc = &udev->dev.transc_in[0];
48 
49     (void)usbd_ep_send(udev, 0U, transc->xfer_buf, transc->remain_len);
50 
51     if (transc->remain_len > transc->max_len) {
52         udev->dev.control.ctl_state = (uint8_t)USB_CTL_DATA_IN;
53     } else {
54         udev->dev.control.ctl_state = (uint8_t)USB_CTL_LAST_DATA_IN;
55     }
56 
57     return USBD_OK;
58 }
59 
60 /*!
61     \brief      USB receive data in control transaction
62     \param[in]  udev: pointer to USB device instance
63     \param[out] none
64     \retval     USB device operation cur_status
65 */
usbd_ctl_recev(usb_core_driver * udev)66 usbd_status usbd_ctl_recev (usb_core_driver *udev)
67 {
68     usb_transc *transc = &udev->dev.transc_out[0];
69 
70     (void)usbd_ep_recev (udev, 0U, transc->xfer_buf, transc->remain_len);
71 
72     if (transc->remain_len > transc->max_len) {
73         udev->dev.control.ctl_state = (uint8_t)USB_CTL_DATA_OUT;
74     } else {
75         udev->dev.control.ctl_state = (uint8_t)USB_CTL_LAST_DATA_OUT;
76     }
77 
78     return USBD_OK;
79 }
80 
81 /*!
82     \brief      USB send control transaction status
83     \param[in]  udev: pointer to USB device instance
84     \param[out] none
85     \retval     USB device operation cur_status
86 */
usbd_ctl_status_send(usb_core_driver * udev)87 usbd_status  usbd_ctl_status_send (usb_core_driver *udev)
88 {
89     udev->dev.control.ctl_state = (uint8_t)USB_CTL_STATUS_IN;
90 
91     (void)usbd_ep_send (udev, 0U, NULL, 0U);
92 
93     usb_ctlep_startout(udev);
94 
95     return USBD_OK;
96 }
97 
98 /*!
99     \brief      USB control receive status
100     \param[in]  udev: pointer to USB device instance
101     \param[out] none
102     \retval     USB device operation cur_status
103 */
usbd_ctl_status_recev(usb_core_driver * udev)104 usbd_status usbd_ctl_status_recev (usb_core_driver *udev)
105 {
106     udev->dev.control.ctl_state = (uint8_t)USB_CTL_STATUS_OUT;
107 
108     (void)usbd_ep_recev (udev, 0U, NULL, 0U);
109 
110     usb_ctlep_startout(udev);
111 
112     return USBD_OK;
113 }
114 
115 /*!
116     \brief      USB setup stage processing
117     \param[in]  udev: pointer to USB device instance
118     \param[out] none
119     \retval     USB device operation cur_status
120 */
usbd_setup_transc(usb_core_driver * udev)121 uint8_t usbd_setup_transc (usb_core_driver *udev)
122 {
123     usb_reqsta reqstat = REQ_NOTSUPP;
124 
125     usb_req req = udev->dev.control.req;
126 
127     switch (req.bmRequestType & USB_REQTYPE_MASK) {
128     /* standard device request */
129     case USB_REQTYPE_STRD:
130         reqstat = usbd_standard_request (udev, &req);
131         break;
132 
133     /* device class request */
134     case USB_REQTYPE_CLASS:
135         reqstat = usbd_class_request (udev, &req);
136         break;
137 
138     /* vendor defined request */
139     case USB_REQTYPE_VENDOR:
140         reqstat = usbd_vendor_request (udev, &req);
141         break;
142 
143     default:
144         break;
145     }
146 
147     if (REQ_SUPP == reqstat) {
148         if (0U == req.wLength) {
149             (void)usbd_ctl_status_send (udev);
150         } else {
151             if (req.bmRequestType & 0x80U) {
152                 (void)usbd_ctl_send (udev);
153             } else {
154                 (void)usbd_ctl_recev (udev);
155             }
156         }
157     } else {
158         usbd_enum_error (udev, &req);
159     }
160 
161     return (uint8_t)USBD_OK;
162 }
163 
164 /*!
165     \brief      data out stage processing
166     \param[in]  udev: pointer to USB device instance
167     \param[in]  ep_num: endpoint identifier(0..7)
168     \param[out] none
169     \retval     USB device operation cur_status
170 */
usbd_out_transc(usb_core_driver * udev,uint8_t ep_num)171 uint8_t usbd_out_transc (usb_core_driver *udev, uint8_t ep_num)
172 {
173     if (0U == ep_num) {
174         usb_transc *transc = &udev->dev.transc_out[0];
175 
176         switch (udev->dev.control.ctl_state) {
177         case USB_CTL_DATA_OUT:
178             /* update transfer length */
179             transc->remain_len -= transc->max_len;
180 
181             if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
182                 transc->xfer_buf += transc->max_len;
183             }
184 
185             (void)usbd_ctl_recev (udev);
186             break;
187 
188         case USB_CTL_LAST_DATA_OUT:
189             if (udev->dev.cur_status == (uint8_t)USBD_CONFIGURED) {
190                 if (udev->dev.class_core->ctlx_out != NULL) {
191                     (void)udev->dev.class_core->ctlx_out (udev);
192                 }
193             }
194 
195             transc->remain_len = 0U;
196 
197             (void)usbd_ctl_status_send (udev);
198             break;
199 
200         default:
201             break;
202         }
203     } else if ((udev->dev.class_core->data_out != NULL) && (udev->dev.cur_status == (uint8_t)USBD_CONFIGURED)) {
204         (void)udev->dev.class_core->data_out (udev, ep_num);
205     } else {
206         /* no operation */
207     }
208 
209     return (uint8_t)USBD_OK;
210 }
211 
212 /*!
213     \brief      data in stage processing
214     \param[in]  udev: pointer to USB device instance
215     \param[in]  ep_num: endpoint identifier(0..7)
216     \param[out] none
217     \retval     USB device operation cur_status
218 */
usbd_in_transc(usb_core_driver * udev,uint8_t ep_num)219 uint8_t usbd_in_transc (usb_core_driver *udev, uint8_t ep_num)
220 {
221     if (0U == ep_num) {
222         usb_transc *transc = &udev->dev.transc_in[0];
223 
224         switch (udev->dev.control.ctl_state) {
225         case USB_CTL_DATA_IN:
226             /* update transfer length */
227             transc->remain_len -= transc->max_len;
228 
229             if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
230                 transc->xfer_buf += transc->max_len;
231             }
232 
233             (void)usbd_ctl_send (udev);
234             break;
235 
236         case USB_CTL_LAST_DATA_IN:
237             /* last packet is MPS multiple, so send ZLP packet */
238             if (udev->dev.control.ctl_zlp) {
239                 (void)usbd_ep_send (udev, 0U, NULL, 0U);
240 
241                 udev->dev.control.ctl_zlp = 0U;
242             } else {
243                 if (udev->dev.cur_status == (uint8_t)USBD_CONFIGURED) {
244                     if (udev->dev.class_core->ctlx_in != NULL) {
245                         (void)udev->dev.class_core->ctlx_in (udev);
246                     }
247                 }
248 
249                 transc->remain_len = 0U;
250 
251                 (void)usbd_ctl_status_recev (udev);
252             }
253             break;
254 
255         default:
256             break;
257         }
258     } else {
259         if ((udev->dev.cur_status == (uint8_t)USBD_CONFIGURED) && (udev->dev.class_core->data_in != NULL)) {
260             (void)udev->dev.class_core->data_in (udev, ep_num);
261         }
262     }
263 
264     return (uint8_t)USBD_OK;
265 }
266