1 /*!
2 * @file usbd_msv_bot.c
3 *
4 * @brief MSC BOT protocol core functions
5 *
6 * @version V1.0.0
7 *
8 * @date 2021-12-25
9 *
10 * @attention
11 *
12 * Copyright (C) 2020-2022 Geehy Semiconductor
13 *
14 * You may not use this file except in compliance with the
15 * GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
16 *
17 * The program is only for reference, which is distributed in the hope
18 * that it will be useful and instructional for customers to develop
19 * their software. Unless required by applicable law or agreed to in
20 * writing, the program is distributed on an "AS IS" BASIS, WITHOUT
21 * ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
23 * and limitations under the License.
24 */
25
26 /* Includes */
27 #include "usbd_msc_bot.h"
28 #include "usbd_core.h"
29 #include "usbd_storage_disk.h"
30 #include "usbd_msc_scsi.h"
31
32 /** @addtogroup USB_Driver_Library USB Driver Library
33 @{
34 */
35
36 /** @addtogroup Core_Device Core Device
37 @{
38 */
39
40 /** @addtogroup Class
41 @{
42 */
43
44 /** @addtogroup MSC_BOT
45 @{
46 */
47
48 /** @defgroup MSC_BOT_Macros Macros
49 @{
50 */
51
52 /**@} end of group MSC_BOT_Macros */
53
54 /** @defgroup MSC_BOT_Enumerations Enumerations
55 @{
56 */
57
58 /**@} end of group MSC_BOT_Enumerations */
59
60 /** @defgroup MSC_BOT_Structures Structures
61 @{
62 */
63
64 /**@} end of group MSC_BOT_Structures */
65
66 /** @defgroup MSC_BOT_Variables Variables
67 @{
68 */
69
70 BOT_Info_T g_BOTInfo;
71
72 /**@} end of group MSC_BOT_Variables */
73
74 /** @defgroup MSC_BOT_Functions Functions
75 @{
76 */
77
78 static void USBD_MSC_BOT_DecodeCBW(void);
79 static void USBD_MSC_BOT_TxData(uint8_t* txBuf, uint16_t len);
80 static void USBD_MSC_BOT_Stall(void);
81
82 /*!
83 * @brief BOT Process Reset.
84 *
85 * @param None
86 *
87 * @retval None
88 */
USBD_MSC_BOT_Reset(void)89 void USBD_MSC_BOT_Reset(void)
90 {
91 g_BOTInfo.state = BOT_STATE_IDLE;
92 g_BOTInfo.status = BOT_STATUS_RECOVERY;
93
94 USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t*)&g_BOTInfo.CBW, MSC_BOT_CBW_LENGTH);
95 }
96
97 /*!
98 * @brief BOT Process initialization.
99 *
100 * @param None
101 *
102 * @retval None
103 */
USBD_MSC_BOT_Init(void)104 void USBD_MSC_BOT_Init(void)
105 {
106 g_BOTInfo.state = BOT_STATE_IDLE;
107 g_BOTInfo.status = BOT_STATUS_NORMAL;
108
109 g_storageCallBack.Init(0);
110
111 USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t*)&g_BOTInfo.CBW, MSC_BOT_CBW_LENGTH);
112 }
113
114 /*!
115 * @brief Bulk OUT data handler.
116 *
117 * @param ep : OUT endpoint
118 *
119 * @retval None
120 */
USBD_MSC_BOT_OutData(uint8_t ep)121 void USBD_MSC_BOT_OutData(uint8_t ep)
122 {
123 if (g_BOTInfo.state == BOT_STATE_IDLE)
124 {
125 USBD_MSC_BOT_DecodeCBW();
126 }
127 else if (g_BOTInfo.state == BOT_STATE_DATA_OUT)
128 {
129 if (SCSI_CmdHandler(g_BOTInfo.CBW.bLUN, g_BOTInfo.CBW.CB) != SCSI_OK)
130 {
131 USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_FAIL);
132 }
133 }
134 }
135
136 /*!
137 * @brief Bulk IN data handler.
138 *
139 * @param ep : IN endpoint
140 *
141 * @retval None
142 */
USBD_MSC_BOT_InData(uint8_t ep)143 void USBD_MSC_BOT_InData(uint8_t ep)
144 {
145 if (g_BOTInfo.state == BOT_STATE_DATA_IN)
146 {
147 if (SCSI_CmdHandler(g_BOTInfo.CBW.bLUN, g_BOTInfo.CBW.CB) != SCSI_OK)
148 {
149 USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_FAIL);
150 }
151 }
152 else if ((g_BOTInfo.state == BOT_STATE_SEND_DATA) || \
153 (g_BOTInfo.state == BOT_STATE_LAST_DATA_IN))
154 {
155 USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_OK);
156 }
157 }
158
159 /*!
160 * @brief Decode CBW.
161 *
162 * @param None
163 *
164 * @retval None
165 */
USBD_MSC_BOT_DecodeCBW(void)166 static void USBD_MSC_BOT_DecodeCBW(void)
167 {
168 uint32_t xferCnt = g_usbDev.outBuf[MSC_OUT_EP & 0x7f].xferCnt;
169
170 g_BOTInfo.CSW.dTag = g_BOTInfo.CBW.dTag;
171 g_BOTInfo.CSW.dDataResidue = g_BOTInfo.CBW.dDataXferLen;
172
173 if ((xferCnt != MSC_BOT_CBW_LENGTH) || \
174 (g_BOTInfo.CBW.dSignature != MSC_BOT_CBW_SIGNATURE) || \
175 (g_BOTInfo.CBW.bLUN > 1) || (g_BOTInfo.CBW.bCBLen < 1) || \
176 (g_BOTInfo.CBW.bCBLen > 16))
177 {
178 SCSI_PutSenseCode(g_BOTInfo.CBW.bLUN, SCSI_SKEY_ILLEGAL_REQUEST,
179 SCSI_ASC_INVALID_CDB, 0);
180
181 g_BOTInfo.status = BOT_STATUS_ERROR;
182 }
183 else
184 {
185 if (SCSI_CmdHandler(g_BOTInfo.CBW.bLUN, g_BOTInfo.CBW.CB) != SCSI_OK)
186 {
187 USBD_MSC_BOT_Stall();
188 }
189 else if ((g_BOTInfo.state == BOT_STATE_IDLE) || \
190 (g_BOTInfo.state == BOT_STATE_SEND_DATA))
191 {
192 if (g_BOTInfo.dataLen)
193 {
194 USBD_MSC_BOT_TxData(g_BOTInfo.data, g_BOTInfo.dataLen);
195 }
196 else
197 {
198 USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_OK);
199 }
200 }
201 }
202 }
203
204 /*!
205 * @brief MSC send data.
206 *
207 * @param txBuf : buffer to send
208 *
209 * @param len : buffer length
210 *
211 * @retval None
212 */
USBD_MSC_BOT_TxData(uint8_t * txBuf,uint16_t len)213 static void USBD_MSC_BOT_TxData(uint8_t* txBuf, uint16_t len)
214 {
215 len = USB_MIN(len, g_BOTInfo.CBW.dDataXferLen);
216
217 g_BOTInfo.CSW.dDataResidue -= len;
218 g_BOTInfo.CSW.bStatus = BOT_CSW_STATUS_CMD_OK;
219 g_BOTInfo.state = BOT_STATE_SEND_DATA;
220
221 USBD_TxData(MSC_IN_EP & 0x7f, txBuf, len);
222 }
223
224 /*!
225 * @brief Send CSW.
226 *
227 * @param cswStatus : status of CSW
228 *
229 * @retval None
230 */
USBD_MSC_BOT_TxCSW(uint8_t cswStatus)231 void USBD_MSC_BOT_TxCSW(uint8_t cswStatus)
232 {
233 g_BOTInfo.CSW.dSignature = MSC_BOT_CSW_SIGNATURE;
234 g_BOTInfo.CSW.bStatus = cswStatus;
235 g_BOTInfo.state = BOT_STATE_IDLE;
236
237 USBD_TxData(MSC_IN_EP & 0x7f, (uint8_t*)&g_BOTInfo.CSW,
238 MSC_BOT_CSW_LENGTH);
239
240 USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t*)&g_BOTInfo.CBW,
241 MSC_BOT_CBW_LENGTH);
242 }
243
244 /*!
245 * @brief handler clearFeature in standard request.
246 *
247 * @param None
248 *
249 * @retval None
250 */
USBD_MSV_BOT_ClearFeatureHandler(void)251 void USBD_MSV_BOT_ClearFeatureHandler(void)
252 {
253 if (g_BOTInfo.status == BOT_STATUS_ERROR)
254 {
255 USBD_SetEPTxStatus(MSC_IN_EP & 0x7f, USBD_EP_STATUS_NAK);
256 g_BOTInfo.status = BOT_STATUS_NORMAL;
257 }
258 else if (((g_usbDev.reqData.byte.wIndex[0] & 0x80) == 0x80) && \
259 g_BOTInfo.status != BOT_STATUS_RECOVERY)
260 {
261 USBD_MSC_BOT_TxCSW(BOT_CSW_STATUS_CMD_FAIL);
262 }
263 }
264
265 /*!
266 * @brief Stall MSC.
267 *
268 * @param None
269 *
270 * @retval None
271 */
USBD_MSC_BOT_Stall(void)272 static void USBD_MSC_BOT_Stall(void)
273 {
274 if ((g_BOTInfo.CBW.bmFlags == 0) && (g_BOTInfo.CBW.dDataXferLen != 0) && \
275 (g_BOTInfo.status == BOT_STATUS_NORMAL))
276 {
277 USBD_SetEPRxStatus(MSC_OUT_EP & 0x7f, USBD_EP_STATUS_STALL);
278 }
279
280 USBD_SetEPTxStatus(MSC_IN_EP & 0x7f, USBD_EP_STATUS_STALL);
281
282 if (g_BOTInfo.status == BOT_STATUS_ERROR)
283 {
284 USBD_RxData(MSC_OUT_EP & 0x7f, (uint8_t*)&g_BOTInfo.CBW, MSC_BOT_CBW_LENGTH);
285 }
286 }
287
288 /**@} end of group MSC_BOT_Functions */
289 /**@} end of group MSC_BOT_ */
290 /**@} end of group Class */
291 /**@} end of group Core_Device */
292 /**@} end of group USB_Driver_Library */
293