1 /*!
2 \file usbd_core.c
3 \brief USB device mode core functions
4
5 \version 2020-08-04, V1.1.0, firmware for GD32VF103
6 */
7
8 /*
9 Copyright (c) 2020, GigaDevice Semiconductor Inc.
10
11 Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13
14 1. Redistributions of source code must retain the above copyright notice, this
15 list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 3. Neither the name of the copyright holder nor the names of its contributors
20 may be used to endorse or promote products derived from this software without
21 specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34
35 #include "usbd_core.h"
36 #include "usbd_enum.h"
37 #include "drv_usb_hw.h"
38
39 /* endpoint type */
40 const uint32_t ep_type[] = {
41 [USB_EP_ATTR_CTL] = (uint32_t)USB_EPTYPE_CTRL,
42 [USB_EP_ATTR_BULK] = (uint32_t)USB_EPTYPE_BULK,
43 [USB_EP_ATTR_INT] = (uint32_t)USB_EPTYPE_INTR,
44 [USB_EP_ATTR_ISO] = (uint32_t)USB_EPTYPE_ISOC
45 };
46
47 /*!
48 \brief initializes the USB device-mode stack and load the class driver
49 \param[in] udev: pointer to USB core instance
50 \param[in] core: USB core type
51 \param[in] desc: pointer to USB descriptor
52 \param[in] class_core: class driver
53 \param[out] none
54 \retval none
55 */
usbd_init(usb_core_driver * udev,usb_core_enum core,usb_desc * desc,usb_class_core * class_core)56 void usbd_init (usb_core_driver *udev, usb_core_enum core, usb_desc *desc, usb_class_core *class_core)
57 {
58 udev->dev.desc = desc;
59
60 /* class callbacks */
61 udev->dev.class_core = class_core;
62
63 /* create serial string */
64 serial_string_get(udev->dev.desc->strings[STR_IDX_SERIAL]);
65
66 /* configure USB capabilities */
67 (void)usb_basic_init (&udev->bp, &udev->regs, core);
68
69 usb_globalint_disable(&udev->regs);
70
71 /* initializes the USB core*/
72 (void)usb_core_init (udev->bp, &udev->regs);
73
74 /* set device disconnect */
75 usbd_disconnect (udev);
76
77 #ifndef USE_OTG_MODE
78 usb_curmode_set(&udev->regs, DEVICE_MODE);
79 #endif
80
81 /* initializes device mode */
82 (void)usb_devcore_init (udev);
83
84 usb_globalint_enable(&udev->regs);
85
86 /* set device connect */
87 usbd_connect (udev);
88
89 udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
90 }
91
92 /*!
93 \brief endpoint initialization
94 \param[in] udev: pointer to USB core instance
95 \param[in] ep_desc: pointer to endpoint descriptor
96 \param[out] none
97 \retval none
98 */
usbd_ep_setup(usb_core_driver * udev,const usb_desc_ep * ep_desc)99 uint32_t usbd_ep_setup (usb_core_driver *udev, const usb_desc_ep *ep_desc)
100 {
101 usb_transc *transc;
102
103 uint8_t ep_addr = ep_desc->bEndpointAddress;
104 uint16_t max_len = ep_desc->wMaxPacketSize;
105
106 /* set endpoint direction */
107 if (EP_DIR(ep_addr)) {
108 transc = &udev->dev.transc_in[EP_ID(ep_addr)];
109
110 transc->ep_addr.dir = 1U;
111 } else {
112 transc = &udev->dev.transc_out[ep_addr];
113
114 transc->ep_addr.dir = 0U;
115 }
116
117 transc->ep_addr.num = EP_ID(ep_addr);
118 transc->max_len = max_len;
119 transc->ep_type = (uint8_t)ep_type[ep_desc->bmAttributes & (uint8_t)USB_EPTYPE_MASK];
120
121 /* active USB endpoint function */
122 (void)usb_transc_active (udev, transc);
123
124 return 0U;
125 }
126
127 /*!
128 \brief configure the endpoint when it is disabled
129 \param[in] udev: pointer to USB core instance
130 \param[in] ep_addr: endpoint address
131 in this parameter:
132 bit0..bit6: endpoint number (0..7)
133 bit7: endpoint direction which can be IN(1) or OUT(0)
134 \param[out] none
135 \retval none
136 */
usbd_ep_clear(usb_core_driver * udev,uint8_t ep_addr)137 uint32_t usbd_ep_clear (usb_core_driver *udev, uint8_t ep_addr)
138 {
139 usb_transc *transc;
140
141 if (EP_DIR(ep_addr)) {
142 transc = &udev->dev.transc_in[EP_ID(ep_addr)];
143 } else {
144 transc = &udev->dev.transc_out[ep_addr];
145 }
146
147 /* deactivate USB endpoint function */
148 (void)usb_transc_deactivate (udev, transc);
149
150 return 0U;
151 }
152
153 /*!
154 \brief endpoint prepare to receive data
155 \param[in] udev: pointer to USB core instance
156 \param[in] ep_addr: endpoint address
157 in this parameter:
158 bit0..bit6: endpoint number (0..7)
159 bit7: endpoint direction which can be IN(1) or OUT(0)
160 \param[in] pbuf: user buffer address pointer
161 \param[in] len: buffer length
162 \param[out] none
163 \retval none
164 */
usbd_ep_recev(usb_core_driver * udev,uint8_t ep_addr,uint8_t * pbuf,uint32_t len)165 uint32_t usbd_ep_recev (usb_core_driver *udev, uint8_t ep_addr, uint8_t *pbuf, uint32_t len)
166 {
167 usb_transc *transc = &udev->dev.transc_out[EP_ID(ep_addr)];
168
169 /* setup the transfer */
170 transc->xfer_buf = pbuf;
171 transc->xfer_len = len;
172 transc->xfer_count = 0U;
173
174 if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
175 transc->dma_addr = (uint32_t)pbuf;
176 }
177
178 /* start the transfer */
179 (void)usb_transc_outxfer (udev, transc);
180
181 return 0U;
182 }
183
184 /*!
185 \brief endpoint prepare to transmit data
186 \param[in] udev: pointer to USB core instance
187 \param[in] ep_addr: endpoint address
188 in this parameter:
189 bit0..bit6: endpoint number (0..7)
190 bit7: endpoint direction which can be IN(1) or OUT(0)
191 \param[in] pbuf: transmit buffer address pointer
192 \param[in] len: buffer length
193 \param[out] none
194 \retval none
195 */
usbd_ep_send(usb_core_driver * udev,uint8_t ep_addr,uint8_t * pbuf,uint32_t len)196 uint32_t usbd_ep_send (usb_core_driver *udev, uint8_t ep_addr, uint8_t *pbuf, uint32_t len)
197 {
198 usb_transc *transc = &udev->dev.transc_in[EP_ID(ep_addr)];
199
200 /* setup the transfer */
201 transc->xfer_buf = pbuf;
202 transc->xfer_len = len;
203 transc->xfer_count = 0U;
204
205 if ((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
206 transc->dma_addr = (uint32_t)pbuf;
207 }
208
209 /* start the transfer */
210 (void)usb_transc_inxfer (udev, transc);
211
212 return 0U;
213 }
214
215 /*!
216 \brief set an endpoint to STALL status
217 \param[in] udev: pointer to USB core instance
218 \param[in] ep_addr: endpoint address
219 in this parameter:
220 bit0..bit6: endpoint number (0..7)
221 bit7: endpoint direction which can be IN(1) or OUT(0)
222 \param[out] none
223 \retval none
224 */
usbd_ep_stall(usb_core_driver * udev,uint8_t ep_addr)225 uint32_t usbd_ep_stall (usb_core_driver *udev, uint8_t ep_addr)
226 {
227 usb_transc *transc = NULL;
228
229 if (EP_DIR(ep_addr)) {
230 transc = &udev->dev.transc_in[EP_ID(ep_addr)];
231 } else {
232 transc = &udev->dev.transc_out[ep_addr];
233 }
234
235 transc->ep_stall = 1U;
236
237 (void)usb_transc_stall (udev, transc);
238
239 return (0U);
240 }
241
242 /*!
243 \brief clear endpoint STALLed status
244 \param[in] udev: pointer to usb core instance
245 \param[in] ep_addr: endpoint address
246 in this parameter:
247 bit0..bit6: endpoint number (0..7)
248 bit7: endpoint direction which can be IN(1) or OUT(0)
249 \param[out] none
250 \retval none
251 */
usbd_ep_stall_clear(usb_core_driver * udev,uint8_t ep_addr)252 uint32_t usbd_ep_stall_clear (usb_core_driver *udev, uint8_t ep_addr)
253 {
254 usb_transc *transc = NULL;
255
256 if (EP_DIR(ep_addr)) {
257 transc = &udev->dev.transc_in[EP_ID(ep_addr)];
258 } else {
259 transc = &udev->dev.transc_out[ep_addr];
260 }
261
262 transc->ep_stall = 0U;
263
264 (void)usb_transc_clrstall (udev, transc);
265
266 return (0U);
267 }
268
269 /*!
270 \brief flush the endpoint FIFOs
271 \param[in] udev: pointer to USB core instance
272 \param[in] ep_addr: endpoint address
273 in this parameter:
274 bit0..bit6: endpoint number (0..7)
275 bit7: endpoint direction which can be IN(1) or OUT(0)
276 \param[out] none
277 \retval none
278 */
usbd_fifo_flush(usb_core_driver * udev,uint8_t ep_addr)279 uint32_t usbd_fifo_flush (usb_core_driver *udev, uint8_t ep_addr)
280 {
281 if (EP_DIR(ep_addr)) {
282 (void)usb_txfifo_flush (&udev->regs, EP_ID(ep_addr));
283 } else {
284 (void)usb_rxfifo_flush (&udev->regs);
285 }
286
287 return (0U);
288 }
289
290 /*!
291 \brief device connect
292 \param[in] udev: pointer to USB device instance
293 \param[out] none
294 \retval none
295 */
usbd_connect(usb_core_driver * udev)296 void usbd_connect (usb_core_driver *udev)
297 {
298 #ifndef USE_OTG_MODE
299 /* connect device */
300 usb_dev_connect (udev);
301
302 usb_mdelay(3U);
303 #endif /* USE_OTG_MODE */
304 }
305
306 /*!
307 \brief device disconnect
308 \param[in] udev: pointer to USB device instance
309 \param[out] none
310 \retval none
311 */
usbd_disconnect(usb_core_driver * udev)312 void usbd_disconnect (usb_core_driver *udev)
313 {
314 #ifndef USE_OTG_MODE
315 /* disconnect device for 3ms */
316 usb_dev_disconnect (udev);
317
318 usb_mdelay(3U);
319 #endif /* USE_OTG_MODE */
320 }
321