/* Requests on the control endpoint (aka EP0) */ static void ep0_rx(void) { uint16_t req = ep0_buf_rx[0]; /* bRequestType | bRequest */ /* interface specific requests */ if ((req & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { uint8_t iface = ep0_buf_rx[1] & 0xff; if (iface < USB_IFACE_COUNT) usb_iface_request[iface](ep0_buf_rx, ep0_buf_tx); return; } /* TODO check setup bit ? */ if (req == (USB_DIR_IN | (USB_REQ_GET_DESCRIPTOR << 8))) { uint8_t type = ep0_buf_rx[1] >> 8; uint8_t idx = ep0_buf_rx[1] & 0xff; const uint8_t *str_desc; switch (type) { case USB_DT_DEVICE: /* Setup : Get device descriptor */ memcpy_usbram(ep0_buf_tx, (void *)&dev_desc, sizeof(dev_desc)); btable_ep[0].tx_count = sizeof(dev_desc); STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT /*null OUT transaction */); break; case USB_DT_CONFIGURATION: /* Setup : Get configuration desc */ memcpy_usbram(ep0_buf_tx, __usb_desc, USB_DESC_SIZE); /* set the real descriptor size */ ep0_buf_tx[1] = USB_DESC_SIZE; btable_ep[0].tx_count = MIN(ep0_buf_rx[3], USB_DESC_SIZE); STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT /*null OUT transaction */); break; case USB_DT_STRING: /* Setup : Get string descriptor */ if (idx >= USB_STR_COUNT) { /* The string does not exist : STALL */ STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0); return; /* don't remove the STALL */ } str_desc = usb_strings[idx]; memcpy_usbram(ep0_buf_tx, str_desc, str_desc[0]); btable_ep[0].tx_count = MIN(ep0_buf_rx[3], str_desc[0]); STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT /*null OUT transaction */); break; case USB_DT_DEVICE_QUALIFIER: /* Get device qualifier desc */ /* Not high speed : STALL next IN used as handshake */ STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0); break; default: /* unhandled descriptor */ goto unknown_req; } } else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
/* * Required by SPC-4. */ static void scsi_report_luns(uint8_t *block, uint8_t in_len) { uint32_t response[16]; if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb6(block, in_len)) return; /* response exceeds allocation length */ if ((block[3] << 8 | block[4]) < sizeof(response)) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); memset(response, 0, sizeof(response)); /* one LUN in the list */ response[3] = 1; /* return response */ memcpy_usbram(ms_ep_tx, (uint8_t *) response, sizeof(response)); btable_ep[USB_EP_MS_TX].tx_count = sizeof(response); } else if (state == USB_MS_SCSI_STATE_DATA_OUT) state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }
static void scsi_mode_sense6(uint8_t *block, uint8_t in_len) { uint8_t response[4]; if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb6(block, in_len)) return; /* response exceeds allocation length */ if (block[4] < sizeof(response)) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); memset(response, 0, sizeof(response)); /* set WP bit if necessary */ response[2] = spi_flash_check_protect(0, CONFIG_SPI_FLASH_SIZE) ? (1 << 7) : 0; memcpy_usbram(ms_ep_tx, (uint8_t *) response, sizeof(response)); btable_ep[USB_EP_MS_TX].tx_count = sizeof(response); } else if (state == USB_MS_SCSI_STATE_DATA_OUT) state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }
/* * Used by UFI. Required by Windows XP. */ static void scsi_read_format_capacities(uint8_t *block, uint8_t in_len) { if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb10(block, in_len)) return; memcpy_usbram(ms_ep_tx, (uint8_t *) &scsi_capacity_list, sizeof(scsi_capacity_list)); btable_ep[USB_EP_MS_TX].tx_count = sizeof(scsi_capacity_list); } else if (state == USB_MS_SCSI_STATE_DATA_OUT) state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }
/* * Required by SPC-4. */ static void scsi_request_sense(uint8_t *block, uint8_t in_len) { uint8_t response[18]; if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb6(block, in_len)) return; /* response exceeds allocation length */ if (block[4] < sizeof(response)) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); memset(response, 0, sizeof(response)); /* Valid | Response Code */ response[0] = SCSI_SENSE_RESPONSE_CURRENT; /* Filemark | EOM | ILI | SDAT_OVFL | Sense Key */ response[2] = scsi_sense_data.key; /* Additional Sense Length */ response[7] = ARRAY_SIZE(response) - 7; /* Additional Sense Code */ response[12] = scsi_sense_data.ASC; /* Additional Sense Code Qualifier */ response[13] = scsi_sense_data.ASCQ; /* return fixed format sense data */ memcpy_usbram(ms_ep_tx, response, sizeof(response)); btable_ep[USB_EP_MS_TX].tx_count = sizeof(response); } else if (state == USB_MS_SCSI_STATE_DATA_OUT) state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }
/* * Required by SPC-4. */ static void scsi_read_capacity10(uint8_t *block, uint8_t in_len) { uint32_t response[2]; if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb10(block, in_len)) return; /* RELADR bit not supported */ if (block[1] & 0x1) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); /* PMI bit or LBA not supported */ if (block[2] | block[3] | block[4] | block[5] | (block[8] & 0x1)) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); /* compute LBA and block size, send in big endian */ response[0] = __builtin_bswap32((CONFIG_SPI_FLASH_SIZE / SCSI_BLOCK_SIZE_BYTES) - 1); response[1] = __builtin_bswap32(SCSI_BLOCK_SIZE_BYTES); memcpy_usbram(ms_ep_tx, (uint8_t *) response, sizeof(response)); btable_ep[USB_EP_MS_TX].tx_count = sizeof(response); } else if (state == USB_MS_SCSI_STATE_DATA_OUT) state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }
/* * Required by SPC-4. */ static void scsi_read10(uint8_t *block, uint8_t in_len) { int rv; int read_len; if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb10(block, in_len)) return; /* RELADR bit not supported */ if (block[1] & 0x1) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); offset = SCSI_BLOCK_SIZE_BYTES * (block[2] << 24 | block[3] << 16 | block[4] << 8 | block[5]); bytes = SCSI_BLOCK_SIZE_BYTES * (block[7] << 8 | block[8]); /* Wait for any previous operation to complete */ rv = spi_flash_wait(); if (rv == EC_ERROR_TIMEOUT) return scsi_sense_code( SCSI_SENSE_HARDWARE_ERROR, SCSI_SENSE_CODE_TIMEOUT); } if (state == USB_MS_SCSI_STATE_DATA_OUT) { /* nothing left to read */ if (!bytes) { state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); } /* read in multiples of USB_MS_PACKET_SIZE, then bytes */ read_len = MIN(bytes, USB_MS_PACKET_SIZE); rv = spi_flash_read(temp_buf, offset, read_len); /* invalid address */ if (rv == EC_ERROR_INVAL) return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_LBA_OUT_OF_RANGE); else if (rv != EC_SUCCESS) return scsi_sense_code(SCSI_SENSE_HARDWARE_ERROR, SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR); /* temp buffer for chip addressing issues */ memcpy_usbram(ms_ep_tx, temp_buf, read_len); offset += read_len; bytes -= read_len; btable_ep[USB_EP_MS_TX].tx_count = read_len; } return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }
/* * Required by SPC-4. */ static void scsi_inquiry(uint8_t *block, uint8_t in_len) { if (state == USB_MS_SCSI_STATE_PARSE) { state = USB_MS_SCSI_STATE_DATA_OUT; /* terminate if fail to verify */ if (scsi_verify_cdb6(block, in_len)) return; /* EVPD bit set */ if (block[1] & 0x1) { /* lookup VPD page */ switch (block[2]) { case SCSI_VPD_CODE_SUPPORTED_PAGES: /* return supported pages */ memcpy_usbram(ms_ep_tx, scsi_vpd_supported_pages, sizeof(scsi_vpd_supported_pages)); /* truncate response */ btable_ep[USB_EP_MS_TX].tx_count = MIN(block[3] << 8 | block[4], sizeof(scsi_vpd_supported_pages)); break; case SCSI_VPD_CODE_SERIAL_NUMBER: /* return serial number response */ memcpy_usbram(ms_ep_tx, scsi_vpd_serial_number, sizeof(scsi_vpd_serial_number)); /* copy STM32 LOT_NUM for serial number */ memcpy(temp_buf, ((uint8_t *) STM32_UNIQUE_ID) + 4 + 1, 7 * sizeof(uint8_t)); /* copy STM32 WAF_NUM for serial number */ temp_buf[7] = ((uint8_t *) STM32_UNIQUE_ID)[4]; /* copy STM32 UID for serial number */ memcpy(temp_buf + 8, ((uint8_t *) STM32_UNIQUE_ID), 4 * sizeof(uint8_t)); /* copy actual serial number */ memcpy_usbram((usb_uint *) (((uint8_t *) ms_ep_tx) + 4), temp_buf, 12 * sizeof(uint8_t)); /* truncate response */ btable_ep[USB_EP_MS_TX].tx_count = MIN(block[3] << 8 | block[4], sizeof(scsi_vpd_serial_number)); break; case SCSI_VPD_CODE_DEVICE_ID: /* return device id */ memcpy_usbram(ms_ep_tx, scsi_vpd_device_id, sizeof(scsi_vpd_device_id)); /* truncate response */ btable_ep[USB_EP_MS_TX].tx_count = MIN(block[3] << 8 | block[4], sizeof(scsi_vpd_device_id)); break; default: /* not supported */ return scsi_sense_code( SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); break; } /* EVPD not set but page code set */ } else if (block[2]) { return scsi_sense_code( SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB); } else { /* return standard inquiry data */ memcpy_usbram(ms_ep_tx, scsi_standard_inquiry, sizeof(scsi_standard_inquiry)); /* copy STM32 LOT_NUM for vendor specific id */ memcpy_usbram((usb_uint *) (((uint8_t *) ms_ep_tx) + 24), ((uint8_t *) STM32_UNIQUE_ID) + 4 + 1, 7 * sizeof(uint8_t)); /* truncate response */ btable_ep[USB_EP_MS_TX].tx_count = MIN(block[3] << 8 | block[4], sizeof(scsi_standard_inquiry)); } } else if (state == USB_MS_SCSI_STATE_DATA_OUT) state = USB_MS_SCSI_STATE_REPLY; return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE); }