Beispiel #1
0
/* 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))) {
Beispiel #2
0
/*
 * 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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
/*
 * 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);
}
Beispiel #5
0
/*
 * 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);
}
Beispiel #6
0
/*
 * 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);
}
Beispiel #7
0
/*
 * 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);
}
Beispiel #8
0
/*
 * 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);
}