ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_hmsc.c
Go to the documentation of this file.
1
47
48#include "ra8_usb_hmsc.h"
49
50#include <stdint.h>
51
52#include "ra8_attributes.h"
53#include "ra8_check.h"
54#include "ra8_err.h"
55#include "ra8_hal_internal.h"
56#include "ra8_log.h"
57#include "ra8_time.h"
58#include "ra8_usb.h"
60
61static const char* s_tag = "USBHMSC";
62
63/* =============================================================================
64 * Internal constants
65 * =============================================================================
66 */
67
84
98
107
115typedef enum : uint32_t {
119
131
136typedef enum : uint32_t {
139
155
167
172typedef enum : uint32_t {
175
190
203
213
214/* =============================================================================
215 * Internal state
216 * =============================================================================
217 */
218
219/* Singleton shadow state. Shared with ra8_usb_hmsc_enum.c (the polled
220 * enumeration ladder) through ra8_hal_internal.h: the type and the extern
221 * declaration live there, the single definition lives here. */
223
224/* =============================================================================
225 * Internal helpers
226 * =============================================================================
227 */
228
257
276static uint32_t internal_next_tag(void)
277{
278 const uint32_t tag = g_usb_hmsc_state.next_cbw_tag;
279 ++g_usb_hmsc_state.next_cbw_tag;
280 return tag;
281}
282
283/* Pack a uint32 into 4 little-endian bytes -- see surrounding code and HUM citations. */
285static void internal_pack_u32_le(uint32_t value, uint8_t* dst)
286{
287 dst[0] = (uint8_t)((value >> k_ra8_hmsc_shift_byte0) & k_ra8_hmsc_byte_mask);
288 dst[1] = (uint8_t)((value >> k_ra8_hmsc_shift_byte1) & k_ra8_hmsc_byte_mask);
289 dst[2] = (uint8_t)((value >> k_ra8_hmsc_shift_byte2) & k_ra8_hmsc_byte_mask);
290 dst[3] = (uint8_t)((value >> k_ra8_hmsc_shift_byte3) & k_ra8_hmsc_byte_mask);
291}
292
293/* Unpack a uint32 from 4 little-endian bytes -- see surrounding code and HUM citations. */
295static uint32_t internal_unpack_u32_le(const uint8_t* src)
296{
297 return ((uint32_t)src[0] << k_ra8_hmsc_shift_byte0) |
298 ((uint32_t)src[1] << k_ra8_hmsc_shift_byte1) |
299 ((uint32_t)src[2] << k_ra8_hmsc_shift_byte2) |
300 ((uint32_t)src[3] << k_ra8_hmsc_shift_byte3);
301}
302
323static uint32_t internal_unpack_u32_be(const uint8_t* src)
324{
325 return ((uint32_t)src[0] << k_ra8_hmsc_shift_byte3) |
326 ((uint32_t)src[1] << k_ra8_hmsc_shift_byte2) |
327 ((uint32_t)src[2] << k_ra8_hmsc_shift_byte1) |
328 ((uint32_t)src[3] << k_ra8_hmsc_shift_byte0);
329}
330
348static void internal_zero_bytes(uint8_t* dst, uint16_t len)
349{
350 for (uint16_t i = 0U; i < len; ++i) {
351 dst[i] = 0U;
352 }
353}
354
355/* Copy `len` bytes from `src` to `dst` byte-by-byte -- see surrounding code and HUM citations. */
357static void internal_copy_bytes(uint8_t* dst, const uint8_t* src, uint16_t len)
358{
359 for (uint16_t i = 0U; i < len; ++i) {
360 dst[i] = src[i];
361 }
362}
363
364/* =============================================================================
365 * Public CBW / CSW helpers (also used as test introspection)
366 * =============================================================================
367 */
368
370 uint32_t data_transfer_length,
371 bool data_in,
372 const uint8_t* cdb,
373 uint8_t cdb_len,
374 uint8_t* out_cbw)
375{
376 RA8_CHECK_NULL_PTR(cdb, s_tag, "build_cbw: cdb");
377 RA8_CHECK_NULL_PTR(out_cbw, s_tag, "build_cbw: out_cbw");
378 if (target_lun > k_ra8_hmsc_lun_field_mask) {
380 }
381 if ((cdb_len == 0U) || (cdb_len > k_ra8_hmsc_cdb_max_len)) {
383 }
384
385 /* Zero the entire CBW so reserved nibbles stay 0 -- USB MSC BBB
386 * rev 1.0 sec 5.1 requires zero in the high nibble of bCBWLUN /
387 * the high 3 bits of bCBWCBLength. */
389
390 /* dCBWSignature = 'USBC' little-endian. */
392
393 /* dCBWTag = monotonic. */
394 const uint32_t tag = internal_next_tag();
396
397 /* dCBWDataTransferLength. */
398 internal_pack_u32_le(data_transfer_length, &out_cbw[k_ra8_hmsc_cbw_off_data_length]);
399
400 /* bmCBWFlags. */
401 out_cbw[k_ra8_hmsc_cbw_off_flags] =
403
404 /* bCBWLUN (low 4 bits) / bCBWCBLength (low 5 bits). */
405 out_cbw[k_ra8_hmsc_cbw_off_lun] = (uint8_t)(target_lun & k_ra8_hmsc_lun_field_mask);
406 out_cbw[k_ra8_hmsc_cbw_off_cdb_length] = (uint8_t)(cdb_len & k_ra8_hmsc_cdb_field_mask);
407
408 /* CBWCB[16]. */
409 internal_copy_bytes(&out_cbw[k_ra8_hmsc_cbw_off_cdb], cdb, (uint16_t)cdb_len);
410
411 return k_ra8_ok;
412}
413
415 uint32_t expected_tag,
416 ra8_usb_hmsc_csw_status_t* out_status)
417{
418 RA8_CHECK_NULL_PTR(csw, s_tag, "decode_csw: csw");
419 RA8_CHECK_NULL_PTR(out_status, s_tag, "decode_csw: out_status");
420
421 const uint32_t signature = internal_unpack_u32_le(&csw[k_ra8_hmsc_csw_off_signature]);
422 if (signature != k_ra8_hmsc_csw_signature) {
424 }
425 const uint32_t tag = internal_unpack_u32_le(&csw[k_ra8_hmsc_csw_off_tag]);
426 if (tag != expected_tag) {
428 }
429
430 const uint8_t status_byte = csw[k_ra8_hmsc_csw_off_status];
431 if ((status_byte != k_ra8_hmsc_csw_status_passed) &&
432 (status_byte != k_ra8_hmsc_csw_status_failed) &&
433 (status_byte != k_ra8_hmsc_csw_status_phase_error)) {
435 }
436
437 *out_status = (ra8_usb_hmsc_csw_status_t)status_byte;
438 return k_ra8_ok;
439}
440
441/* =============================================================================
442 * Lifecycle
443 * =============================================================================
444 */
445
447{
448 if ((speed != k_ra8_usb_speed_fs) && (speed != k_ra8_usb_speed_hs)) {
450 }
451 const ra8_err_t usb_err = ra8_usb_host_init(speed);
452 if (usb_err != k_ra8_ok) {
453 ra8_log_error_val(s_tag, "ra8_usb_host_init failed", (uint32_t)usb_err);
455 }
456
457 g_usb_hmsc_state.speed = speed;
458 g_usb_hmsc_state.attached = false;
459 g_usb_hmsc_state.attach_cb = nullptr;
460 g_usb_hmsc_state.attach_ctx = nullptr;
463 g_usb_hmsc_state.initialized = true;
464
465 ra8_log_info_val(s_tag, "host-MSC ready", (uint32_t)speed);
466 return k_ra8_ok;
467}
468
470{
471 if (!g_usb_hmsc_state.initialized) {
473 }
474 /* Bus power down: drop UACT before tearing the controller. */
475 (void)ra8_usb_host_set_uact(g_usb_hmsc_state.speed, false);
477 g_usb_hmsc_state.initialized = false;
478 g_usb_hmsc_state.attached = false;
479 g_usb_hmsc_state.attach_cb = nullptr;
480 g_usb_hmsc_state.attach_ctx = nullptr;
481 return err;
482}
483
484/* =============================================================================
485 * Attach callback
486 * =============================================================================
487 */
488
490{
491 if (!g_usb_hmsc_state.initialized) {
493 }
494 g_usb_hmsc_state.attach_cb = on_attach;
495 g_usb_hmsc_state.attach_ctx = ctx;
496 return k_ra8_ok;
497}
498
499/* =============================================================================
500 * Internal BOT helpers shared by SCSI command entry points
501 * =============================================================================
502 */
503
504/* Validate driver state + LUN before issuing a SCSI command -- see surrounding code and HUM citations. */
506static ra8_err_t internal_check_ready(uint8_t target_lun)
507{
508 if (!g_usb_hmsc_state.initialized) {
510 }
511 if (!g_usb_hmsc_state.attached) {
513 }
514 if (target_lun > k_ra8_hmsc_max_lun) {
516 }
517 return k_ra8_ok;
518}
519
538static ra8_err_t internal_send_cbw(const uint8_t* cbw)
539{
542 cbw,
544}
545
564static ra8_err_t internal_recv_bytes(uint8_t* dst, uint16_t* inout_len)
565{
566 const uint16_t cap = *inout_len;
567 return ra8_usb_host_bulk_in(g_usb_hmsc_state.speed, k_ra8_hmsc_pipe_bulk_in, dst, cap, inout_len);
568}
569
570/* Build a 6-byte CDB for SCSI INQUIRY -- see surrounding code and HUM citations. */
578
579/* Build a 10-byte CDB for SCSI READ_CAPACITY(10) -- see surrounding code and HUM citations. */
586
604static void
605internal_build_rw10_cdb(uint8_t opcode, uint32_t lba, uint16_t block_count, uint8_t* cdb)
606{
608 cdb[k_ra8_hmsc_cdb_off_opcode] = opcode;
610 (uint8_t)((lba >> k_ra8_hmsc_shift_byte3) & k_ra8_hmsc_byte_mask);
612 (uint8_t)((lba >> k_ra8_hmsc_shift_byte2) & k_ra8_hmsc_byte_mask);
614 (uint8_t)((lba >> k_ra8_hmsc_shift_byte1) & k_ra8_hmsc_byte_mask);
616 (uint8_t)((lba >> k_ra8_hmsc_shift_byte0) & k_ra8_hmsc_byte_mask);
618 (uint8_t)((block_count >> k_ra8_hmsc_shift_byte1) & k_ra8_hmsc_byte_mask);
619 cdb[k_ra8_hmsc_cdb_off_cnt_lsb] = (uint8_t)(block_count & k_ra8_hmsc_byte_mask);
620}
621
622/* Build CBW + push it on bulk-OUT -- see surrounding code and HUM citations. */
624static ra8_err_t internal_issue_cbw(uint8_t target_lun,
625 uint32_t xfer_len,
626 bool data_in,
627 const uint8_t* cdb,
628 uint8_t cdb_len,
629 uint32_t* out_tag)
630{
631 uint8_t cbw[k_ra8_hmsc_cbw_len] = {};
632 const ra8_err_t cbw_err =
633 ra8_usb_hmsc_build_cbw(target_lun, xfer_len, data_in, cdb, cdb_len, cbw);
634 RA8_RETURN_ON_ERROR(cbw_err, s_tag, "issue_cbw: build cbw");
636 return internal_send_cbw(cbw);
637}
638
658static ra8_err_t internal_read_csw(uint32_t expected_tag)
659{
660 uint8_t csw[k_ra8_hmsc_csw_len] = {};
661 uint16_t len = k_ra8_hmsc_csw_len;
662 ra8_err_t err = internal_recv_bytes(csw, &len);
663 RA8_RETURN_ON_ERROR(err, s_tag, "read_csw: bulk in");
664 if (len != (uint16_t)k_ra8_hmsc_csw_len) {
665 return k_ra8_err_hw_error;
666 }
668 err = ra8_usb_hmsc_decode_csw(csw, expected_tag, &status);
669 RA8_RETURN_ON_ERROR(err, s_tag, "read_csw: decode");
670 if (status != k_ra8_hmsc_csw_status_passed) {
671 return k_ra8_err_hw_error;
672 }
673 return k_ra8_ok;
674}
675
676/* function -- see surrounding code and HUM citations. */
678static ra8_err_t internal_run_data_in(uint8_t target_lun,
679 const uint8_t* cdb,
680 uint8_t cdb_len,
681 uint8_t* out_buf,
682 uint16_t* inout_len)
683{
684 uint32_t tag = 0U;
685 const ra8_err_t cbw_err = internal_issue_cbw(target_lun, *inout_len, true, cdb, cdb_len, &tag);
686 RA8_RETURN_ON_ERROR(cbw_err, s_tag, "run_data_in: issue cbw");
687 const ra8_err_t derr = internal_recv_bytes(out_buf, inout_len);
688 RA8_RETURN_ON_ERROR(derr, s_tag, "run_data_in: data");
689 return internal_read_csw(tag);
690}
691
692/* function -- see surrounding code and HUM citations. */
694static ra8_err_t internal_run_data_out(uint8_t target_lun,
695 const uint8_t* cdb,
696 uint8_t cdb_len,
697 const uint8_t* in_buf,
698 uint16_t push_len)
699{
700 uint32_t tag = 0U;
701 const ra8_err_t cbw_err =
702 internal_issue_cbw(target_lun, (uint32_t)push_len, false, cdb, cdb_len, &tag);
703 RA8_RETURN_ON_ERROR(cbw_err, s_tag, "run_data_out: issue cbw");
704 /* The bulk-OUT primitive ships one packet per call, so chunk at the
705 * DEVICE's enumerated bulk-OUT wMaxPacketSize -- NOT the host
706 * controller's native ceiling. On a HS host driving an FS device (the
707 * self-loop) the controller speed is HS (512) but the endpoint is FS
708 * (64); chunking at 512 advances the offset 8x faster than the 64-byte
709 * packet actually sent, so the device receives only 1/8 of the data
710 * and the WRITE wedges. The pipe's PIPEMAXP is already this value
711 * (see the enum pipe setup). Fall back to the speed ceiling only if
712 * enumeration left it unset. */
713 uint16_t mps = g_usb_hmsc_state.device.bulk_out_max_packet;
714 if (mps == 0U) {
716 }
717 uint16_t offset = 0U;
718 while (offset < push_len) {
719 uint16_t chunk = (uint16_t)(push_len - offset);
720 if (chunk > mps) {
721 chunk = mps;
722 }
725 &in_buf[offset],
726 chunk);
727 RA8_RETURN_ON_ERROR(werr, s_tag, "run_data_out: data chunk");
728 offset = (uint16_t)(offset + chunk);
729 }
730 return internal_read_csw(tag);
731}
732
754static void internal_decode_inquiry(const uint8_t* raw, ra8_usb_hmsc_inquiry_response_t* response)
755{
756 internal_zero_bytes((uint8_t*)response, (uint16_t)sizeof(*response));
757 const uint8_t b0 = raw[k_ra8_hmsc_inq_off_dev_type];
758 const uint8_t b1 = raw[k_ra8_hmsc_inq_off_removable];
759 response->peripheral_qualifier = (uint8_t)(b0 >> k_ra8_hmsc_inq_qual_shift);
760 response->peripheral_device_type = (uint8_t)(b0 & k_ra8_hmsc_inq_dev_type_mask);
761 response->removable =
763 response->version = raw[k_ra8_hmsc_inq_off_version];
766 (uint16_t)sizeof(response->vendor_id));
769 (uint16_t)sizeof(response->product_id));
772 (uint16_t)sizeof(response->product_revision));
773}
774
775/* =============================================================================
776 * SCSI commands -- public entry points
777 * =============================================================================
778 */
779
781{
782 RA8_CHECK_NULL_PTR(response, s_tag, "inquiry: response");
783 const ra8_err_t ready_err = internal_check_ready(target_lun);
784 RA8_RETURN_ON_ERROR(ready_err, s_tag, "inquiry: not ready");
785
786 uint8_t cdb[k_ra8_hmsc_cdb_max_len] = {};
788
789 uint8_t raw_response[k_ra8_hmsc_inquiry_resp_len] = {};
790 uint16_t got_len = k_ra8_hmsc_inquiry_resp_len;
791 const ra8_err_t err =
792 internal_run_data_in(target_lun, cdb, (uint8_t)k_ra8_hmsc_cdb6_len, raw_response, &got_len);
793 RA8_RETURN_ON_ERROR(err, s_tag, "inquiry: bot");
794 internal_decode_inquiry(raw_response, response);
795 return k_ra8_ok;
796}
797
799ra8_usb_hmsc_read_capacity(uint8_t target_lun, uint32_t* block_count, uint32_t* block_size)
800{
801 RA8_CHECK_NULL_PTR(block_count, s_tag, "read_capacity: block_count");
802 RA8_CHECK_NULL_PTR(block_size, s_tag, "read_capacity: block_size");
803 const ra8_err_t ready_err = internal_check_ready(target_lun);
804 RA8_RETURN_ON_ERROR(ready_err, s_tag, "read_capacity: not ready");
805
806 uint8_t cdb[k_ra8_hmsc_cdb_max_len] = {};
808
809 uint8_t raw_response[k_ra8_hmsc_read_capacity_resp_len] = {};
810 uint16_t got_len = k_ra8_hmsc_read_capacity_resp_len;
811 const ra8_err_t err =
812 internal_run_data_in(target_lun, cdb, (uint8_t)k_ra8_hmsc_cdb10_len, raw_response, &got_len);
813 RA8_RETURN_ON_ERROR(err, s_tag, "read_capacity: bot");
814
815 /* Decode SBC-4 sec 5.10: byte[0..3] = LAST valid LBA (big-endian),
816 * byte[4..7] = block size (big-endian). When the fake returns
817 * zeros default to a sane block size so calling code can still
818 * compute capacities. */
819 const uint32_t last_lba = internal_unpack_u32_be(&raw_response[k_ra8_hmsc_cap_off_last_lba]);
820 const uint32_t blk = internal_unpack_u32_be(&raw_response[k_ra8_hmsc_cap_off_blk_size]);
821 *block_count = last_lba + 1U;
822 *block_size = (blk == 0U) ? (uint32_t)k_ra8_hmsc_block_size_default : blk;
823 return k_ra8_ok;
824}
825
827ra8_usb_hmsc_read10(uint8_t target_lun, uint32_t lba, uint16_t block_count, uint8_t* out_buf)
828{
829 RA8_CHECK_NULL_PTR(out_buf, s_tag, "read10: out_buf");
830 if (block_count == 0U) {
832 }
833 const ra8_err_t ready_err = internal_check_ready(target_lun);
834 RA8_RETURN_ON_ERROR(ready_err, s_tag, "read10: not ready");
835
836 uint8_t cdb[k_ra8_hmsc_cdb_max_len] = {};
837 internal_build_rw10_cdb(k_ra8_hmsc_scsi_read_10, lba, block_count, cdb);
838
839 /* dCBWDataTransferLength = block_count * block_size. We default to
840 * the standard 512-byte block; production should use the cached
841 * read_capacity result. */
842 const uint32_t xfer_len = (uint32_t)block_count * (uint32_t)k_ra8_hmsc_block_size_default;
843 uint16_t got_len = (xfer_len > UINT16_MAX) ? UINT16_MAX : (uint16_t)xfer_len;
844 const ra8_err_t err =
845 internal_run_data_in(target_lun, cdb, (uint8_t)k_ra8_hmsc_cdb10_len, out_buf, &got_len);
846 RA8_RETURN_ON_ERROR(err, s_tag, "read10: bot");
847 return k_ra8_ok;
848}
849
851ra8_usb_hmsc_write10(uint8_t target_lun, uint32_t lba, uint16_t block_count, const uint8_t* in_buf)
852{
853 RA8_CHECK_NULL_PTR(in_buf, s_tag, "write10: in_buf");
854 if (block_count == 0U) {
856 }
857 const ra8_err_t ready_err = internal_check_ready(target_lun);
858 RA8_RETURN_ON_ERROR(ready_err, s_tag, "write10: not ready");
859
860 uint8_t cdb[k_ra8_hmsc_cdb_max_len] = {};
862
863 const uint32_t xfer_len = (uint32_t)block_count * (uint32_t)k_ra8_hmsc_block_size_default;
864 const uint16_t push_len = (xfer_len > UINT16_MAX) ? UINT16_MAX : (uint16_t)xfer_len;
865 const ra8_err_t err =
866 internal_run_data_out(target_lun, cdb, (uint8_t)k_ra8_hmsc_cdb10_len, in_buf, push_len);
867 RA8_RETURN_ON_ERROR(err, s_tag, "write10: bot");
868 return k_ra8_ok;
869}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Cross-translation-unit private helpers shared inside ra8_hal.
ra8_usb_hmsc_state_t g_usb_hmsc_state
Singleton host-MSC shadow state, shared across the ra8_usb_hmsc split.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
SysTick-based tick counter, delay and timestamp helpers.
Native USB controller driver public API (device + host modes).
ra8_usb_speed_t
Selects which controller instance the call targets.
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
ra8_usb_hmsc_initial_tag_t
Starting value of the BOT dCBWTag counter.
@ k_ra8_hmsc_initial_tag
First tag handed out post-init.
static uint32_t internal_unpack_u32_le(const uint8_t *src)
ra8_usb_hmsc_byte_shift_t
Per-byte left-shift constants for little-endian / big-endian serialisation.
@ k_ra8_hmsc_shift_byte2
RA8 hmsc shift byte2.
@ k_ra8_hmsc_shift_byte3
RA8 hmsc shift byte3.
@ k_ra8_hmsc_shift_byte0
RA8 hmsc shift byte0.
@ k_ra8_hmsc_shift_byte1
RA8 hmsc shift byte1.
static ra8_err_t internal_read_csw(uint32_t expected_tag)
Read and validate the 13-byte CSW that closes a BOT exchange.
static void internal_build_inquiry_cdb(uint8_t *cdb)
static ra8_err_t internal_run_data_in(uint8_t target_lun, const uint8_t *cdb, uint8_t cdb_len, uint8_t *out_buf, uint16_t *inout_len)
static void internal_decode_inquiry(const uint8_t *raw, ra8_usb_hmsc_inquiry_response_t *response)
Decode a 36-byte SCSI standard INQUIRY response into the public struct.
static ra8_err_t internal_check_ready(uint8_t target_lun)
static ra8_err_t internal_recv_bytes(uint8_t *dst, uint16_t *inout_len)
Pull bytes from the bulk-IN pipe (data + CSW phase).
ra8_usb_hmsc_lun_mask_t
Field width masks for the bCBWLUN + bCBWCBLength bytes.
@ k_ra8_hmsc_lun_field_mask
Low 4 bits of bCBWLUN.
@ k_ra8_hmsc_cdb_field_mask
Low 5 bits of bCBWCBLen.
ra8_usb_hmsc_inquiry_offset_t
Byte offsets inside the SBC-4 standard INQUIRY response.
@ k_ra8_hmsc_inq_off_product_rev
Product revision.
@ k_ra8_hmsc_inq_off_product_id
Product ID start.
@ k_ra8_hmsc_inq_off_vendor_id
T10 Vendor ID start.
@ k_ra8_hmsc_inq_off_version
Byte 2 (SPC version).
@ k_ra8_hmsc_inq_off_dev_type
Byte 0 (qual+devtype).
@ k_ra8_hmsc_inq_off_removable
Byte 1 (removable).
ra8_err_t ra8_usb_hmsc_inquiry(uint8_t target_lun, ra8_usb_hmsc_inquiry_response_t *response)
Issue a SCSI INQUIRY (opcode 0x12) over BBB.
static void internal_pack_u32_le(uint32_t value, uint8_t *dst)
ra8_usb_hmsc_cbw_offset_t
Byte offsets inside the 31-byte CBW header.
@ k_ra8_hmsc_cbw_off_lun
bCBWLUN (low nib).
@ k_ra8_hmsc_cbw_off_data_length
dCBWDataTransferLen.
@ k_ra8_hmsc_cbw_off_tag
dCBWTag [4].
@ k_ra8_hmsc_cbw_off_cdb_length
bCBWCBLength (low 5).
@ k_ra8_hmsc_cbw_off_flags
bmCBWFlags.
@ k_ra8_hmsc_cbw_off_signature
dCBWSignature [4].
@ k_ra8_hmsc_cbw_off_cdb
CBWCB [16].
static void internal_copy_bytes(uint8_t *dst, const uint8_t *src, uint16_t len)
ra8_usb_hmsc_inquiry_field_t
Bit-field shifts / masks inside the SCSI INQUIRY response byte 0 / byte 1 (SBC-4 sec 6....
@ k_ra8_hmsc_inq_dev_type_mask
Byte 0 [4:0] dev type.
@ k_ra8_hmsc_inq_removable_shift
Byte 1 [7] removable bit.
@ k_ra8_hmsc_inq_removable_mask
1-bit removable flag.
@ k_ra8_hmsc_inq_qual_shift
Byte 0 [7:5] qualifier.
ra8_err_t ra8_usb_hmsc_read_capacity(uint8_t target_lun, uint32_t *block_count, uint32_t *block_size)
Issue a SCSI READ CAPACITY(10) (opcode 0x25) over BBB.
static uint32_t internal_next_tag(void)
Hand out the next BOT tag (monotonic uint32 counter).
ra8_err_t ra8_usb_hmsc_build_cbw(uint8_t target_lun, uint32_t data_transfer_length, bool data_in, const uint8_t *cdb, uint8_t cdb_len, uint8_t *out_cbw)
Construct the 31-byte CBW header for the given SCSI command.
ra8_err_t ra8_usb_hmsc_attach_callback(ra8_usb_hmsc_attach_fn_t on_attach, void *ctx)
Register (or detach) the attach callback.
ra8_usb_hmsc_byte_mask_t
Byte mask for serialisation.
@ k_ra8_hmsc_byte_mask
Single-byte extraction mask.
ra8_err_t ra8_usb_hmsc_read10(uint8_t target_lun, uint32_t lba, uint16_t block_count, uint8_t *out_buf)
Issue a SCSI READ(10) (opcode 0x28) over BBB.
static void internal_build_rw10_cdb(uint8_t opcode, uint32_t lba, uint16_t block_count, uint8_t *cdb)
Build a 10-byte CDB for SCSI READ(10) / WRITE(10).
ra8_err_t ra8_usb_hmsc_close(void)
Tear down the host-MSC driver and release the controller.
ra8_usb_hmsc_signature_t
BOT wrapper signatures (USB MSC BBB rev 1.0 sec 5).
@ k_ra8_hmsc_cbw_signature
'USBC' little-endian.
@ k_ra8_hmsc_csw_signature
'USBS' little-endian.
ra8_usb_hmsc_cdb_offset_t
SCSI CDB byte offsets used when assembling READ(10) / WRITE(10) / READ_CAPACITY(10) / INQUIRY blocks.
@ k_ra8_hmsc_cdb_off_cnt_lsb
READ(10): count low.
@ k_ra8_hmsc_cdb_off_opcode
Operation Code.
@ k_ra8_hmsc_cdb_off_lba_lsb
READ(10): LBA byte 0.
@ k_ra8_hmsc_cdb_off_cnt_msb
READ(10): count high.
@ k_ra8_hmsc_cdb_off_lba_b2
READ(10): LBA byte 1.
@ k_ra8_hmsc_cdb_off_inq_alloc
INQUIRY allocation len.
@ k_ra8_hmsc_cdb_off_lba_b1
READ(10): LBA byte 2.
@ k_ra8_hmsc_cdb_off_lba_msb
READ(10): LBA byte 3.
ra8_usb_hmsc_csw_offset_t
Byte offsets inside the 13-byte CSW.
@ k_ra8_hmsc_csw_off_tag
dCSWTag [4].
@ k_ra8_hmsc_csw_off_status
bCSWStatus.
@ k_ra8_hmsc_csw_off_signature
dCSWSignature [4].
@ k_ra8_hmsc_csw_off_residue
dCSWDataResidue.
static void internal_build_read_capacity_cdb(uint8_t *cdb)
static uint32_t internal_unpack_u32_be(const uint8_t *src)
Assemble a 32-bit word from four big-endian bytes.
static ra8_err_t internal_run_data_out(uint8_t target_lun, const uint8_t *cdb, uint8_t cdb_len, const uint8_t *in_buf, uint16_t push_len)
ra8_err_t ra8_usb_hmsc_decode_csw(const uint8_t *csw, uint32_t expected_tag, ra8_usb_hmsc_csw_status_t *out_status)
Decode a 13-byte CSW.
static uint16_t internal_bulk_max_packet(ra8_usb_speed_t speed)
Pick the bulk-endpoint max-packet ceiling for the negotiated speed.
static ra8_err_t internal_send_cbw(const uint8_t *cbw)
Push a CBW out on the bulk-OUT pipe.
ra8_err_t ra8_usb_hmsc_init(ra8_usb_speed_t speed)
Bring up the host-MSC driver on a chosen USB controller.
ra8_usb_hmsc_capacity_offset_t
Byte offsets inside the SCSI READ_CAPACITY(10) 8-byte response (SBC-4 sec 5.10).
@ k_ra8_hmsc_cap_off_last_lba
Last valid LBA (big-endian).
@ k_ra8_hmsc_cap_off_blk_size
Block length (big-endian).
ra8_usb_hmsc_cbw_flag_t
bmCBWFlags direction bit values.
@ k_ra8_hmsc_cbw_flag_data_in
Device -> host.
@ k_ra8_hmsc_cbw_flag_data_out
Host -> device.
static void internal_zero_bytes(uint8_t *dst, uint16_t len)
Zero len bytes at dst byte-by-byte.
static ra8_err_t internal_issue_cbw(uint8_t target_lun, uint32_t xfer_len, bool data_in, const uint8_t *cdb, uint8_t cdb_len, uint32_t *out_tag)
ra8_err_t ra8_usb_hmsc_write10(uint8_t target_lun, uint32_t lba, uint16_t block_count, const uint8_t *in_buf)
Issue a SCSI WRITE(10) (opcode 0x2A) over BBB.
Native USB host-side MSC (Mass Storage Class) class layer.
void(* ra8_usb_hmsc_attach_fn_t)(void *ctx, const ra8_usb_hmsc_device_t *device)
Attach-callback signature.
@ k_ra8_hmsc_pipe_bulk_in
PIPE3 -> attached EP bulk IN.
@ k_ra8_hmsc_pipe_bulk_out
PIPE4 -> attached EP bulk OUT.
@ k_ra8_hmsc_max_lun
Max LUNs the starter tracks.
ra8_usb_hmsc_csw_status_t
CSW status field values returned by the device after a CBW.
@ k_ra8_hmsc_csw_status_failed
Command failed.
@ k_ra8_hmsc_csw_status_phase_error
BBB phase error – need reset recovery.
@ k_ra8_hmsc_csw_status_passed
Command succeeded.
@ k_ra8_hmsc_bulk_max_packet_fs
Bulk size at full speed.
@ k_ra8_hmsc_bulk_max_packet_hs
Bulk size at high speed.
@ k_ra8_hmsc_read_capacity_resp_len
READ_CAPACITY(10).
@ k_ra8_hmsc_block_size_default
SCSI default block.
@ k_ra8_hmsc_inquiry_resp_len
INQUIRY response len.
@ k_ra8_hmsc_scsi_inquiry
INQUIRY.
@ k_ra8_hmsc_scsi_read_10
READ(10).
@ k_ra8_hmsc_scsi_write_10
WRITE(10).
@ k_ra8_hmsc_scsi_read_capacity_10
READ CAPACITY(10).
Cross-TU surface shared between the host-MSC class layer(ra8_usb_hmsc.c) and the polled enumeration l...
@ k_ra8_hmsc_csw_len
CSW length (BBB sec 5.2).
@ k_ra8_hmsc_cdb6_len
6-byte SCSI CDB.
@ k_ra8_hmsc_cdb_max_len
CDB ceiling.
@ k_ra8_hmsc_cdb10_len
10-byte SCSI CDB.
@ k_ra8_hmsc_cbw_len
CBW length (BBB sec 5.1).
ra8_err_t ra8_usb_host_bulk_out(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t *data, uint16_t len)
Transmit one bulk packet to the device and wait for the ACK.
ra8_err_t ra8_usb_host_bulk_in(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t *buf, uint16_t max_len, uint16_t *out_received)
Receive a bulk transfer from the device into buf.
ra8_err_t ra8_usb_host_init(ra8_usb_speed_t speed)
Bring up a USB controller in HOST mode.
ra8_err_t ra8_usb_host_deinit(ra8_usb_speed_t speed)
Tear down a host-mode controller and drop its MSTP reference.
ra8_err_t ra8_usb_host_set_uact(ra8_usb_speed_t speed, bool enable)
Enable / disable SOF (Start-of-Frame) generation on the bus.
Snapshot of the attached MSC device, passed to the attach callback.
Decoded SCSI INQUIRY response.
uint8_t vendor_id[8]
T10 Vendor ID, ASCII.
uint8_t peripheral_device_type
Bits [4:0] of byte 0.
uint8_t version
SPC version code.
uint8_t peripheral_qualifier
Bits [7:5] of byte 0.
uint8_t removable
1 = removable medium.
uint8_t product_id[16]
Product ID, ASCII.
uint8_t product_revision[4]
Product revision, ASCII.
Singleton shadow state for the host-MSC driver.