ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ux_device_class_storage_inquiry.c
Go to the documentation of this file.
1
35
36#define UX_SOURCE_CODE
37
38#include <stdint.h>
39
40#include "ra8_attributes.h"
41#include "ux_api.h"
42#include "ux_device_class_storage.h"
43#include "ux_device_stack.h"
44
76
98RA8_INTERNAL static void
99internal_inquiry_fill_standard(UX_SLAVE_CLASS_STORAGE* storage, ULONG lun, UCHAR* buf)
100{
101 buf[UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_PERIPHERAL_TYPE] =
102 (UCHAR)storage->ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_type;
103 buf[UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_REMOVABLE_MEDIA] =
104 (UCHAR)storage->ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_removable_flag;
105 if (storage->ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_type ==
106 UX_SLAVE_CLASS_STORAGE_MEDIA_CDROM) {
108 buf[k_inq_off_addl_len] = UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH_CD_ROM;
109 } else {
113 }
114 _ux_utility_memory_copy(buf + UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_VENDOR_INFORMATION,
115 storage->ux_slave_class_storage_vendor_id,
116 (ULONG)k_inq_vendor_id_len); /* Use case of memcpy is verified. */
117 _ux_utility_memory_copy(buf + UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_PRODUCT_ID,
118 storage->ux_slave_class_storage_product_id,
119 (ULONG)k_inq_product_id_len); /* Use case of memcpy is verified. */
120 _ux_utility_memory_copy(buf + UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_PRODUCT_REVISION,
121 storage->ux_slave_class_storage_product_rev,
122 (ULONG)k_inq_product_rev_len); /* Use case of memcpy is verified. */
123}
124
143{
144 buf[k_inq_off_page_code] = UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_STANDARD;
146 buf[k_inq_vpd0_first_off] = UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_STANDARD;
147 buf[k_inq_vpd0_second_off] = UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_SERIAL;
148 return (ULONG)k_inq_vpd0_len;
149}
150
169RA8_INTERNAL static ULONG internal_inquiry_fill_serial(UX_SLAVE_CLASS_STORAGE* storage, UCHAR* buf)
170{
171 _ux_utility_short_put_big_endian(buf, UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_SERIAL);
172 _ux_utility_short_put_big_endian(buf + k_inq_off_version, (USHORT)k_inq_serial_len);
173 _ux_utility_memory_copy(buf + k_inq_vpd_hdr_len,
174 storage->ux_slave_class_storage_product_serial,
175 (ULONG)k_inq_serial_len); /* Use case of memcpy is verified. */
177}
178
199RA8_INTERNAL static UINT
200internal_inquiry_reject(UX_SLAVE_CLASS_STORAGE* storage, ULONG lun, UX_SLAVE_ENDPOINT* endpoint_in)
201{
202#ifndef UX_DEVICE_STANDALONE
203 _ux_device_stack_endpoint_stall(endpoint_in);
204#else
205 UX_PARAMETER_NOT_USED(endpoint_in);
206#endif
207 storage->ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status =
208 UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_inq_sense_illegal,
211 storage->ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
212 return UX_ERROR;
213}
214
237RA8_INTERNAL static void internal_inquiry_send(UX_SLAVE_CLASS_STORAGE* storage,
238 UX_SLAVE_ENDPOINT* endpoint_in,
239 UX_SLAVE_TRANSFER* transfer_request,
240 ULONG inquiry_length)
241{
242#ifdef UX_DEVICE_STANDALONE
243 UX_PARAMETER_NOT_USED(endpoint_in);
244 storage->ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
245 storage->ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_READ;
246 storage->ux_device_class_storage_transfer = transfer_request;
247 storage->ux_device_class_storage_device_length = inquiry_length;
248 storage->ux_device_class_storage_data_length = inquiry_length;
249 storage->ux_device_class_storage_data_count = 0;
250#else
251 if (inquiry_length != 0U) {
252 _ux_device_stack_transfer_request(transfer_request, inquiry_length, inquiry_length);
253 }
254 if (storage->ux_slave_class_storage_host_length != inquiry_length) {
255 storage->ux_slave_class_storage_csw_residue =
256 storage->ux_slave_class_storage_host_length - inquiry_length;
257 _ux_device_stack_endpoint_stall(endpoint_in);
258 }
259#endif
260}
261
287UINT _ux_device_class_storage_inquiry(UX_SLAVE_CLASS_STORAGE* storage,
288 ULONG lun,
289 UX_SLAVE_ENDPOINT* endpoint_in,
290 UX_SLAVE_ENDPOINT* endpoint_out,
291 UCHAR* cbwcb)
292{
293 UX_PARAMETER_NOT_USED(endpoint_out);
294 UX_ASSERT(UX_SLAVE_REQUEST_DATA_MAX_LENGTH >= (ULONG)k_inq_serial_resp_len);
295 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_INQUIRY,
296 storage,
297 lun,
298 0,
299 0,
300 UX_TRACE_DEVICE_CLASS_EVENTS,
301 0,
302 0)
303
304#ifndef UX_DEVICE_STANDALONE
305 /* A data phase the host marked OUT cannot satisfy INQUIRY: phase error. */
306 if (storage->ux_slave_class_storage_host_length != 0U) {
307 if ((storage->ux_slave_class_storage_cbw_flags & (UCHAR)k_inq_dir_in_bit) == 0U) {
308 _ux_device_stack_endpoint_stall(endpoint_out);
309 storage->ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
310 return (UX_ERROR);
311 }
312 }
313#endif
314
315 UX_SLAVE_TRANSFER* transfer_request = &endpoint_in->ux_slave_endpoint_transfer_request;
316 UCHAR* buf = transfer_request->ux_slave_transfer_request_data_pointer;
317 const UCHAR evpd = (UCHAR)(cbwcb[k_inq_cdb_off_evpd] & (UCHAR)k_inq_cdb_evpd_bit);
318 const UCHAR page = cbwcb[UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE];
319 ULONG inquiry_length = storage->ux_slave_class_storage_host_length;
320
321 _ux_utility_memory_set(buf,
322 0,
323 UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH); /* Use case of memset is
324 verified. */
325 storage->ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED;
326
327 ULONG response_length = 0U;
328 if (evpd == 0U) {
329 /* Standard INQUIRY: SPC requires PAGE CODE = 0 when EVPD is clear. */
330 if (page != (UCHAR)UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_STANDARD) {
331 return internal_inquiry_reject(storage, lun, endpoint_in);
332 }
333 internal_inquiry_fill_standard(storage, lun, buf);
334 response_length = UX_SLAVE_CLASS_STORAGE_INQUIRY_RESPONSE_LENGTH;
335 } else if (page == (UCHAR)UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_STANDARD) {
336 response_length = internal_inquiry_fill_vpd_pages(buf);
337 } else if (page == (UCHAR)UX_SLAVE_CLASS_STORAGE_INQUIRY_PAGE_CODE_SERIAL) {
338 response_length = internal_inquiry_fill_serial(storage, buf);
339 } else {
340 return internal_inquiry_reject(storage, lun, endpoint_in);
341 }
342
343 if (inquiry_length > response_length) {
344 inquiry_length = response_length;
345 }
346
347 internal_inquiry_send(storage, endpoint_in, transfer_request, inquiry_length);
348 return (UX_SUCCESS);
349}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
static ULONG internal_inquiry_fill_vpd_pages(UCHAR *buf)
Fill the VPD page 0x00 (Supported VPD Pages) response.
static UINT internal_inquiry_reject(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in)
Reject an unsupported INQUIRY variant per the vendor contract.
UINT _ux_device_class_storage_inquiry(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UX_SLAVE_ENDPOINT *endpoint_in, UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb)
SCSI INQUIRY command handler (USBX storage class entry).
static void internal_inquiry_send(UX_SLAVE_CLASS_STORAGE *storage, UX_SLAVE_ENDPOINT *endpoint_in, UX_SLAVE_TRANSFER *transfer_request, ULONG inquiry_length)
Run the vendor transport tail: data IN + residue / IN stall.
static void internal_inquiry_fill_standard(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun, UCHAR *buf)
Fill the 36-byte standard INQUIRY response.
static ULONG internal_inquiry_fill_serial(UX_SLAVE_CLASS_STORAGE *storage, UCHAR *buf)
Fill the VPD page 0x80 (Unit Serial Number) response.
ra8_ux_inquiry_const_t
SCSI INQUIRY wire-format constants (SPC-4 sec 6.6).
@ k_inq_product_id_len
Product-identification field bytes.
@ k_inq_vpd_hdr_len
VPD header bytes before payload.
@ k_inq_vpd0_first_off
VPD page 0: first supported page.
@ k_inq_vpd0_second_off
VPD page 0: second supported page.
@ k_inq_serial_resp_len
VPD page 0x80 total response length.
@ k_inq_serial_len
Serial payload bytes (vendor size).
@ k_inq_format_spc
RESPONSE DATA FORMAT = 2 (SPC).
@ k_inq_vpd0_len
VPD page 0 total response length.
@ k_inq_addl_len_std
36-byte response: n - 5 = 31.
@ k_inq_format_cdrom
Vendor's CD-ROM format byte.
@ k_inq_version_spc2
VERSION = SPC-2 (SPC-4 table 142).
@ k_inq_sense_illegal
Sense key: ILLEGAL REQUEST.
@ k_inq_sense_ascq
ASCQ used by the vendor class.
@ k_inq_off_version
Standard response: VERSION byte.
@ k_inq_off_addl_len
Standard response: ADDITIONAL LENGTH.
@ k_inq_vpd0_count_off
VPD page 0: PAGE LENGTH byte.
@ k_inq_off_data_format
Standard response: RESPONSE FORMAT.
@ k_inq_vpd0_pages
Pages listed (0x00 + 0x80).
@ k_inq_cdb_evpd_bit
EVPD: vital-product-data request.
@ k_inq_cdb_off_evpd
CDB byte holding the EVPD flag.
@ k_inq_dir_in_bit
CBW bmCBWFlags: data IN direction.
@ k_inq_off_page_code
VPD response: PAGE CODE byte.
@ k_inq_sense_asc_field
ASC: INVALID FIELD IN PARAMETER.
@ k_inq_product_rev_len
Product-revision field bytes.
@ k_inq_vendor_id_len
Vendor-identification field bytes.