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