@@ -60,11 +60,8 @@ struct CSW {
6060/* Single instance is likely enough because it can support multiple LUNs */
6161#define MSC_NUM_INSTANCES CONFIG_USBD_MSC_INSTANCES_COUNT
6262
63- /* Can be 64 if device is not High-Speed capable */
64- #define MSC_BUF_SIZE USBD_MAX_BULK_MPS
65-
6663UDC_BUF_POOL_DEFINE (msc_ep_pool ,
67- MSC_NUM_INSTANCES * 2 , MSC_BUF_SIZE ,
64+ MSC_NUM_INSTANCES * 2 , USBD_MAX_BULK_MPS ,
6865 sizeof (struct udc_buf_info ), NULL );
6966
7067struct msc_event {
@@ -121,9 +118,8 @@ struct msc_bot_ctx {
121118 struct scsi_ctx luns [CONFIG_USBD_MSC_LUNS_PER_INSTANCE ];
122119 struct CBW cbw ;
123120 struct CSW csw ;
124- uint8_t scsi_buf [ CONFIG_USBD_MSC_SCSI_BUFFER_SIZE ] ;
121+ uint8_t * scsi_buf ;
125122 uint32_t transferred_data ;
126- size_t scsi_offset ;
127123 size_t scsi_bytes ;
128124};
129125
@@ -143,6 +139,53 @@ static struct net_buf *msc_buf_alloc(const uint8_t ep)
143139 return buf ;
144140}
145141
142+ static struct net_buf * msc_buf_alloc_data (const uint8_t ep , uint8_t * data , size_t len )
143+ {
144+ struct net_buf * buf = NULL ;
145+ struct udc_buf_info * bi ;
146+
147+ buf = net_buf_alloc_with_data (& msc_ep_pool , data , len , K_NO_WAIT );
148+ if (buf == NULL ) {
149+ return NULL ;
150+ }
151+
152+ if (USB_EP_DIR_IS_OUT (ep )) {
153+ /* Buffer is empty, USB stack will write data from host */
154+ buf -> len = 0 ;
155+ }
156+
157+ bi = udc_get_buf_info (buf );
158+ bi -> ep = ep ;
159+
160+ return buf ;
161+ }
162+
163+ static size_t msc_next_transfer_length (struct usbd_class_data * const c_data )
164+ {
165+ struct usbd_context * uds_ctx = usbd_class_get_ctx (c_data );
166+ struct msc_bot_ctx * ctx = usbd_class_get_private (c_data );
167+ struct scsi_ctx * lun = & ctx -> luns [ctx -> cbw .bCBWLUN ];
168+ size_t len = scsi_cmd_remaining_data_len (lun );
169+
170+ len = MIN (CONFIG_USBD_MSC_SCSI_BUFFER_SIZE , len );
171+
172+ /* Limit transfer to bulk endpoint wMaxPacketSize multiple */
173+ if (USBD_SUPPORTS_HIGH_SPEED &&
174+ usbd_bus_speed (uds_ctx ) == USBD_SPEED_HS ) {
175+ len = ROUND_DOWN (len , 512 );
176+ } else {
177+ /* Full-Speed */
178+ len = ROUND_DOWN (len , 64 );
179+ }
180+
181+ /* Round down to sector size multiple */
182+ if (lun -> sector_size ) {
183+ len = ROUND_DOWN (len , lun -> sector_size );
184+ }
185+
186+ return len ;
187+ }
188+
146189static uint8_t msc_get_bulk_in (struct usbd_class_data * const c_data )
147190{
148191 struct usbd_context * uds_ctx = usbd_class_get_ctx (c_data );
@@ -171,10 +214,11 @@ static uint8_t msc_get_bulk_out(struct usbd_class_data *const c_data)
171214 return desc -> if0_out_ep .bEndpointAddress ;
172215}
173216
174- static void msc_queue_bulk_out_ep (struct usbd_class_data * const c_data )
217+ static void msc_queue_bulk_out_ep (struct usbd_class_data * const c_data , bool data )
175218{
176219 struct msc_bot_ctx * ctx = usbd_class_get_private (c_data );
177220 struct net_buf * buf ;
221+ uint8_t * scsi_buf = ctx -> scsi_buf ;
178222 uint8_t ep ;
179223 int ret ;
180224
@@ -185,7 +229,13 @@ static void msc_queue_bulk_out_ep(struct usbd_class_data *const c_data)
185229
186230 LOG_DBG ("Queuing OUT" );
187231 ep = msc_get_bulk_out (c_data );
188- buf = msc_buf_alloc (ep );
232+
233+ if (data ) {
234+ buf = msc_buf_alloc_data (ep , scsi_buf , msc_next_transfer_length (c_data ));
235+ } else {
236+ buf = msc_buf_alloc (ep );
237+ }
238+
189239 /* The pool is large enough to support all allocations. Failing alloc
190240 * indicates either a memory leak or logic error.
191241 */
@@ -255,50 +305,37 @@ static void msc_process_read(struct msc_bot_ctx *ctx)
255305 struct scsi_ctx * lun = & ctx -> luns [ctx -> cbw .bCBWLUN ];
256306 int bytes_queued = 0 ;
257307 struct net_buf * buf ;
308+ uint8_t * scsi_buf = ctx -> scsi_buf ;
258309 uint8_t ep ;
259- size_t len ;
260310 int ret ;
261311
262312 /* Fill SCSI Data IN buffer if there is no data available */
263313 if (ctx -> scsi_bytes == 0 ) {
264- ctx -> scsi_bytes = scsi_read_data (lun , ctx -> scsi_buf );
265- ctx -> scsi_offset = 0 ;
314+ size_t len = msc_next_transfer_length (ctx -> class_node );
315+
316+ bytes_queued = scsi_read_data (lun , scsi_buf , len );
317+ } else {
318+ bytes_queued = ctx -> scsi_bytes ;
266319 }
267320
321+ /* All data is submitted in one go. Any potential new data will
322+ * have to be retrieved using scsi_read_data() on next call.
323+ */
324+ ctx -> scsi_bytes = 0 ;
325+
268326 if (atomic_test_and_set_bit (& ctx -> bits , MSC_BULK_IN_QUEUED )) {
269327 __ASSERT_NO_MSG (false);
270328 LOG_ERR ("IN already queued" );
271329 return ;
272330 }
273331
274332 ep = msc_get_bulk_in (ctx -> class_node );
275- buf = msc_buf_alloc (ep );
333+ buf = msc_buf_alloc_data (ep , scsi_buf , bytes_queued );
276334 /* The pool is large enough to support all allocations. Failing alloc
277335 * indicates either a memory leak or logic error.
278336 */
279337 __ASSERT_NO_MSG (buf );
280338
281- while (ctx -> scsi_bytes - ctx -> scsi_offset > 0 ) {
282- len = MIN (ctx -> scsi_bytes - ctx -> scsi_offset ,
283- MSC_BUF_SIZE - bytes_queued );
284- if (len == 0 ) {
285- /* Either queued as much as possible or there is no more
286- * SCSI IN data available
287- */
288- break ;
289- }
290-
291- net_buf_add_mem (buf , & ctx -> scsi_buf [ctx -> scsi_offset ], len );
292- bytes_queued += len ;
293- ctx -> scsi_offset += len ;
294-
295- if (ctx -> scsi_bytes == ctx -> scsi_offset ) {
296- /* SCSI buffer can be reused now */
297- ctx -> scsi_bytes = scsi_read_data (lun , ctx -> scsi_buf );
298- ctx -> scsi_offset = 0 ;
299- }
300- }
301-
302339 /* Either the net buf is full or there is no more SCSI data */
303340 ctx -> csw .dCSWDataResidue -= bytes_queued ;
304341 ret = usbd_ep_enqueue (ctx -> class_node , buf );
@@ -319,7 +356,6 @@ static void msc_process_cbw(struct msc_bot_ctx *ctx)
319356 cb_len = scsi_usb_boot_cmd_len (ctx -> cbw .CBWCB , ctx -> cbw .bCBWCBLength );
320357 data_len = scsi_cmd (lun , ctx -> cbw .CBWCB , cb_len , ctx -> scsi_buf );
321358 ctx -> scsi_bytes = data_len ;
322- ctx -> scsi_offset = 0 ;
323359 cmd_is_data_read = scsi_cmd_is_data_read (lun );
324360 cmd_is_data_write = scsi_cmd_is_data_write (lun );
325361 data_len += scsi_cmd_remaining_data_len (lun );
@@ -399,46 +435,17 @@ static void msc_process_write(struct msc_bot_ctx *ctx,
399435
400436 ctx -> transferred_data += len ;
401437
402- while ((len > 0 ) && (scsi_cmd_remaining_data_len (lun ) > 0 )) {
403- /* Copy received data to the end of SCSI buffer */
404- tmp = MIN (len , sizeof (ctx -> scsi_buf ) - ctx -> scsi_bytes );
405- memcpy (& ctx -> scsi_buf [ctx -> scsi_bytes ], buf , tmp );
406- ctx -> scsi_bytes += tmp ;
407- buf += tmp ;
408- len -= tmp ;
409-
410- /* Pass data to SCSI layer when either all transfer data bytes
411- * have been received or SCSI buffer is full.
412- */
413- while ((ctx -> scsi_bytes >= scsi_cmd_remaining_data_len (lun )) ||
414- (ctx -> scsi_bytes == sizeof (ctx -> scsi_buf ))) {
415- tmp = scsi_write_data (lun , ctx -> scsi_buf , ctx -> scsi_bytes );
416- __ASSERT (tmp <= ctx -> scsi_bytes ,
417- "Processed more data than requested" );
418- if (tmp == 0 ) {
419- LOG_WRN ("SCSI handler didn't process %d bytes" ,
420- ctx -> scsi_bytes );
421- ctx -> scsi_bytes = 0 ;
422- } else {
423- LOG_DBG ("SCSI processed %d out of %d bytes" ,
424- tmp , ctx -> scsi_bytes );
425- }
426-
427- ctx -> csw .dCSWDataResidue -= tmp ;
428- if (scsi_cmd_remaining_data_len (lun ) == 0 ) {
429- /* Abandon any leftover data */
430- ctx -> scsi_bytes = 0 ;
431- break ;
432- }
433-
434- /* Move remaining data at the start of SCSI buffer. Note
435- * that the copied length here is zero (and thus no copy
436- * happens) when underlying sector size is equal to SCSI
437- * buffer size.
438- */
439- memmove (ctx -> scsi_buf , & ctx -> scsi_buf [tmp ], ctx -> scsi_bytes - tmp );
440- ctx -> scsi_bytes -= tmp ;
438+ if ((len > 0 ) && (scsi_cmd_remaining_data_len (lun ) > 0 )) {
439+ /* Pass data to SCSI layer. */
440+ tmp = scsi_write_data (lun , buf , len );
441+ __ASSERT (tmp <= len , "Processed more data than requested" );
442+ if (tmp == 0 ) {
443+ LOG_WRN ("SCSI handler didn't process %d bytes" , len );
444+ } else {
445+ LOG_DBG ("SCSI processed %d out of %d bytes" , tmp , len );
441446 }
447+
448+ ctx -> csw .dCSWDataResidue -= tmp ;
442449 }
443450
444451 if ((ctx -> transferred_data >= ctx -> cbw .dCBWDataTransferLength ) ||
@@ -514,7 +521,7 @@ static void msc_handle_bulk_in(struct msc_bot_ctx *ctx,
514521 struct scsi_ctx * lun = & ctx -> luns [ctx -> cbw .bCBWLUN ];
515522
516523 ctx -> transferred_data += len ;
517- if (ctx -> scsi_bytes == 0 ) {
524+ if (msc_next_transfer_length ( ctx -> class_node ) == 0 ) {
518525 if (ctx -> csw .dCSWDataResidue > 0 ) {
519526 /* Case (5) Hi > Di
520527 * While we may have sent short packet, device
@@ -623,9 +630,11 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3)
623630
624631 switch (ctx -> state ) {
625632 case MSC_BBB_EXPECT_CBW :
633+ msc_queue_bulk_out_ep (evt .c_data , false);
634+ break ;
626635 case MSC_BBB_PROCESS_WRITE :
627636 /* Ensure we can accept next OUT packet */
628- msc_queue_bulk_out_ep (evt .c_data );
637+ msc_queue_bulk_out_ep (evt .c_data , true );
629638 break ;
630639 default :
631640 break ;
@@ -645,7 +654,7 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3)
645654 if (ctx -> state == MSC_BBB_PROCESS_READ ) {
646655 msc_process_read (ctx );
647656 } else if (ctx -> state == MSC_BBB_PROCESS_WRITE ) {
648- msc_queue_bulk_out_ep (evt .c_data );
657+ msc_queue_bulk_out_ep (evt .c_data , true );
649658 } else if (ctx -> state == MSC_BBB_SEND_CSW ) {
650659 msc_send_csw (ctx );
651660 }
@@ -864,14 +873,17 @@ struct usbd_class_api msc_bot_api = {
864873 .init = msc_bot_init ,
865874};
866875
867- #define DEFINE_MSC_BOT_CLASS_DATA (x , _ ) \
868- static struct msc_bot_ctx msc_bot_ctx_##x = { \
869- .desc = &msc_bot_desc_##x, \
870- .fs_desc = msc_bot_fs_desc_##x, \
871- .hs_desc = msc_bot_hs_desc_##x, \
872- }; \
873- \
874- USBD_DEFINE_CLASS(msc_##x, &msc_bot_api, &msc_bot_ctx_##x, \
876+ #define DEFINE_MSC_BOT_CLASS_DATA (x , _ ) \
877+ UDC_STATIC_BUF_DEFINE(scsi_buf_##x, CONFIG_USBD_MSC_SCSI_BUFFER_SIZE); \
878+ \
879+ static struct msc_bot_ctx msc_bot_ctx_##x = { \
880+ .desc = &msc_bot_desc_##x, \
881+ .fs_desc = msc_bot_fs_desc_##x, \
882+ .hs_desc = msc_bot_hs_desc_##x, \
883+ .scsi_buf = scsi_buf_##x \
884+ }; \
885+ \
886+ USBD_DEFINE_CLASS(msc_##x, &msc_bot_api, &msc_bot_ctx_##x, \
875887 &msc_bot_vregs);
876888
877889LISTIFY (MSC_NUM_INSTANCES , DEFINE_MSC_BOT_DESCRIPTOR , ( ))
0 commit comments