1 /******************************************************************************* 2 * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. 3 * 4 * SPDX-License-Identifier: MIT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * PolarFire SoC MSS USB Host logical driver layer Implementation. 25 * 26 * PolarFire SoC MSS USB Driver Stack 27 * USB Logical Layer (USB-LL) 28 * USBD-MSC class driver. 29 * 30 * USBD-MSC class driver public API. 31 * 32 */ 33 34 /*=========================================================================*//** 35 @mainpage PolarFire SoC MSS USB driver (USBD-MSC) 36 37 ============================================================================== 38 Introduction 39 ============================================================================== 40 The Mass Storage Class device driver implements the USB MSC device as specified 41 by the USB-IF. This driver enables easy implementation of mass storage drive 42 functionality on the Smarfusion2 devices. 43 44 This driver implements the MSC class using Bulk Only transport (BOT). 45 One BULK IN and one BULK OUT endpoints are used to implement BOT. This driver 46 is independent of the storage medium used for storing the data and the number 47 of Logical Units (LUN) it supports. 48 49 This driver uses the USBD-Class driver template to implement the USB MSC 50 device. 51 52 This driver passes the USB-IF USB2.0 compliance test for high speed MSC class 53 device. 54 55 ============================================================================== 56 Theory of Operation 57 ============================================================================== 58 The following steps are involved in the operation of the USBD-MSC driver: 59 - Configuration 60 - Initialization 61 - Enumeration 62 - Class Specific requests 63 - Data transfer 64 65 -------------------------------- 66 Configuration 67 -------------------------------- 68 To use this driver, the MSS USB driver must first be configured in the USB 69 device mode using the MSS_USB_PERIPHERAL_MODE. No other configuration is 70 necessary. 71 72 -------------------------------- 73 Initialization 74 -------------------------------- 75 The MSC class driver must be initialized using the MSS_USBD_MSC_init() function. 76 Once initialized, this driver gets configured by the USBD driver during the 77 enumeration process. The Call-back function usbd_msc_init_cb() is 78 implemented by this driver which will be called by the USBD driver when the 79 host configures the this device. The usbd_msc_get_descriptor_cb() function 80 is implemented to provide the class specific descriptor table to the USBD driver. 81 82 -------------------------------- 83 Class Specific requests 84 -------------------------------- 85 This driver defines descriptor table which contains a configuration descriptor, 86 an interface descriptor, two endpoint descriptors for successful enumeration 87 as a MSC class device. 88 89 Note: For successful enumeration, the device specific descriptors must also be 90 provided by the application using the MSS_USBD_set_desc_cb_handler() 91 function to the USBD Driver. Since the device descriptor, string descriptors etc. 92 are not class specific, they are not part of the MSC class driver. 93 94 Class Specific requests 95 The usbd_msc_process_request_cb() call-back function is implemented by 96 this driver which processes the MSC class specific requests. This driver may 97 not have all the information related to the storage medium e.g. storage 98 capacity etc. To process such requests; they are passed on to the application 99 by calling appropriate call-back functions. The application must implement 100 these call-back functions for the driver to successfully respond to the host 101 requests. Refer data structures section for more information. 102 103 -------------------------------- 104 Data transfer 105 -------------------------------- 106 The MSC class driver performs the data transfers using one BULK IN endpoint 107 and one BULK OUT endpoint. The data transfers follow the BoT protocol. This 108 driver implements the usbd_msc_tx_complete_cb() and the usbd_msc_tx_complete_cb() 109 function to get the information on data transfer events on the USB bus which 110 are called by the USBD Driver. 111 112 The BoT read/write operations happen on logical units of fixed block sizes. 113 This driver translates these read write operation into memory read/write 114 operation and calls the call-back function where application can perform the 115 memory read/write operations. This method makes the MSC class driver 116 independent of the storage medium being used. The call-back function elements 117 media_acquire_write_buf, media_write_ready and media_read (as part of structure 118 of type mss_usbd_msc_media_t) must be implemented by the application. 119 120 *//*==========================================================================*/ 121 122 #ifndef __MSS_USB_DEVICE_MSD_H_ 123 #define __MSS_USB_DEVICE_MSD_H_ 124 125 #include <stdint.h> 126 #include "mss_usb_device.h" 127 128 #ifdef __cplusplus 129 extern "C" { 130 #endif 131 132 #ifdef MSS_USB_DEVICE_ENABLED 133 /******************************************************************************* 134 * User Descriptor lengths 135 */ 136 137 /* Full configuration descriptor length*/ 138 #define FULL_CONFIG_DESCR_LENGTH (USB_STD_CONFIG_DESCR_LEN + \ 139 USB_STD_INTERFACE_DESCR_LEN + \ 140 USB_STD_ENDPOINT_DESCR_LEN + \ 141 USB_STD_ENDPOINT_DESCR_LEN ) 142 143 /***************************************************************************//** 144 Exported Types from USBD-MSC class driver 145 */ 146 /***************************************************************************//** 147 mss_usbd_msc_state_t 148 The mss_usbd_msc_state_t provides a type to identify the current state of the 149 MSC class driver. 150 USBD_MSC_NOT_CONFIGURED – The USB MSC class driver is not configured and it 151 cannot perform the data transfers. 152 USBD_MSC_CONFIGURED - The USB MSC class driver is configured by the host 153 and it can perform the data transfers. 154 155 Note: The application must not access the flash media (on board SPI Flash 156 in this case) while the MSC class driver is in USBD_MSC_CONFIGURED state 157 because the USB host might be performing read/write operation on the flash 158 media. If the application also attempts to access the flash media at the same 159 time, the data might get corrupted and the host will get misleading information 160 from the flash media. 161 */ 162 typedef enum mss_usbd_msc_state { 163 USBD_MSC_NOT_CONFIGURED, 164 USBD_MSC_CONFIGURED, 165 }mss_usbd_msc_state_t; 166 167 /***************************************************************************//** 168 mss_usbd_msc_media_t 169 The mss_usbd_msc_media_t provides the prototype for all the call-back 170 functions which must be implemented by the user application. The user 171 application must define and initialize a structure of this type and provide 172 the address of that structure as parameter to the MSS_USBD_MSC_init() function. 173 174 media_init 175 The function pointed by the media_init function pointer will be called to 176 indicate that the MSC driver is configured by the USB host. The application 177 can use this function to prepare itself for data exchange with the host. 178 This driver cannot perform data transfers unless it is configured by the USB 179 host to do so. 180 181 media_get_capacity 182 The function pointed to by the media_get_capacity function pointer is called 183 to find out the capacity of the LUN on the storage medium. The parameter lun 184 indicates the logical unit on which the current operation is being performed. 185 The application must return address of the last logical block and the size of 186 the logical block in the parameters last_block_lba and block_size respectively. 187 188 media_is_ready 189 The function pointed by the media_is_ready function pointer is called to find 190 out if the LUN on the media is ready for the data transfers. The parameter lun 191 indicates the logical unit on which the current operation is being performed. 192 193 media_is_write_protected 194 The function pointed by the media_is_write_protected function pointer is called 195 to find out if the LUN on the media is write-protected, before a write operation 196 can be performed on the LUN. The parameter lun indicates the logical unit on 197 which the current operation is being performed. 198 199 media_read 200 The function pointed by the media_read function pointer is called when the 201 host wants to read the data from the storage medium. The application must 202 provide a buffer and its length which can be sent to the host. The parameter 203 lun indicates the logical unit on which the current operation is being performed. 204 The blk_addr parameter provides the logical block address and the len 205 parameter provides the number of bytes to be read. The application must provide 206 a buffer in return parameter buf and the length of this buffer must be provided 207 as the return value of this function. 208 209 media_acquire_write_buffer 210 The function pointed by the msd_media_acquire_write_buffer function pointer is 211 called when the host wants to write data on to the storage medium. The 212 application must provide a buffer where the data sent by the host can be stored. 213 The parameter lun indicates the logical unit on which the current operation is 214 being performed. The blk_addr parameter provides the logical block address 215 where the data is to be written. The application must provide a buffer as a 216 return value of this function and the length of the buffer must be provided 217 in the return parameter length. 218 219 media_write_ready 220 The function pointed by the media_write_ready function pointer is called when 221 the data to be written is received from the host and is ready to be written on 222 the storage medium. The data is stored in the previously provided write buffer 223 using media_acquire_write_buffer. The parameter lun indicates the logical unit 224 on which the current operation is being performed. The blk_addr parameter 225 provides the logical block address where data is to be written. The parameter 226 length provides the number of bytes to be written. 227 228 media_get_max_lun 229 The function pointed by the media_get_max_lun function pointer is called to 230 find out the maximum number of logical units supported by the application or 231 the storage medium. 232 233 media_inquiry 234 The function pointed by the media_inquiry function pointer is called to get 235 the response for the INQUIRY request from the MSC class host. The parameter 236 lun indicates the logical unit on which the current operation is being performed. 237 The application must provide a buffer as a return value of this function and 238 must provide the length of this buffer in the parameter length. 239 240 media_release 241 The function pointed by the media_inquiry function pointer is called to 242 indicate that the either the MSC class device has been un-configured or is 243 disconnected from the host. The MSC class device is un-configured when it 244 receives SET_CONFIGURATION request from USB host with a cfgidx = 0. This value 245 is passed as a parameter. In case when the disconnect event is detected by the 246 USBD driver a value of cfgidx = 0xFF is passed. The application can use this 247 call-back function and its parameter to take appropriate action as required. 248 */ 249 250 typedef struct mss_usbd_msc_media { 251 uint8_t (*media_init)(uint8_t lun); 252 uint8_t (*media_get_capacity)(uint8_t lun, 253 uint32_t *last_block_lba, 254 uint32_t *block_size); 255 256 uint8_t (*media_is_ready)(uint8_t lun); 257 uint8_t (*media_is_write_protected)(uint8_t lun); 258 uint32_t(*media_read)(uint8_t lun, 259 uint8_t **buf, 260 uint32_t blk_addr, 261 uint32_t len); 262 263 uint8_t*(*media_acquire_write_buf)(uint8_t lun, 264 uint32_t blk_addr, 265 uint32_t *len); 266 267 uint32_t(*media_write_ready)(uint8_t lun, 268 uint32_t blk_addr, 269 uint32_t len); 270 271 uint8_t (*media_get_max_lun)(void); 272 uint8_t*(*media_inquiry)(uint8_t lun, uint32_t *len); 273 uint8_t (*media_release)(uint8_t cfgidx); 274 275 } mss_usbd_msc_media_t; 276 277 /***************************************************************************//** 278 Types Internal to the USBD-MSC class driver 279 */ 280 typedef enum mss_usbd_msc_bot_events { 281 BOT_EVENT_IDLE, 282 BOT_EVENT_TX, 283 BOT_EVENT_RX, 284 BOT_EVENT_TX_ERROR, 285 BOT_EVENT_RX_ERROR 286 } mss_usbd_msc_bot_events_t; 287 288 typedef enum mss_usbd_msc_csw_status { 289 SCSI_COMMAND_PASS, 290 SCSI_COMMAND_FAIL, 291 SCSI_COMMAND_PHASE_ERR, 292 SCSI_COMMAND_LESSDATAPASS, 293 } mss_usbd_msc_csw_status_t; 294 295 typedef enum mss_usbd_msc_bot_state { 296 BOT_IDLE, 297 BOT_DATA_RX, 298 BOT_DATA_TX, 299 BOT_SEND_STATUS, 300 BOT_ABORTED 301 } mss_usbd_msc_bot_state_t; 302 303 /* Command Block Wrapper (CBW) */ 304 typedef struct mss_usb_msc_cbw { 305 uint32_t signature; 306 uint32_t tag; 307 uint32_t xfr_length; 308 uint8_t flags; 309 uint8_t lun; 310 uint8_t cmd_length; 311 uint8_t cmd_block[16]; 312 } mss_usb_msc_cbw_t; 313 314 /* Command Status Wrapper (CSW) */ 315 typedef struct mss_usbd_msc_csw { 316 uint32_t signature; 317 uint32_t tag; 318 uint32_t data_residue; 319 mss_usbd_msc_csw_status_t status; 320 } mss_usbd_msc_csw_t; 321 322 /* SCSI inquiry response */ 323 typedef struct mss_usbd_msc_scsi_inq_resp { 324 uint8_t peripheral; 325 uint8_t removable; 326 uint8_t version; 327 uint8_t resp_data_format; 328 uint8_t additional_length; 329 uint8_t sccstp; 330 uint8_t bqueetc; 331 uint8_t cmd_que; 332 uint8_t vendor_id[8]; 333 uint8_t product_id[16]; 334 uint8_t product_rev[4]; 335 } mss_usbd_msc_scsi_inq_resp_t; 336 337 typedef struct mss_usbd_msc_scsi_sense_resp { 338 const uint8_t response_code; /*0x70 - spc3-table12*/ 339 const uint8_t obsolete; 340 uint8_t sense_key; /*Table 27 - spc3-4.5.6*/ 341 const uint8_t info[4]; 342 const uint8_t additional_length; 343 const uint8_t command_info[4]; 344 uint8_t asc; /*Table28 - spc3-4.5.6*/ 345 const uint8_t unused[5]; 346 } mss_usbd_msc_scsi_sense_resp_t; 347 348 typedef struct mss_usbd_msc_lun_capacity { 349 uint8_t last_lba_msb; 350 uint8_t last_lba_2; 351 uint8_t last_lba_1; 352 uint8_t last_lba_lsb; 353 uint8_t block_size_msb; 354 uint8_t block_size_2; 355 uint8_t block_size_1; 356 uint8_t block_size_lsb; 357 uint32_t blk_sz_len; 358 } mss_usbd_msc_lun_capacity_t; 359 360 /***************************************************************************//** 361 Exported functions from USBD-MSC class driver 362 */ 363 364 /***************************************************************************//** 365 @brief MSS_USBD_MSC_init() 366 The MSS_USBD_MSC_init() function must be used by the application to initialize 367 the MSC class driver. A pointer to the structure of type mss_usbd_msc_media_t 368 must be passed as a parameter to this function. 369 370 @param media_ops 371 The media_ops parameter is a pointer to the structure of type 372 mss_usbd_msc_media_t. This is used by the MSC class driver to call the 373 call-back functions implemented by the application. 374 375 @param speed 376 The speed parameter indicates the USB speed at which this class driver must 377 operate. 378 379 @return 380 This function does not return a value. 381 382 Example: 383 @code 384 //Assign call-back function handler structure needed by MSD class driver 385 MSS_USBD_MSC_init(&usb_flash_media, MSS_USB_DEVICE_HS); 386 387 //Assign call-back function handler structure needed by USB Device Core driver 388 MSS_USBD_set_desc_cb_handler(&flash_drive_descr_cb); 389 390 //Initialize USB driver HS device mode 391 MSS_USBD_init(MSS_USB_DEVICE_HS); 392 393 @endcode 394 */ 395 void 396 MSS_USBD_MSC_init 397 ( 398 mss_usbd_msc_media_t* media_ops, 399 mss_usb_device_speed_t speed 400 ); 401 402 /***************************************************************************//** 403 @brief USBD_get_state() 404 The MSS_USBD_MSC_get_state() function can be used by the application to find 405 out the current state of the MSC class driver. 406 407 @param media_ops 408 This function does not take a parameter. 409 410 @return 411 This function returns a value of type mss_usbd_msc_state_t indicating the 412 current state of the MSC class driver. 413 414 Example: 415 @code 416 uint8_t 417 usb_flash_media_get_capacity 418 ( 419 uint8_t lun, 420 uint32_t *no_of_blocks, 421 uint32_t *block_size 422 ) 423 { 424 if(USBD_MSC_CONFIGURED == MSS_USBD_MSC_get_state()) 425 { 426 *no_of_blocks = lun_data[lun].number_of_blocks; 427 *block_size = lun_data[lun].lba_block_size; 428 return 1; 429 } 430 Else 431 { 432 Return 0; 433 } 434 } 435 436 @endcode 437 */ 438 mss_usbd_msc_state_t 439 MSS_USBD_MSC_get_state 440 ( 441 void 442 ); 443 444 #endif //MSS_USB_DEVICE_ENABLED 445 446 #ifdef __cplusplus 447 } 448 #endif 449 450 #endif /* __MSS_USB_DEVICE_MSD_H_ */ 451