41 #if MODE_HOST_SUPPORTED & TUSB_CFG_HOST_MSC
43 #define _TINY_USB_SOURCE_FILE_
58 OSAL_SEM_DEF(msch_semaphore);
59 static osal_semaphore_handle_t msch_sem_hdl;
73 return tusbh_device_is_configured(dev_addr) &&
74 msch_data[dev_addr-1].is_initialized;
79 return msch_data[dev_addr-1].is_initialized &&
80 hcd_pipe_is_busy(msch_data[dev_addr-1].bulk_in);
85 return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].vendor_id : NULL;
90 return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].product_id : NULL;
95 if ( !msch_data[dev_addr-1].is_initialized )
return TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED;
96 ASSERT(p_last_lba != NULL && p_block_size != NULL, TUSB_ERROR_INVALID_PARA);
98 (*p_last_lba) = msch_data[dev_addr-1].last_lba;
99 (*p_block_size) = (uint32_t) msch_data[dev_addr-1].block_size;
101 return TUSB_ERROR_NONE;
111 p_cbw->
tag = 0xCAFECAFE;
116 static tusb_error_t msch_command_xfer(msch_interface_t * p_msch,
void* p_buffer)
118 if ( NULL != p_buffer)
120 if (p_msch->cbw.dir & TUSB_DIR_DEV_TO_HOST_MASK)
122 ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw,
sizeof(
msc_cmd_block_wrapper_t),
false) );
123 ASSERT_STATUS( hcd_pipe_queue_xfer(p_msch->bulk_in , p_buffer, p_msch->cbw.xfer_bytes) );
126 ASSERT_STATUS( hcd_pipe_queue_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw,
sizeof(
msc_cmd_block_wrapper_t)) );
127 ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out , p_buffer, p_msch->cbw.xfer_bytes,
false) );
133 return TUSB_ERROR_NONE;
136 tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
138 msch_interface_t* p_msch = &msch_data[dev_addr-1];
141 msc_cbw_add_signature(&p_msch->cbw, lun);
143 p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
153 memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len);
155 ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) );
157 return TUSB_ERROR_NONE;
160 tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
162 msch_interface_t* p_msch = &msch_data[dev_addr-1];
165 msc_cbw_add_signature(&p_msch->cbw, lun);
167 p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
175 .partial_medium_indicator = 0
178 memcpy(p_msch->cbw.command, &cmd_read_capacity10, p_msch->cbw.cmd_len);
180 ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) );
182 return TUSB_ERROR_NONE;
189 msch_interface_t* p_msch = &msch_data[dev_addr-1];
192 p_msch->cbw.xfer_bytes = 18;
193 p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
203 memcpy(p_msch->cbw.command, &cmd_request_sense, p_msch->cbw.cmd_len);
205 ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) );
207 return TUSB_ERROR_NONE;
212 msch_interface_t* p_msch = &msch_data[dev_addr-1];
215 msc_cbw_add_signature(&p_msch->cbw, lun);
217 p_msch->cbw.xfer_bytes = 0;
218 p_msch->cbw.dir = TUSB_DIR_HOST_TO_DEV;
228 memcpy(p_msch->cbw.command, &cmd_test_unit_ready, p_msch->cbw.cmd_len);
231 ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw,
sizeof(
msc_cmd_block_wrapper_t),
false) );
234 return TUSB_ERROR_NONE;
239 msch_interface_t* p_msch = &msch_data[dev_addr-1];
242 msc_cbw_add_signature(&p_msch->cbw, lun);
244 p_msch->cbw.xfer_bytes = p_msch->block_size*block_count;
245 p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
253 .block_count = u16_le2be(block_count)
256 memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len);
258 ASSERT_STATUS ( msch_command_xfer(p_msch, p_buffer));
260 return TUSB_ERROR_NONE;
265 msch_interface_t* p_msch = &msch_data[dev_addr-1];
268 msc_cbw_add_signature(&p_msch->cbw, lun);
270 p_msch->cbw.xfer_bytes = p_msch->block_size*block_count;
271 p_msch->cbw.dir = TUSB_DIR_HOST_TO_DEV;
279 .block_count = u16_le2be(block_count)
282 memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len);
284 ASSERT_STATUS ( msch_command_xfer(p_msch, (
void*) p_buffer));
286 return TUSB_ERROR_NONE;
295 msch_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(msch_semaphore) );
307 return TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL;
314 for(uint32_t i=0; i<2; i++)
316 SUBTASK_ASSERT(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->
bDescriptorType);
317 SUBTASK_ASSERT(TUSB_XFER_BULK == p_endpoint->
bmAttributes.xfer);
320 &msch_data[dev_addr-1].bulk_in : &msch_data[dev_addr-1].bulk_out;
322 (*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint,
TUSB_CLASS_MSC);
323 SUBTASK_ASSERT( pipehandle_is_valid(*p_pipe_hdl) );
328 msch_data[dev_addr-1].interface_number = p_interface_desc->
bInterfaceNumber;
333 OSAL_SUBTASK_INVOKED_AND_WAIT(
334 usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE),
340 SUBTASK_ASSERT( TUSB_ERROR_NONE == error );
341 msch_data[dev_addr-1].max_lun = msch_buffer[0];
345 OSAL_SUBTASK_INVOKED_AND_WAIT(
346 usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE),
353 enum { SCSI_XFER_TIMEOUT = 2000 };
355 tusbh_msc_inquiry(dev_addr, 0, msch_buffer);
356 osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
357 SUBTASK_ASSERT_STATUS(error);
359 memcpy(msch_data[dev_addr-1].vendor_id , ((
scsi_inquiry_data_t*) msch_buffer)->vendor_id , 8);
360 memcpy(msch_data[dev_addr-1].product_id, ((
scsi_inquiry_data_t*) msch_buffer)->product_id, 16);
363 tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
364 osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
365 SUBTASK_ASSERT_STATUS(error);
369 if ( hcd_pipe_is_stalled(msch_data[dev_addr-1].bulk_in) )
371 OSAL_SUBTASK_INVOKED_AND_WAIT(
372 usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_ENDPOINT),
377 SUBTASK_ASSERT_STATUS(error);
379 hcd_pipe_clear_stall(msch_data[dev_addr-1].bulk_in);
380 osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
381 SUBTASK_ASSERT_STATUS(error);
385 osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
386 SUBTASK_ASSERT_STATUS(error);
389 tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
390 osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
391 SUBTASK_ASSERT_STATUS(error);
397 msch_data[dev_addr-1].is_initialized =
true;
403 void msch_isr(
pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
405 if ( pipehandle_is_equal(pipe_hdl, msch_data[pipe_hdl.dev_addr-1].bulk_in) )
407 if (msch_data[pipe_hdl.dev_addr-1].is_initialized)
412 osal_semaphore_post(msch_sem_hdl);
417 void msch_close(uint8_t dev_addr)
419 (void) hcd_pipe_close(msch_data[dev_addr-1].bulk_in);
420 (void) hcd_pipe_close(msch_data[dev_addr-1].bulk_out);
422 memclr_(&msch_data[dev_addr-1],
sizeof(msch_interface_t));
423 osal_semaphore_reset(msch_sem_hdl);
SCSI Read Capacity 10 Command: Read Capacity.
tusb_error_t tusbh_msc_read10(uint8_t dev_addr, uint8_t lun, void *p_buffer, uint32_t lba, uint16_t block_count) ATTR_WARN_UNUSED_RESULT
Perform SCSI READ 10 command to read data from MassStorage device.
USB Standard Interface Descriptor (section 9.6.1 table 9-12)
#define ATTR_WARN_UNUSED_RESULT
The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this...
uint8_t const * tusbh_msc_get_vendor_name(uint8_t dev_addr)
Get SCSI vendor's name of MassStorage device.
#define __n2be(x)
built-in function to convert 32-bit from native to Big Endian
The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/wri...
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
Constant value of 43425355h (little endian)
uint8_t const * tusbh_msc_get_product_name(uint8_t dev_addr)
Get SCSI product's name of MassStorage device.
uint8_t lun
The device Logical Unit Number (LUN) to which the command block is being sent. For devices that suppo...
uint32_t signature
Signature that helps identify this data packet as a CBW. The signature field shall contain the value ...
The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from th...
#define TUSB_CFG_HOST_DEVICE_MAX
Maximum number of device host stack can manage If hub class is not enabled, set this equal to numbe...
uint8_t cmd_code
SCSI OpCode for SCSI_CMD_INQUIRY.
uint8_t cmd_code
SCSI OpCode.
#define __be2n(x)
built-in function to convert 32-bit from Big Endian to native
The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used t...
The READ (10) command requests that the device server read the specified logical block(s) and transfe...
The SCSI Inquiry command is used to obtain basic information from a target device.
SCSI Read Capacity 10 Response Data.
tusb_error_t tusbh_msc_write10(uint8_t dev_addr, uint8_t lun, void const *p_buffer, uint32_t lba, uint16_t block_count) ATTR_WARN_UNUSED_RESULT
Perform SCSI WRITE 10 command to write data to MassStorage device.
struct tusb_descriptor_endpoint_t::@8 bmAttributes
This field describes the endpoint's attributes when it is configured using the bConfigurationValue. Bits 1..0: Transfer Type - 00 = Control - 01 = Isochronous - 10 = Bulk - 11 = Interrupt If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: Bits 3..2: Synchronization Type - 00 = No Synchronization - 01 = Asynchronous - 10 = Adaptive - 11 = Synchronous Bits 5..4: Usage Type - 00 = Data endpoint - 01 = Feedback endpoint - 10 = Implicit feedback Data endpoint - 11 = Reserved Refer to Chapter 5 of USB 2.0 specification for more information. All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
#define TUSB_CFG_ATTR_USBRAM
SCSI Inquiry Response Data.
tusb_error_t tusbh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
Perform SCSI REQUEST SENSE command, used to retrieve sense data from MassStorage device.
tusb_error_t tusbh_msc_get_capacity(uint8_t dev_addr, uint32_t *p_last_lba, uint32_t *p_block_size)
Get SCSI Capacity of MassStorage device.
uint8_t bDescriptorType
ENDPOINT Descriptor Type.
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
USB Standard Endpoint Descriptor (section 9.6.1 table 9-13)
tusb_error_t tusbh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_cmd_status_wrapper_t *p_csw) ATTR_WARN_UNUSED_RESULT
Perform SCSI TEST UNIT READY command to test if MassStorage device is ready.
uint8_t cmd_code
SCSI OpCode for SCSI_CMD_READ_CAPACITY_10.
void tusbh_msc_unmounted_cb(uint8_t dev_addr)
Callback function that will be invoked when a device with MassStorage interface is unmounted...
bool tusbh_msc_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT
Check if device supports MassStorage interface or not.
This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host.
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
uint32_t tag
Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTa...
bool tusbh_msc_is_busy(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT
Check if the interface is currently busy or not.
The Get Max LUN device request is used to determine the number of logical units supported by the devi...
tusb_error_t
Error Code returned.
void tusbh_msc_isr(uint8_t dev_addr, tusb_event_t event, uint32_t xferred_bytes)
Callback function that is invoked when an transferring event occurred.
#define ATTR_ALIGNED(Bytes)
This attribute specifies a minimum alignment for the variable or structure field, measured in bytes...
The SCSI Read Capacity command is used to obtain data capacity information from a target device...
SCSI transparent command set.
uint8_t cmd_code
SCSI OpCode for SCSI_CMD_TEST_UNIT_READY.
#define ATTR_ALWAYS_INLINE
Generally, functions are not inlined unless optimization is specified. For functions declared inline...
void tusbh_msc_mounted_cb(uint8_t dev_addr)
Callback function that will be invoked when a device with MassStorage interface is mounted...
SCSI Test Unit Ready Command.
uint8_t bEndpointAddress
The address of the endpoint on the USB device described by this descriptor. The address is encoded as...