1 /*!
2     \file    usbd_msc_bbb.c
3     \brief   USB BBB(Bulk/Bulk/Bulk) protocol core functions
4     \note    BBB means Bulk-only transport protocol for USB MSC
5 
6     \version 2020-08-04, V1.1.0, 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_msc_bbb.h"
38 
39 /* local function prototypes ('static') */
40 static void msc_bbb_cbw_decode (usb_core_driver *pudev);
41 static void msc_bbb_data_send (usb_core_driver *pudev, uint8_t *pbuf, uint32_t Len);
42 static void msc_bbb_abort (usb_core_driver *pudev);
43 
44 /*!
45     \brief      initialize the bbb process
46     \param[in]  pudev: pointer to USB device instance
47     \param[out] none
48     \retval     none
49 */
msc_bbb_init(usb_core_driver * pudev)50 void msc_bbb_init (usb_core_driver *pudev)
51 {
52     uint8_t lun_num;
53 
54     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
55 
56     msc->bbb_state = BBB_IDLE;
57     msc->bbb_status = BBB_STATUS_NORMAL;
58 
59     /* init the storage logic unit */
60     for(lun_num = 0U; lun_num < MEM_LUN_NUM; lun_num++) {
61         usbd_mem_fops->mem_init(lun_num);
62     }
63 
64     /* flush the Rx FIFO */
65     usbd_fifo_flush (pudev, MSC_OUT_EP);
66 
67     /* flush the Tx FIFO */
68     usbd_fifo_flush (pudev, MSC_IN_EP);
69 
70     /* prepare endpoint to receive the first BBB CBW */
71     usbd_ep_recev (pudev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
72 }
73 
74 /*!
75     \brief      reset the BBB machine
76     \param[in]  pudev: pointer to USB device instance
77     \param[out] none
78     \retval     none
79 */
msc_bbb_reset(usb_core_driver * pudev)80 void msc_bbb_reset (usb_core_driver *pudev)
81 {
82     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
83 
84     msc->bbb_state = BBB_IDLE;
85     msc->bbb_status = BBB_STATUS_RECOVERY;
86 
87     /* prepare endpoint to receive the first BBB command */
88     usbd_ep_recev (pudev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
89 }
90 
91 /*!
92     \brief      de-initialize the BBB machine
93     \param[in]  pudev: pointer to USB device instance
94     \param[out] none
95     \retval     none
96 */
msc_bbb_deinit(usb_core_driver * pudev)97 void msc_bbb_deinit (usb_core_driver *pudev)
98 {
99     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
100 
101     msc->bbb_state = BBB_IDLE;
102 }
103 
104 /*!
105     \brief      handle BBB data IN stage
106     \param[in]  pudev: pointer to USB device instance
107     \param[in]  ep_num: endpoint number
108     \param[out] none
109     \retval     none
110 */
msc_bbb_data_in(usb_core_driver * pudev,uint8_t ep_num)111 void msc_bbb_data_in (usb_core_driver *pudev, uint8_t ep_num)
112 {
113     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
114 
115     switch (msc->bbb_state) {
116     case BBB_DATA_IN:
117         if (scsi_process_cmd (pudev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
118             msc_bbb_csw_send (pudev, CSW_CMD_FAILED);
119         }
120         break;
121 
122     case BBB_SEND_DATA:
123     case BBB_LAST_DATA_IN:
124         msc_bbb_csw_send (pudev, CSW_CMD_PASSED);
125         break;
126 
127     default:
128         break;
129     }
130 }
131 
132 /*!
133     \brief      handle BBB data OUT stage
134     \param[in]  pudev: pointer to USB device instance
135     \param[in]  ep_num: endpoint number
136     \param[out] none
137     \retval     none
138 */
msc_bbb_data_out(usb_core_driver * pudev,uint8_t ep_num)139 void msc_bbb_data_out (usb_core_driver *pudev, uint8_t ep_num)
140 {
141     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
142 
143     switch (msc->bbb_state) {
144     case BBB_IDLE:
145         msc_bbb_cbw_decode (pudev);
146         break;
147 
148     case BBB_DATA_OUT:
149         if (scsi_process_cmd (pudev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
150             msc_bbb_csw_send (pudev, CSW_CMD_FAILED);
151         }
152         break;
153 
154     default:
155         break;
156     }
157 }
158 
159 /*!
160     \brief      send the CSW(command status wrapper)
161     \param[in]  pudev: pointer to USB device instance
162     \param[in]  csw_status: CSW status
163     \param[out] none
164     \retval     none
165 */
msc_bbb_csw_send(usb_core_driver * pudev,uint8_t csw_status)166 void msc_bbb_csw_send (usb_core_driver *pudev, uint8_t csw_status)
167 {
168     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
169 
170     msc->bbb_csw.dCSWSignature = BBB_CSW_SIGNATURE;
171     msc->bbb_csw.bCSWStatus = csw_status;
172     msc->bbb_state = BBB_IDLE;
173 
174     usbd_ep_send (pudev, MSC_IN_EP, (uint8_t *)&msc->bbb_csw, BBB_CSW_LENGTH);
175 
176     /* prapare endpoint to receive next command */
177     usbd_ep_recev (pudev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
178 }
179 
180 /*!
181     \brief      complete the clear feature request
182     \param[in]  pudev: pointer to USB device instance
183     \param[in]  ep_num: endpoint number
184     \param[out] none
185     \retval     none
186 */
msc_bbb_clrfeature(usb_core_driver * pudev,uint8_t ep_num)187 void msc_bbb_clrfeature (usb_core_driver *pudev, uint8_t ep_num)
188 {
189     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
190 
191     if (msc->bbb_status == BBB_STATUS_ERROR)/* bad CBW signature */ {
192         usbd_ep_stall(pudev, MSC_IN_EP);
193 
194         msc->bbb_status = BBB_STATUS_NORMAL;
195     } else if(((ep_num & 0x80U) == 0x80U) && (msc->bbb_status != BBB_STATUS_RECOVERY)) {
196         msc_bbb_csw_send (pudev, CSW_CMD_FAILED);
197     } else {
198 
199     }
200 }
201 
202 /*!
203     \brief      decode the CBW command and set the BBB state machine accordingly
204     \param[in]  pudev: pointer to USB device instance
205     \param[out] none
206     \retval     none
207 */
msc_bbb_cbw_decode(usb_core_driver * pudev)208 static void msc_bbb_cbw_decode (usb_core_driver *pudev)
209 {
210     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
211 
212     msc->bbb_csw.dCSWTag = msc->bbb_cbw.dCBWTag;
213     msc->bbb_csw.dCSWDataResidue = msc->bbb_cbw.dCBWDataTransferLength;
214 
215     if ((BBB_CBW_LENGTH != usbd_rxcount_get (pudev, MSC_OUT_EP)) ||
216             (BBB_CBW_SIGNATURE != msc->bbb_cbw.dCBWSignature)||
217                 (msc->bbb_cbw.bCBWLUN > 1U) ||
218                     (msc->bbb_cbw.bCBWCBLength < 1U) ||
219                         (msc->bbb_cbw.bCBWCBLength > 16U)) {
220         /* illegal command handler */
221         scsi_sense_code (pudev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
222 
223         msc->bbb_status = BBB_STATUS_ERROR;
224 
225         msc_bbb_abort (pudev);
226     } else {
227         if (scsi_process_cmd (pudev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
228             msc_bbb_abort (pudev);
229         } else if ((BBB_DATA_IN != msc->bbb_state) &&
230                     (BBB_DATA_OUT != msc->bbb_state) &&
231                       (BBB_LAST_DATA_IN != msc->bbb_state)) { /* burst xfer handled internally */
232             if (msc->bbb_datalen > 0U) {
233                 msc_bbb_data_send (pudev, msc->bbb_data, msc->bbb_datalen);
234             } else if (0U == msc->bbb_datalen) {
235                 msc_bbb_csw_send (pudev, CSW_CMD_PASSED);
236             } else {
237 
238             }
239         } else {
240 
241         }
242     }
243 }
244 
245 /*!
246     \brief      send the requested data
247     \param[in]  pudev: pointer to USB device instance
248     \param[in]  buf: pointer to data buffer
249     \param[in]  len: data length
250     \param[out] none
251     \retval     none
252 */
msc_bbb_data_send(usb_core_driver * pudev,uint8_t * buf,uint32_t len)253 static void msc_bbb_data_send (usb_core_driver *pudev, uint8_t *buf, uint32_t len)
254 {
255     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
256 
257     len = USB_MIN (msc->bbb_cbw.dCBWDataTransferLength, len);
258 
259     msc->bbb_csw.dCSWDataResidue -= len;
260     msc->bbb_csw.bCSWStatus = CSW_CMD_PASSED;
261     msc->bbb_state = BBB_SEND_DATA;
262 
263     usbd_ep_send (pudev, MSC_IN_EP, buf, len);
264 }
265 
266 /*!
267     \brief      abort the current transfer
268     \param[in]  pudev: pointer to USB device instance
269     \param[out] none
270     \retval     none
271 */
msc_bbb_abort(usb_core_driver * pudev)272 static void msc_bbb_abort (usb_core_driver *pudev)
273 {
274     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
275 
276     if ((0U == msc->bbb_cbw.bmCBWFlags) &&
277          (0U != msc->bbb_cbw.dCBWDataTransferLength) &&
278           (BBB_STATUS_NORMAL == msc->bbb_status)) {
279         usbd_ep_stall(pudev, MSC_OUT_EP);
280     }
281 
282     usbd_ep_stall(pudev, MSC_IN_EP);
283 
284     if (msc->bbb_status == BBB_STATUS_ERROR) {
285         usbd_ep_recev (pudev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
286     }
287 }
288