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