This patch includes the tests that should be compiled with the GoogleTest framework. Signed-off-by: Tatyana Brokhman <tlinder@xxxxxxxxxxxxxx> --- tools/usb/unittests/make/Makefile | 132 ++ tools/usb/unittests/make/autoconfig.sh | 118 ++ tools/usb/unittests/usb/UASP_CMD_tests.cc | 2140 ++++++++++++++++++++++++++++ tools/usb/unittests/usb/UASP_TM_tests.cc | 1207 ++++++++++++++++ tools/usb/unittests/usb/UASP_tests.h | 434 ++++++ tools/usb/unittests/usb/composite_tests.cc | 1646 +++++++++++++++++++++ tools/usb/unittests/usb/composite_tests.h | 65 + tools/usb/unittests/usb/g_serial_tests.cc | 198 +++ tools/usb/unittests/usb/g_serial_tests.h | 68 + tools/usb/unittests/usb/hs_expected_desc.h | 164 +++ tools/usb/unittests/usb/libusb_utils.cc | 358 +++++ tools/usb/unittests/usb/libusb_utils.h | 149 ++ tools/usb/unittests/usb/ss_expected_desc.h | 291 ++++ tools/usb/unittests/usb/streams_tests.cc | 243 ++++ tools/usb/unittests/usb/streams_tests.h | 51 + tools/usb/unittests/usb/usb_devel_mode.cc | 185 +++ tools/usb/unittests/usb/usb_devel_mode.h | 50 + tools/usb/unittests/usb/usb_tests.cc | 651 +++++++++ tools/usb/unittests/usb/usb_tests.h | 146 ++ tools/usb/unittests/usb/usb_tests_main.cc | 83 ++ tools/usb/unittests/usb/ut_config.h | 89 ++ 21 files changed, 8468 insertions(+), 0 deletions(-) create mode 100644 tools/usb/unittests/make/Makefile create mode 100644 tools/usb/unittests/make/autoconfig.sh create mode 100644 tools/usb/unittests/usb/UASP_CMD_tests.cc create mode 100644 tools/usb/unittests/usb/UASP_TM_tests.cc create mode 100644 tools/usb/unittests/usb/UASP_tests.h create mode 100644 tools/usb/unittests/usb/composite_tests.cc create mode 100644 tools/usb/unittests/usb/composite_tests.h create mode 100644 tools/usb/unittests/usb/g_serial_tests.cc create mode 100644 tools/usb/unittests/usb/g_serial_tests.h create mode 100644 tools/usb/unittests/usb/hs_expected_desc.h create mode 100644 tools/usb/unittests/usb/libusb_utils.cc create mode 100644 tools/usb/unittests/usb/libusb_utils.h create mode 100644 tools/usb/unittests/usb/ss_expected_desc.h create mode 100644 tools/usb/unittests/usb/streams_tests.cc create mode 100644 tools/usb/unittests/usb/streams_tests.h create mode 100644 tools/usb/unittests/usb/usb_devel_mode.cc create mode 100644 tools/usb/unittests/usb/usb_devel_mode.h create mode 100644 tools/usb/unittests/usb/usb_tests.cc create mode 100644 tools/usb/unittests/usb/usb_tests.h create mode 100644 tools/usb/unittests/usb/usb_tests_main.cc create mode 100644 tools/usb/unittests/usb/ut_config.h diff --git a/tools/usb/unittests/make/Makefile b/tools/usb/unittests/make/Makefile new file mode 100644 index 0000000..3f4986e --- /dev/null +++ b/tools/usb/unittests/make/Makefile @@ -0,0 +1,132 @@ +# A Makefile for building Google Test and USB30 tests. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. +# +# Befor building the code the folowing env. variables needs to be set: +# GTEST - Pointer to the root of Google Tests +# KERNEL - Pointer to the Kernel code the test are about to be ran on +# + +# Points to the root of Google Test, relative to where this file is. +GTEST_DIR = $(GTEST) + +# Where to find usb tests code. +USER_DIR = ../usb + +# Where to find kernel code. +KERNEL_DIR = $(KERNEL) + +USB_INC_DIR = $(KERNEL_DIR)/include/linux/usb + +LINUX_INC_DIR = $(KERNEL_DIR)/arch/x86/include/asm + +# Flags passed to the preprocessor. +CPPFLAGS += -I$(GTEST_DIR) -I$(GTEST_DIR)/include -I$(LIBUSB_INC) +CPPFLAGS += -I$(KERNEL_DIR)/include +#CPPFLAGS += -I$(KERNEL_DIR)/arch/x86/include + +# Flags passed to the C++ compiler. +CXXFLAGS += -g -Wall -Wextra -m32 + +LIBUSB_LIB = $(LIBUSB)/lib +LFLAGS = -L/usr/lib32 -lstdc++ -L$(LIBUSB_LIB) -lusb-1.0 -lpthread + +# All tests produced by this Makefile. Remember to add new tests you +# created to the list. +TESTS = usb_tests + + +# All Google Test headers. Usually you shouldn't change this +# definition. +GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ + $(GTEST_DIR)/include/gtest/internal/*.h + + +KERNEL_HEADERS = $(USB_INC_DIR)/*.h + + +LIBUSB_INC = $(LIBUSB)/include/libusb-1.0 +LIBUSB_HEADERS = $(LIBUSB_INC)/libusb.h + +# House-keeping build targets. + +all : $(TESTS) + +clean : + rm -f $(TESTS) gtest.a gtest_main.a *.o + +# Builds gtest.a and gtest_main.a. + +# Usually you shouldn't tweak such internal variables, indicated by a +# trailing _. +GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) + +# For simplicity and to avoid depending on Google Test's +# implementation details, the dependencies specified below are +# conservative and not optimized. This is fine as Google Test +# compiles fast and for ordinary users its source rarely changes. +gtest-all.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest-all.cc + +gtest_main.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest_main.cc + +gtest.a : gtest-all.o + $(AR) $(ARFLAGS) $@ $^ + +gtest_main.a : gtest-all.o gtest_main.o + $(AR) $(ARFLAGS) $@ $^ + +# Builds a sample test. A test should link with either gtest.a or +# gtest_main.a, depending on whether it defines its own main() +# function. + +libusb_utils.o : $(USER_DIR)/libusb_utils.cc \ + $(USER_DIR)/libusb_utils.h $(KERNEL_HEADERS) \ + $(GTEST_HEADERS) $(LIBUSB_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/libusb_utils.cc + +composite_tests.o : $(USER_DIR)/composite_tests.cc \ + $(USER_DIR)/composite_tests.h $(KERNEL_HEADERS) \ + $(GTEST_HEADERS) $(LIBUSB_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/composite_tests.cc + +g_serial_tests.o : $(USER_DIR)/g_serial_tests.cc \ + $(USER_DIR)/g_serial_tests.h $(KERNEL_HEADERS) \ + $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/g_serial_tests.cc + +streams_tests.o : $(USER_DIR)/streams_tests.cc \ + $(USER_DIR)/streams_tests.h $(KERNEL_HEADERS) \ + $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/streams_tests.cc + +UASP_CMD_tests.o : $(USER_DIR)/UASP_CMD_tests.cc \ + $(USER_DIR)/UASP_tests.h $(KERNEL_HEADERS) \ + $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/UASP_CMD_tests.cc + + +UASP_TM_tests.o : $(USER_DIR)/UASP_TM_tests.cc \ + $(USER_DIR)/UASP_tests.h $(KERNEL_HEADERS) \ + $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/UASP_TM_tests.cc + +usb_tests.o : $(USER_DIR)/usb_tests.cc $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/usb_tests.cc + +usb_tests_main.o : $(USER_DIR)/usb_tests_main.cc $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/usb_tests_main.cc + +usb_devel_mode.o : $(USER_DIR)/usb_devel_mode.cc $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/usb_devel_mode.cc + +usb_tests : g_serial_tests.o usb_tests.o usb_tests_main.o gtest.a \ + composite_tests.o libusb_utils.o usb_devel_mode.o UASP_CMD_tests.o \ + UASP_TM_tests.o streams_tests.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LFLAGS) $^ -o $@ + diff --git a/tools/usb/unittests/make/autoconfig.sh b/tools/usb/unittests/make/autoconfig.sh new file mode 100644 index 0000000..b8e90ff --- /dev/null +++ b/tools/usb/unittests/make/autoconfig.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# A Script to configure the kernel .config file + +cat .config | sed -e 's/# CONFIG_BLK_DEV_INITRD is not set/CONFIG_BLK_DEV_INITRD=y/' > .config.new +cp .config.new .config +cat .config | sed -e 's/# CONFIG_EXT2_FS is not set/CONFIG_EXT2_FS=y\ +# CONFIG_EXT2_FS_XATTR is not set\ +# CONFIG_EXT2_FS_XIP is not set/' > .config.new +cp .config.new .config +cat .config | sed -e 's/# CONFIG_DEBUG_INFO is not set/CONFIG_DEBUG_INFO=y/' > .config.new +cp .config.new .config +cat .config | sed -e 's/# CONFIG_USB_GADGET is not set/CONFIG_USB_GADGET=m\ +CONFIG_USB_GADGET_DEBUG=y\ +CONFIG_USB_GADGET_DEBUG_FILES=y\ +CONFIG_USB_GADGET_DEBUG_FS=y\ +CONFIG_USB_GADGET_DEBUG_MODULE_LOAD=y\ +CONFIG_USB_GADGET_VBUS_DRAW=2\ +CONFIG_USB_GADGET_SELECTED=y\ +CONFIG_USB_GADGET_DUMMY_HCD=y\ +CONFIG_USB_DUMMY_HCD=m\ +CONFIG_USB_GADGET_DUALSPEED=y\ +CONFIG_USB_ZERO=m\ +CONFIG_USB_AUDIO=m\ +CONFIG_USB_ETH=m\ +CONFIG_USB_ETH_RNDIS=y\ +CONFIG_USB_ETH_EEM=y\ +CONFIG_USB_GADGETFS=m\ +CONFIG_USB_FILE_STORAGE=m\ +CONFIG_USB_FILE_STORAGE_TEST=y\ +CONFIG_USB_MASS_STORAGE=m\ +CONFIG_USB_G_SERIAL=m\ +CONFIG_USB_MIDI_GADGET=m\ +CONFIG_USB_G_PRINTER=m\ +CONFIG_USB_CDC_COMPOSITE=m\ +CONFIG_USB_G_MULTI=m\ +CONFIG_USB_G_MULTI_RNDIS=y\ +CONFIG_USB_G_MULTI_CDC=y\ +# CONFIG_USB_GADGET_AT91 is not set\ +# CONFIG_USB_GADGET_ATMEL_USBA is not set\ +# CONFIG_USB_GADGET_FSL_USB2 is not set\ +# CONFIG_USB_GADGET_LH7A40X is not set\ +# CONFIG_USB_GADGET_OMAP is not set\ +# CONFIG_USB_GADGET_PXA25X is not set\ +# CONFIG_USB_GADGET_R8A66597 is not set\ +# CONFIG_USB_GADGET_PXA27X is not set\ +# CONFIG_USB_GADGET_S3C_HSOTG is not set\ +# CONFIG_USB_GADGET_IMX is not set\ +# CONFIG_USB_GADGET_S3C2410 is not set\ +# CONFIG_USB_GADGET_M66592 is not set\ +# CONFIG_USB_GADGET_AMD5536UDC is not set\ +# CONFIG_USB_GADGET_FSL_QE is not set\ +# CONFIG_USB_GADGET_CI13XXX is not set\ +# CONFIG_USB_GADGET_NET2280 is not set\ +# CONFIG_USB_GADGET_GOKU is not set\ +# CONFIG_USB_GADGET_LANGWELL is not set/' > .config.new +cp .config.new .config + +cat .config | sed -e 's/# CONFIG_USB_ACM is not set/CONFIG_USB_ACM=y/' > .config.new +cp .config.new .config +cat .config | sed -e 's/# CONFIG_USB_STORAGE_DEBUG is not set/CONFIG_USB_STORAGE_DEBUG=y/' > .config.new +cp .config.new .config +cat .config | sed -e 's/# CONFIG_USB_SERIAL is not set/CONFIG_USB_SERIAL=y\ +CONFIG_USB_SERIAL_CONSOLE=y\ +# CONFIG_USB_EZUSB is not set\ +CONFIG_USB_SERIAL_GENERIC=y\ +# CONFIG_USB_SERIAL_AIRCABLE is not set\ +# CONFIG_USB_SERIAL_ARK3116 is not set\ +# CONFIG_USB_SERIAL_BELKIN is not set\ +# CONFIG_USB_SERIAL_CH341 is not set\ +# CONFIG_USB_SERIAL_WHITEHEAT is not set\ +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set\ +# CONFIG_USB_SERIAL_CP210X is not set\ +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set\ +# CONFIG_USB_SERIAL_EMPEG is not set\ +# CONFIG_USB_SERIAL_FTDI_SIO is not set\ +# CONFIG_USB_SERIAL_FUNSOFT is not set\ +# CONFIG_USB_SERIAL_VISOR is not set\ +# CONFIG_USB_SERIAL_IPAQ is not set\ +# CONFIG_USB_SERIAL_IR is not set\ +# CONFIG_USB_SERIAL_EDGEPORT is not set\ +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set\ +# CONFIG_USB_SERIAL_GARMIN is not set\ +# CONFIG_USB_SERIAL_IPW is not set\ +# CONFIG_USB_SERIAL_IUU is not set\ +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set\ +# CONFIG_USB_SERIAL_KEYSPAN is not set\ +# CONFIG_USB_SERIAL_KLSI is not set\ +# CONFIG_USB_SERIAL_KOBIL_SCT is not set\ +# CONFIG_USB_SERIAL_MCT_U232 is not set\ +# CONFIG_USB_SERIAL_MOS7720 is not set\ +# CONFIG_USB_SERIAL_MOS7840 is not set\ +# CONFIG_USB_SERIAL_MOTOROLA is not set\ +# CONFIG_USB_SERIAL_NAVMAN is not set\ +# CONFIG_USB_SERIAL_PL2303 is not set\ +# CONFIG_USB_SERIAL_OTI6858 is not set\ +# CONFIG_USB_SERIAL_QCAUX is not set\ +# CONFIG_USB_SERIAL_QUALCOMM is not set\ +# CONFIG_USB_SERIAL_SPCP8X5 is not set\ +# CONFIG_USB_SERIAL_HP4X is not set\ +# CONFIG_USB_SERIAL_SAFE is not set\ +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set\ +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set\ +# CONFIG_USB_SERIAL_SYMBOL is not set\ +# CONFIG_USB_SERIAL_TI is not set\ +# CONFIG_USB_SERIAL_CYBERJACK is not set\ +# CONFIG_USB_SERIAL_XIRCOM is not set\ +# CONFIG_USB_SERIAL_OPTION is not set\ +# CONFIG_USB_SERIAL_OMNINET is not set\ +# CONFIG_USB_SERIAL_OPTICON is not set\ +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set\ +# CONFIG_USB_SERIAL_DEBUG is not set/' > .config.new +cp .config.new .config + +cat .config | sed -e 's/# CONFIG_USB_XHCI_HCD is not set/CONFIG_USB_XHCI_HCD=y\ +CONFIG_USB_XHCI_HCD_DEBUGGING=y/' > .config.new +cp .config.new .config + +echo "DONE! Configured: CONFIG_USB_DUMMY_HCD=y" \ No newline at end of file diff --git a/tools/usb/unittests/usb/UASP_CMD_tests.cc b/tools/usb/unittests/usb/UASP_CMD_tests.cc new file mode 100644 index 0000000..066219e --- /dev/null +++ b/tools/usb/unittests/usb/UASP_CMD_tests.cc @@ -0,0 +1,2140 @@ +/* + * UASP_CMD_tests.cc - The tests in this file test the UASP COMMAND IUs + * handling. This file implements test to be run on a UASP supporting device. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include "UASP_tests.h" +#include "usb_tests.h" +#include "usb_devel_mode.h" + +unsigned char reference_buf[1024] = +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference -\n" +"reference reference reference reference 0\n"; + + +/* + * verify_sense_iu() - prints and verifies the received sense_iu structure + * @buf: pointer to the sense_iu to print + * @length: size of the buf param + * + * Returns 0 if the status = STATUS_GOOD + * 1 if the sense data is SS_OVERLAPPED_COMMANDS_ATTEMPTED + * -1 otherwise + */ +static int verify_sense_iu(unsigned char *buf, int length) +{ + struct sense_iu *status_iu = (struct sense_iu *)buf; + unsigned long sense_data; + int rc = 0; + + if (length != sizeof(struct sense_iu)) { + printf("verify_sense_iu(): length (%d) != status_iu size (%d)\n", + length, sizeof(struct sense_iu)); + return -1; + } + + if (status_iu->iu_id != IU_ID_SENSE) { + printf("verify_sense_iu(): status_iu->iu_id != IU_ID_SENSE\n"); + return -1; + } + + switch (status_iu->status) { + case STATUS_GOOD: + printf(" Status received = STATUS_GOOD\n"); + break; + case STATUS_CHECK_CONDITION: + printf(" Status received = STATUS_CHECK_CONDITION"); + break; + case STATUS_CONDITION_MET: + printf(" Status received = STATUS_CONDITION_MET"); + break; + case STATUS_BUSY: + printf(" Status received = STATUS_BUSY"); + break; + case STATUS_RESERVATION_CONFLICT: + printf(" Status received = STATUS_RESERVATION_CONFLICT"); + break; + case STATUS_TASK_SET_FULL: + printf(" Status received = STATUS_TASK_SET_FULL"); + break; + case STATUS_ACA_ACTIVE: + printf(" Status received = STATUS_ACA_ACTIVE"); + break; + case STATUS_TASK_ABORTED: + printf(" Status received = STATUS_TASK_ABORTED"); + break; + default: + printf(" ERROR: Unknown status code!"); + } + if (status_iu->status) { + /* Print the SENSE data*/ + rc = -1; + sense_data = status_iu->sense_data[0] << 16 | + status_iu->sense_data[1] << 8 | + status_iu->sense_data[2]; + switch (sense_data) { + case SS_COMMUNICATION_FAILURE: + printf(" SENSE DATA = SS_COMMUNICATION_FAILURE\n"); + break; + case SS_INVALID_COMMAND: + printf(" SENSE DATA = SS_INVALID_COMMAND\n"); + break; + case SS_INVALID_FIELD_IN_CDB: + printf(" SENSE DATA = SS_INVALID_FIELD_IN_CDB\n"); + break; + case SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE: + printf(" SENSE DATA = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE\n"); + break; + case SS_LOGICAL_UNIT_NOT_SUPPORTED: + printf(" SENSE DATA = SS_LOGICAL_UNIT_NOT_SUPPORTED\n"); + break; + case SS_MEDIUM_NOT_PRESENT: + printf(" SENSE DATA = SS_MEDIUM_NOT_PRESENT\n"); + break; + case SS_MEDIUM_REMOVAL_PREVENTED: + printf(" SENSE DATA = SS_MEDIUM_REMOVAL_PREVENTED\n"); + break; + case SS_NOT_READY_TO_READY_TRANSITION: + rc = 0; + printf(" SENSE DATA = SS_NOT_READY_TO_READY_TRANSITION\n"); + break; + case SS_RESET_OCCURRED: + printf(" SENSE DATA = SS_RESET_OCCURRED\n"); + break; + case SS_SAVING_PARAMETERS_NOT_SUPPORTED: + printf(" SENSE DATA = SS_SAVING_PARAMETERS_NOT_SUPPORTED\n"); + break; + case SS_UNRECOVERED_READ_ERROR: + printf(" SENSE DATA = SS_UNRECOVERED_READ_ERROR\n"); + break; + case SS_WRITE_ERROR: + printf(" SENSE DATA = SS_WRITE_ERROR\n"); + break; + case SS_WRITE_PROTECTED: + printf(" SENSE DATA = SS_WRITE_PROTECTED\n"); + break; + case SS_OVERLAPPED_COMMANDS_ATTEMPTED: + printf(" SENSE DATA = SS_OVERLAPPED_COMMANDS_ATTEMPTED\n"); + return 1; + default: + printf(" ERROR: Unrecognized sense data!\n"); + } + printf(" (Press Enter to continue...)"); + (void)getchar(); + } + return rc; +} + +/** + * print_cmdiu() - print the received command iu + * @cmdiu: pointer to the cmd_iu to print + * + */ +static void print_cmdiu(struct cmd_iu *cmdiu) +{ + printf("\ncmdiu->iu_id [%d] = %02x, \n" + "cmdiu->reserved [%d] = %02x, \n" + "cmdiu->ipt_tag [%d] = %d, \n" + "cmdiu->forth_byte [%d] = %02x, \n" + "cmdiu->reserved5 [%d] = %02x, \n" + "cmdiu->length [%d] = %02x, \n" + "cmdiu->reserved7 [%d] = %02x, \n" + "cmdiu->lun[8] = \n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n" + "cmdiu->cdb[16] = \n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + sizeof(cmdiu->iu_id), cmdiu->iu_id, + sizeof(cmdiu->reserved), cmdiu->reserved, + sizeof(cmdiu->tag), cmdiu->tag, + sizeof(cmdiu->b), cmdiu->b, + sizeof(cmdiu->reserved5), cmdiu->reserved5, + sizeof(cmdiu->length), cmdiu->length, + sizeof(cmdiu->reserved7), cmdiu->reserved7, + cmdiu->lun[0], cmdiu->lun[1], cmdiu->lun[2], cmdiu->lun[3], + cmdiu->lun[4], cmdiu->lun[5], cmdiu->lun[6], cmdiu->lun[7], + cmdiu->cdb[0], cmdiu->cdb[1], cmdiu->cdb[2], cmdiu->cdb[3], + cmdiu->cdb[4], cmdiu->cdb[5], cmdiu->cdb[6], cmdiu->cdb[7], + cmdiu->cdb[8], cmdiu->cdb[9], cmdiu->cdb[10], cmdiu->cdb[11], + cmdiu->cdb[12], cmdiu->cdb[13], cmdiu->cdb[14], cmdiu->cdb[15]); +} + +/** + * fill_cmd_iu() - Fills the command iu structure with given values + * @iu: pointer to the cmd_iu structure to fill + * @cdb_opcode: OpCode of the CDB to send + * @lun: LUN number + * @add_length: additional_length field of the CDB + * + */ +void fill_cmd_iu(struct cmd_iu *iu, u8 cdb_opcode, u8 lun, u8 add_length) +{ + memset((void *)iu, 0 ,sizeof(struct cmd_iu)); + iu->iu_id = 0x01; /* Command iu*/ + iu->reserved = 0; + iu->tag = get_next_ip_tag(); + memset(&iu->b,0,sizeof(iu->b)); + iu->reserved5 = 0; + iu->length = 6; + + memset(iu->lun, 0, 8); + iu->lun[0] = lun; /* Workaround: Right now @init we set lun_id[0] = i */ + iu->cdb[0] = cdb_opcode; + iu->cdb[1] = 0; + iu->cdb[2] = 0; + iu->cdb[3] = 0; + iu->cdb[4] = add_length; + iu->cdb[5] = 0; +} + +/** + * receive_read_iu() - Reads a READ IU from the device. + * @udev: handle of the libusb device + * @sts: pointer to the status endpoint descriptor + * + * Used when opperating in HS mode for DATA IN commands. In SS + * mode replaced by ERDY. + * + * Return 0 on success, -1 otherwise + */ +static int receive_read_iu(struct libusb_device_handle *udev, + struct libusb_endpoint_descriptor *sts, + u16 tag) +{ + unsigned char buf[1024]; + int transferred; + int ret; + + if (!udev || !sts) + return -1; + + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + UASP_SIZEOF_RW_READY_IU, + &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + return -1; + } + /* Verify the tag */ + if (((struct rw_ready_iu*)buf)->tag != tag || + ((struct rw_ready_iu*)buf)->iu_id != IU_ID_READ_READY) { + printf(" ERROR: Received Incorrect IU!!!" + " (iu_id = %d, tag = %d, expected_tag = %d)\n\n", + ((struct rw_ready_iu*)buf)->iu_id, + ((struct rw_ready_iu*)buf)->tag, tag); + return -1; + } + return 0; +} + +/** + * exec_send_mode_sense10() - Test the MODE_SENSE10 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the MODE_SENSE10 SCSI command to the device and verifies + * the correct reply from it. + * It consists of several tests (according to the fields of the + * MODE_SENSE10 CDB) : + * - First test case: + * page code = 0x08 (cashing) + * pc = 0 (page control = return current values) + * - Second test case: + * page code = 0x08 (cashing) + * pc = 01 (page control = return changable values) + * + * Return 0 on success, -1 otherwise + */ +int exec_send_mode_sense10(struct libusb_device *dev) +{ + struct cmd_iu modes_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + uint8_t buf[1024]; + int transferred; + int ret = -1; + + /* + * First test case: + * page code = 0x08 (cashing) + * pc = 0 (page control = return current values) + * + * Expected reply: + * buf[0-1] - len -2 = 18 = 0x00, 0x12 + * buf[3] = (curlun->lun->ro ? 0x80 : 0x00) = 0x00 + * buf[8] = 0x08 Page code + * buf[9] = 0x0a Page length + * buf[10] = 0x04 Write cache enable, Read cache not disabled, + * No cache retention priorities + * buf[12]-buf[13] = 0xffff Don't disable prefetch + * buf[14-15] = 0x00 Minimum prefetch = 0 + * buf[16-19] =0xffff, 0xffff Maximum prefetch ceiling + * reply length = 20 + */ + uint8_t expected_buf_t1[20] = {0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x08, 0x0a, 0x04, 0x00, + 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff}; + /* + * Second test case: + * page code = 0x08 (cashing) + * pc = 01 (page control = return changable values) + * + * expected reply: + * buf[0-1] - len -2 = 18 = 0x00, 0x12 + * buf[3] = (curlun->lun->ro ? 0x80 : 0x00); = 0x00 + * buf[8] = 0x08 Page code + * buf[9] = 0x0a Page length + * buf[10-19] = 0x00 + * reply length = 20 + */ + uint8_t expected_buf_t2[20] = {0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x08, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_send_mode_sense10_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_send_mode_sense10_done; + } + memset(buf, 0, 1024); + + fill_cmd_iu(&modes_iu, 0x5a, UASP_LUN_NUM, 0x10); + + /* First test case: */ + /* Fill aditional cdb fields */ + modes_iu.cdb[2] = 0x08; /* page code = cashing, pc = 0 */ + printf("First test case: page code = 0x08 (cashing)\n" + " pc = 0 (page controll = return current " + "values)\n"); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&modes_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_mode_sense10_done; + } + + memset(buf, 0, 1024); + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, modes_iu.tag)) + goto exec_send_mode_sense10_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 20, &transferred, 2000); + + if (memcmp(buf, expected_buf_t1, 20)) + printf(" ERROR ocured! Received incorrect reply!\n" + " buf = %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x,\n" + " %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_send_mode_sense10_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_send_mode_sense10_done; + + /* Second test case: */ + /* Fill aditional cdb fields */ + modes_iu.cdb[2] = 0x48; /* page code = cashing, pc = 1 */ + printf("Second test case: page code = 0x08 (cashing)\n" + " pc = 1 (page controll = return changble " + "values)\n"); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&modes_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_mode_sense10_done; + } + + memset(buf, 0, 1024); + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, modes_iu.tag)) + goto exec_send_mode_sense10_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 20, &transferred, 2000); + + if (memcmp(buf, expected_buf_t2, 20)) + printf(" ERROR ocured! Received incorrect reply!\n" + " buf = %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x,\n" + " %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_send_mode_sense10_done: + libusb_close(udev); + return ret; +} + +/** + * exec_send_mode_sense() - Test the MODE_SENSE(6) SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the MODE_SENSE(6) SCSI command to the device and + * verifies the correct reply from it. + * It consists of several tests (according to the fields of the MODE_SENSE CDB): + * - First test case: + * page code = 0x08 (cashing) + * pc = 0 (page control = return current values) + * - Second test case: + * page code = 0x08 (cashing) + * pc = 01 (page control = return changable values) + * + * Return 0 on success, -1 otherwise + */ +int exec_send_mode_sense(struct libusb_device *dev) +{ + struct cmd_iu modes_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + uint8_t buf[1024]; + int transferred; + int ret = -1; + + /* + * First test case: + * page code = 0x08 (cashing) + * pc = 0 (page control = return current values) + * + * Expected reply: + * buf[0] - len -1 = 15 + * buf[2] = (curlun->lun->ro ? 0x80 : 0x00); = 0x00 + * buf[4] = 0x08 Page code + * buf[5] = 0x0a Page length + * buf[6] = 0x04 Write cache enable, Read cache not disabled, + * No cache retention priorities + * buf[8]-buf[9] = 0xffff Don't disable prefetch + * buf[10-11] = 0x00 Minimum prefetch = 0 + * buf[12-15] =0xffff, 0xffff Maximum prefetch ceiling + * reply length = 16 + */ + uint8_t expected_buf_t1[16] = {0x0f, 0x00, 0x00, 0x00, + 0x08, 0x0a, 0x04, 0x00, + 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff}; + /* + * Second test case: + * page code = 0x08 (cashing) + * pc = 01 (page control = return changable values) + * + * Expected reply: + * buf[0] - len -1 = 15 + * buf[2] = (curlun->lun->ro ? 0x80 : 0x00); = 0x00 + * buf[4] = 0x08 Page code + * buf[5] = 0x0a Page length + * buf[6-15] = 0x00 + * reply length = 16 + */ + uint8_t expected_buf_t2[16] = {0x0f, 0x00, 0x00, 0x00, + 0x08, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_send_mode_sense_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_send_mode_sense_done; + } + memset(buf, 0, 1024); + + fill_cmd_iu(&modes_iu, 0x1a, UASP_LUN_NUM, 0x10); + + /* First test case: */ + /* Fill aditional cdb fields */ + modes_iu.cdb[2] = 0x08; /* page code = cashing, pc = 0 */ + printf("First test case: page code = 0x08 (cashing)\n" + " pc = 0 (page controll = return current " + "values)\n"); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&modes_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_mode_sense_done; + } + + memset(buf, 0, 1024); + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, modes_iu.tag)) + goto exec_send_mode_sense_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 16, &transferred, 2000); + + if (memcmp(buf, expected_buf_t1, 16)) + printf(" ERROR ocured! Received incorrect reply!\n" + " buf = %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x,\n" + " %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_send_mode_sense_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_send_mode_sense_done; + + /* Second test case: */ + /* Fill aditional cdb fields */ + modes_iu.cdb[2] = 0x48; /* page code = cashing, pc = 1 */ + printf("Second test case: page code = 0x08 (cashing)\n" + " pc = 1 (page controll = return changble " + "values)\n"); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&modes_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_mode_sense_done; + } + + memset(buf, 0, 1024); + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, modes_iu.tag)) + goto exec_send_mode_sense_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 16, &transferred, 2000); + + if (memcmp(buf, expected_buf_t2, 16)) + printf(" ERROR ocured! Received incorrect reply!\n" + " buf = %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x,\n" + " %02x, %02x, %02x, %02x, %02x, %02x, %02x," + " %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_send_mode_sense_done: + libusb_close(udev); + return ret; +} + +/** + * exec_send_prevent_allow_removal() - Test the PREVENT_ALLOW_MEDIA_REMOVAL + * SCSI command + * @dev:pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_send_prevent_allow_removal(struct libusb_device *dev) +{ + struct cmd_iu prev_allow_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + uint8_t buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_send_prevent_allow_removal_done; + } + + memset(buf, 0, 1024); + + fill_cmd_iu(&prev_allow_iu, 0x1e, UASP_LUN_NUM, 0); + /* Update the prevent field */ + prev_allow_iu.cdb[4] = 0x01; + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_send_prevent_allow_removal_done; + } + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&prev_allow_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_prevent_allow_removal_done; + } + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + + if (ret) + goto exec_send_prevent_allow_removal_done; + + /*Restore the prevent_allow -> allow medium removal */ + printf("Restoring to 'allow medium removal'...\n"); + prev_allow_iu.cdb[4] = 0x00; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&prev_allow_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_prevent_allow_removal_done; + } + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_send_prevent_allow_removal_done: + libusb_close(udev); + return ret; +} + +/** + * exec_send_read_capacity() - Test the READ_CAPACITY SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the READ_CAPACITY SCSI command to the device and + * verifies the correct reply from it. + * + * Return 0 on success, -1 otherwise + */ +int exec_send_read_capacity(struct libusb_device *dev) +{ + struct cmd_iu readc_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + uint8_t buf[1024]; + int transferred; + int ret = -1; + + unsigned long lba, block_length ; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_send_read_capacity_done; + } + + memset(buf, 0, 1024); + + fill_cmd_iu(&readc_iu, 0x25, UASP_LUN_NUM, 0); + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_send_read_capacity_done; + } + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&readc_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_read_capacity_done; + } + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, readc_iu.tag)) + goto exec_send_read_capacity_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 8, &transferred, 2000); + lba = IUGETDW(&buf[0]); + block_length = IUGETDW(&buf[4]); + printf("reply received:\n" + " LBA = %d, Block Length = %d\n", + (int)lba, (int)block_length); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_send_read_capacity_done: + libusb_close(udev); + return ret; +} + +/** + * exec_send_inquiry() - Test the INQUIRY SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the INQUIRY SCSI command to the device and verifies the + * correct reply from it. + * + * Return 0 on success, -1 otherwise + */ +int exec_send_inquiry(struct libusb_device *dev) +{ + struct cmd_iu inq_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + char vendor_id[9]; + char prod_id[17]; + int *prod_level; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_send_inquiry_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_send_inquiry_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&inq_iu, 0x12, UASP_LUN_NUM, 0x24); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&inq_iu, CMDIU_SIZE, + &transferred, 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_inquiry_done; + } + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev,sts,inq_iu.tag)) + goto exec_send_inquiry_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, CMDIU_SIZE, &transferred, 2000); + + printf("reply received: size = %d, ret=%d\n", transferred, ret); + memcpy(vendor_id,&(buf[8]),sizeof(vendor_id)); + memcpy(prod_id,&(buf[16]),sizeof(prod_id)); + prod_level = (int*)&(buf[32]); + printf(" Vendor identification (ASCII)[8-15]: %s\n" + " Product identification (ASCII)[16-31]: %s\n" + " Product revision level[32-35]: %x\n", &buf[8], prod_id, + *prod_level); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_send_inquiry_done: + libusb_close(udev); + return ret; +} + + +/** + * exec_send_request_sense() - Test the REQUEST_SENCE command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the REQUEST_SENCE SCSI command to the device and + * verifies the correct reply from it. + * + * Return 0 on success, -1 otherwise + */ +int exec_send_request_sense(struct libusb_device *dev) +{ + struct cmd_iu sense_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + int transferred; + + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_send_request_sense_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find Command BULK OUT endpoint!\n"); + goto exec_send_request_sense_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&sense_iu, 0x03, UASP_LUN_NUM, 0x18); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&sense_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_send_request_sense_done; + } + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, sense_iu.tag)) + goto exec_send_request_sense_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 18, &transferred, 2000); + + printf("Reply received: size = %d, ret=%d\n", transferred, ret); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_send_request_sense_done: + libusb_close(udev); + return ret; +} + +/** + * exec_test_unit_ready() - Test the TEST_UNIT_READY command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_unit_ready(struct libusb_device *dev) +{ + struct cmd_iu unit_ready_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_unit_ready_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_unit_ready_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&unit_ready_iu, 0x00, UASP_LUN_NUM, 0); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&unit_ready_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_unit_ready_done; + } + + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n", ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_test_unit_ready_done: + libusb_close(udev); + return ret; +} + +/** + * test_write() - Tests the SCSI WRITE command + * @dev: pointer to the libusb device to run the test on + * @write_iu: pointer to the cmdiu to send + * @data_size: size of the data to write + * @data_buf: the data buffer to write + * + * This function is used to test the WRITE6, WRITE10 and WRITE12 SCSI commands. + * + * Return 0 on success, -1 otherwise + * TODO: add write verification + */ +static int test_write(struct libusb_device *dev, + struct cmd_iu write_iu, + int data_size, + unsigned char *data_buf) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkout, *bulkin, *sts; + unsigned char buf[1024]; + unsigned char *read_to_buf; + + int transferred; + int ret = -1; + + if (!dev) + return -1; + + read_to_buf = (unsigned char *)malloc(data_size); + if (!read_to_buf) { + printf(" ERROR: cound't allocate memory!\n"); + return ret; + } + /* + * Prior to a write command we need to send test_unit_ready command to + * verify that the device is ready for data transfer + */ + ret = exec_test_unit_ready(dev); + if (ret) { + printf("TEST_UNIT_READY failed\n"); + goto exec_test_write_done; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_write_done; + } + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkout = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_OUT); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !bulkout || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_write_done; + } + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&write_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_write_done; + } + + /* If we're working in HS mode we should receive a WRITE READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER) { + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + UASP_SIZEOF_RW_READY_IU, + &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_write_done; + } + /* Verify the tag */ + if (((struct rw_ready_iu*)buf)->tag != write_iu.tag || + ((struct rw_ready_iu*)buf)->iu_id != IU_ID_WRITE_READY) { + printf(" ERROR: Received Incorrect IU!!!" + " (iu_id = %d, tag = %d, expected_tag = %d)\n\n", + ((struct rw_ready_iu*)buf)->iu_id, + ((struct rw_ready_iu*)buf)->tag, write_iu.tag); + goto exec_test_write_done; + } + } + + printf(" Sending Data:...\n"); + ret = libusb_bulk_transfer(udev, bulkout->bEndpointAddress, + data_buf, data_size, &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_write_done; + } + printf("data sent: transferred = %d, data_size = %d\n", + transferred, data_size); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_write_done; + } + ret = verify_sense_iu(buf, transferred); + +exec_test_write_done: + free(read_to_buf); + libusb_close(udev); + return ret; +} + +/** + * test_read() - Tests the SCSI READ command + * @dev: pointer to the libusb device to run the test on + * @write_iu: pointer to the cmdiu to send + * @data_size: size of the data to read + * + * This function is used to test the READ6, READ10 and READ12 SCSI commands. + * + * Return 0 on success, -1 otherwise + */ +static int test_read(struct libusb_device *dev, + struct cmd_iu read_iu, + int data_size) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* + * Prior to a read command we need to send test_unit_ready command to + * verify that the device is ready for data transfer + */ + ret = exec_test_unit_ready(dev); + if (ret) { + printf("TEST_UNIT_READY failed\n"); + goto exec_test_read_done; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_read_done; + } + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_read_done; + } + + memset(buf, 0, sizeof(buf)); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&read_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_read_done; + } + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, read_iu.tag)) + goto exec_test_read_done; + + printf("waiting for data...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, data_size, &transferred, 2000); + + printf("Reply received: size = %d, ret=%d\n", transferred, ret); + if (transferred != sizeof(reference_buf)) + printf("\n ERROR: Received less data then expected (%d)\n", + sizeof(reference_buf)); + else + if (memcmp(buf, reference_buf, sizeof(reference_buf))) + printf(" Receieved not-expected data:\n%s\n", + buf); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + +exec_test_read_done: + libusb_close(udev); + return ret; +} + +int reset_data_file(struct libusb_device *dev) +{ + unsigned char buf[1024]; + struct cmd_iu write_iu; + int i = 0; + + printf(" Reseting data file...\n"); + /* Fill the data buffer*/ + for (i = 0; i < 1024; i++) { + if (!(i % 100)) + buf[i] = 0x0a; + else + buf[i] = 0x41; + } + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + return test_write(dev, write_iu, 1024, buf); +} + +/** + * exec_test_read6() - Test the READ6 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read6(struct libusb_device *dev) +{ + struct cmd_iu read6_iu; + struct cmd_iu write_iu; + + int rc = 0; + + /* Write the reference_buf to the file prior to reading */ + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + rc = test_write(dev, write_iu, sizeof(reference_buf), reference_buf); + if (rc) { + printf("Failed to write reference buffer\n"); + return rc; + } + + /* Start reading from block 0, LBA = 0 */ + fill_cmd_iu(&read6_iu, 0x08, UASP_LUN_NUM, 0); + read6_iu.cdb[4] = 0x02; /* read 2 blocks (of 512 bytes) */ + + rc = test_read(dev, read6_iu, 1024); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return rc; +} + +/** + * exec_test_read10() - Test the READ10 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read10(struct libusb_device *dev) +{ + struct cmd_iu read10_iu; + struct cmd_iu write_iu; + int rc = 0; + + /* Write the reference_buf to the file prior to reading */ + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + rc = test_write(dev, write_iu, sizeof(reference_buf), reference_buf); + if (rc) { + printf("Failed to write reference buffer\n"); + return rc; + } + + /* Start reading from block 0, LBA = 0 */ + fill_cmd_iu(&read10_iu, 0x28, UASP_LUN_NUM, 0); + read10_iu.cdb[8] = 0x02; /* read 2 blocks (of 512 bytes) */ + + rc = test_read(dev, read10_iu, 1024); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return rc; +} + +/** + * exec_test_read12() - Test the READ12 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read12(struct libusb_device *dev) +{ + struct cmd_iu read12_iu; + struct cmd_iu write_iu; + int rc = 0; + + /* Write the reference_buf to the file prior to reading */ + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + rc = test_write(dev, write_iu, sizeof(reference_buf), reference_buf); + if (rc) { + printf("Failed to write reference buffer\n"); + return rc; + } + + /* Start reading from block 0, LBA = 0 */ + fill_cmd_iu(&read12_iu, 0xa8, UASP_LUN_NUM, 0); + read12_iu.cdb[9] = 0x02; /* read 2 blocks (of 512 bytes) */ + + rc = test_read(dev, read12_iu, 1024); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return rc; +} + +/** + * exec_test_write6() - Test the WRITE6 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write6(struct libusb_device *dev) +{ + struct cmd_iu write6_iu; + unsigned char buf[1024]; + int i, rc; + + /* Fill the data buffer*/ + for (i = 0; i < 1024; i++) { + if (!(i % 100)) + buf[i] = 0x0a; + else + buf[i] = 0x41; + } + + /* Start reading from block 0, LBA = 0 */ + fill_cmd_iu(&write6_iu, 0x0a, UASP_LUN_NUM, 0); + write6_iu.cdb[4] = 0x02; /* read 2 blocks (of 512 bytes) */ + + rc = test_write(dev, write6_iu, 1024, buf); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return rc; +} + + +/** + * exec_test_write10() - Test the WRITE10 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write10(struct libusb_device *dev) +{ + struct cmd_iu write10_iu; + unsigned char buf[1024]; + int i, rc; + + /* Fill the data buffer*/ + for (i = 0; i < 1024; i++) { + if (!(i % 100)) + buf[i] = 0x0a; + else + buf[i] = 0x42; + } + + /* Start reading from block 0, LBA = 0 */ + fill_cmd_iu(&write10_iu, 0x2a, UASP_LUN_NUM, 0); + write10_iu.cdb[8] = 0x02; /* read 2 blocks (of 512 bytes) */ + + rc = test_write(dev, write10_iu, 1024, buf); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return rc; +} + + +/** + * exec_test_write12() - Test the WRITE12 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write12(struct libusb_device *dev) +{ + struct cmd_iu write12_iu; + unsigned char buf[1024]; + int i, rc; + + /* Fill the data buffer*/ + for (i = 0; i < 1024; i++) { + if (!(i % 100)) + buf[i] = 0x0a; + else + buf[i] = 0x43; + } + + /* Start reading from block 0, LBA = 0 */ + fill_cmd_iu(&write12_iu, 0xaa, UASP_LUN_NUM, 0); + write12_iu.cdb[9] = 0x02; /* read 2 blocks (of 512 bytes) */ + + rc = test_write(dev, write12_iu, 1024, buf); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return rc; +} + +/** + * exec_test_write_huge() - Test the WRITE10 SCSI command with alot of data + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write_huge(struct libusb_device *dev) +{ + struct cmd_iu write10_iu; + unsigned char buf[31744]; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkout, *bulkin, *sts; + + int transferred, i; + int ret = -1; + + if (!dev) + return -1; + + /* + * Prior to a write command we need to send test_unit_ready command to + * verify that the device is ready for data transfer + */ + ret = exec_test_unit_ready(dev); + if (ret) { + printf("TEST_UNIT_READY failed\n"); + goto exec_test_write_huge_done; + } + + /* Fill the data buffer*/ + for (i = 0; i < 31744; i++) { + if (!(i % 100)) + buf[i] = 0x0a; + else + buf[i] = 0x42; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_write_huge_done; + } + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkout = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_OUT); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !bulkout || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_write_huge_done; + } + + /* Start writing from block 0, LBA = 0 */ + fill_cmd_iu(&write10_iu, 0x2a, UASP_LUN_NUM, 0); + /* write 62 blocks (of 512 bytes) = 31744 bytes*/ + write10_iu.cdb[8] = 0x3e; + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&write10_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_write_huge_done; + } + + /* If we're working in HS mode we should receive a WRITE READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER) { + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + UASP_SIZEOF_RW_READY_IU, + &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_write_huge_done; + } + /* Verify the tag */ + if (((struct rw_ready_iu*)buf)->tag != write10_iu.tag || + ((struct rw_ready_iu*)buf)->iu_id != IU_ID_WRITE_READY) { + printf(" ERROR: Received Incorrect IU!!!" + " (iu_id = %d, tag = %d, expected_tag = %d)\n\n", + ((struct rw_ready_iu*)buf)->iu_id, + ((struct rw_ready_iu*)buf)->tag, write10_iu.tag); + goto exec_test_write_huge_done; + } + } + + printf(" Sending Data:...\n"); + ret = libusb_bulk_transfer(udev, bulkout->bEndpointAddress, + buf, 31744, &transferred, 0); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_write_huge_done; + } + + printf("data sent: transferred = %d\n", transferred); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_write_huge_done; + } + ret = verify_sense_iu(buf, transferred); + + if (ret) + goto exec_test_write_huge_done; + + ret = 0; +exec_test_write_huge_done: + libusb_close(udev); + if (reset_data_file(dev)) + printf(" Failed Reseting data fail!\n"); + return ret; +} + +/** + * exec_test_read_format_capacities() - Test the READ FORMAT CAPACITIES + * SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read_format_capacities(struct libusb_device *dev) +{ + struct cmd_iu form_cap_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + unsigned char expected_buf[12] = {0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x07, 0xa1, 0x02, 0x00, 0x02, 0x00}; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_read_format_capacities_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !bulkin || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_read_format_capacities_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&form_cap_iu, 0x23, UASP_LUN_NUM, 0); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&form_cap_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_read_format_capacities_done; + } + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, form_cap_iu.tag)) + goto exec_test_read_format_capacities_done; + + printf("waiting for reply:...\n"); + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 12, &transferred, 2000); + + if (memcmp(expected_buf, buf, 12)) { + printf("Received incorrect reply:\n" + " buf = %02x, %02x, %02x, %02x, %02x, %02x,\n" + " %02x, %02x, %02x, %02x, %02x, %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9], + buf[10], buf[11]); + } else + printf("Received expected data\n"); + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret){ + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_read_format_capacities_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_test_read_format_capacities_done; + ret = 0; +exec_test_read_format_capacities_done: + libusb_close(udev); + return ret; +} + +/** + * exec_test_start_stop() - Test the TEST_START_STOP_UNIT command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + * + * TODO: this test isn't full. It doesn't check that the unit was indeed + * started/ejected etc. It just verifies the completion status. + */ +int exec_test_start_stop(struct libusb_device *dev) +{ + struct cmd_iu start_stop_iu, sense_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_start_stop_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !sts || !bulkin) { + printf("Didn't find endpoints!\n"); + goto exec_test_start_stop_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&start_stop_iu, 0x1b, UASP_LUN_NUM, 0); + + /* First test case (LoEj,Start) = 00 (stop motor) */ + printf(" First test case (LoEj,Start) = 00 (stop motor)\n"); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&start_stop_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_start_stop_done; + } + + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret){ + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_start_stop_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_test_start_stop_done; + + /* Second test case (LoEj,Start) = 01 (start motor) */ + printf(" Second test case (LoEj,Start) = 01 (start motor)\n"); + start_stop_iu.cdb[4] = 0x01; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&start_stop_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_start_stop_done; + } + + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_start_stop_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_test_start_stop_done; + + /* Third test case (LoEj,Start) = 10 (Eject media) */ + printf(" Third test case (LoEj,Start) = 10 (Eject media)\n"); + start_stop_iu.cdb[4] = 0x02; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&start_stop_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_start_stop_done; + } + + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret){ + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_start_stop_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_test_start_stop_done; + + /* + * After the media is ejected the lun is closed. We need to re-open + * it manualy in order to be able to continue working with it + */ + ret = usb_tests_write_gadget_sysfs_file_str((char *)"lun0/file", + (char *)"/root/back_storage_file.txt"); + if (ret) { + printf("Write to device_attr(file) failed %d \n",ret); + goto exec_test_start_stop_done; + } + + /* After the LUN was re-opened, issue a REQUEST SENSE first */ + printf("Issue REQUEST SENSE...\n"); + fill_cmd_iu(&sense_iu, 0x03, UASP_LUN_NUM, 0x18); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&sense_iu, CMDIU_SIZE, + &transferred, 2000); + + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_start_stop_done; + } + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER && + receive_read_iu(udev, sts, sense_iu.tag)) + goto exec_test_start_stop_done; + + ret = libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, 18, &transferred, 2000); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) + printf("libusb_bulk_transfer error = %d\n",ret); + else + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_test_start_stop_done; + + /* Forth test case (LoEj,Start) = 11 (LOAD media) */ + printf(" Forth test case (LoEj,Start) = 11 (LOAD media)\n"); + start_stop_iu.cdb[4] = 0x03; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&start_stop_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_start_stop_done; + } + + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret){ + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_start_stop_done; + } + ret = verify_sense_iu(buf, transferred); + if (ret) + goto exec_test_start_stop_done; + + ret = 0; +exec_test_start_stop_done: + libusb_close(udev); + return ret; +} + +/** + * exec_test_verify() - Test the VERIFY command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_verify(struct libusb_device *dev) +{ + struct cmd_iu verify_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_verify_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_verify_done; + } + + /* First write data to the device to verify it */ + if (exec_test_write6(dev)) { + printf(" ERROR: write (prior to verify) failed!\n"); + goto exec_test_verify_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&verify_iu, 0x2f, UASP_LUN_NUM, 0); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&verify_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_verify_done; + } + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_verify_done; + } + ret = verify_sense_iu(buf,transferred); + if (ret) + goto exec_test_verify_done; + + ret = 0; +exec_test_verify_done: + libusb_close(udev); + return ret; +} + +/** + * exec_test_synchronize_cache() - Test the SYNCHRONIZE CACHE + * command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_synchronize_cache(struct libusb_device *dev) +{ + struct cmd_iu sync_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_sync_cache_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_sync_cache_done; + } + + memset(buf, 0, 1024); + fill_cmd_iu(&sync_iu, 0x35, UASP_LUN_NUM, 0); + /* Update CDB fields */ + sync_iu.cdb[8] = 2; + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&sync_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_sync_cache_done; + } + + printf(" Reading status:...\n"); + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_sync_cache_done; + } + ret = verify_sense_iu(buf,transferred); + if (ret) + goto exec_test_sync_cache_done; + + ret = 0; +exec_test_sync_cache_done: + libusb_close(udev); + return ret; +} + +/** + * exec_test_cmd_overlapped_tag() - Verifies correct behavior in + * case of CMD overlapped tag attempted + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_cmd_overlapped_tag(struct libusb_device *dev) +{ + struct cmd_iu unit_ready_iu, tag_error_cmd; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_cmd_overlapped_tag_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_cmd_overlapped_tag_done; + } + + /* Issue command for the overlapped tag condition */ + fill_cmd_iu(&unit_ready_iu, 0x00, UASP_LUN_NUM, 0x00); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&unit_ready_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_cmd_overlapped_tag_done; + } + + printf("Issued TEST UNIT TEADY command...\n"); + + /* Now issue a CMD with the same tag */ + fill_cmd_iu(&tag_error_cmd, 0x00, UASP_LUN_NUM, 0x00); + tag_error_cmd.tag = unit_ready_iu.tag; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&tag_error_cmd, + CMDIU_SIZE, &transferred, 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_cmd_overlapped_tag_done; + } + + printf("Issued a CMD with the same tag...\n"); + /* read status */ + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_cmd_overlapped_tag_done; + } else + ret = verify_sense_iu(buf,transferred); + + if (ret != 1) + goto exec_test_cmd_overlapped_tag_done; + + /* Verify that no additional data is about to be received */ + if (!libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000)) { + printf(" ERROR: REceived additional data on " + "status ep!\n"); + ret = -1; + goto exec_test_cmd_overlapped_tag_done; + } + + ret = 0; +exec_test_cmd_overlapped_tag_done: + libusb_close(udev); + /* If test sucseded, verify that the device is functional */ + if (!ret && exec_send_request_sense(dev)) { + printf(" ERROR: After overlapped tag the device is not" + "functional!!!\n"); + ret = -1; + } + return ret; +} diff --git a/tools/usb/unittests/usb/UASP_TM_tests.cc b/tools/usb/unittests/usb/UASP_TM_tests.cc new file mode 100644 index 0000000..ab360ca --- /dev/null +++ b/tools/usb/unittests/usb/UASP_TM_tests.cc @@ -0,0 +1,1207 @@ +/* + * UASP_TM_tests.cc - The tests in this file test the UASP TASK MANAGEMENT IUs + * handling. This file implements test to be run on a UASP supporting device. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include "UASP_tests.h" +#include "usb_tests.h" +#include "usb_devel_mode.h" + +struct command_status{ + u8 code; /* for cmdiu this is CDB OpCode. For tmiu this is tm func */ + u16 tag; + int is_cmdiu; + int expected_comp_sts; + int stat_received; +}; + +#define MAX_ACTIVE_COMMANDS 100 +static struct command_status active_cmd_arr[MAX_ACTIVE_COMMANDS]; +static int num_act_cmd = 0; + +static void reset_active_cmd_arr() +{ + int i=0; + for (i = 0; i < MAX_ACTIVE_COMMANDS; i++) { + active_cmd_arr[i].code = 0; + active_cmd_arr[i].tag = 0; + active_cmd_arr[i].is_cmdiu = 0; + active_cmd_arr[i].expected_comp_sts = -1; + } + num_act_cmd = 0; +} + +static void add_cmd_to_arr(u8 code, + u16 tag, + int is_cmdiu, + int expected_comp_sts) +{ + active_cmd_arr[num_act_cmd].code = code; + active_cmd_arr[num_act_cmd].tag = tag; + active_cmd_arr[num_act_cmd].is_cmdiu = is_cmdiu; + active_cmd_arr[num_act_cmd].expected_comp_sts = expected_comp_sts; + active_cmd_arr[num_act_cmd++].stat_received = 0; +} + +static int find_cmd_in_arr(u16 tag){ + int i; + for (i = 0; i < num_act_cmd; i++) + if (active_cmd_arr[i].tag == tag) + return i; + return -1; +} + +static int analize_received_status(unsigned char *buf) +{ + struct sense_iu *sense; + struct response_iu *response; + u16 tag; + int is_cmdiu; + int cmd_index; + int status; + + if (buf[0] == 0x03) { + sense = (struct sense_iu*)buf; + tag = sense->tag; + is_cmdiu = 1; + status = sense->status; + } else if (buf[0] == 0x04){ + response = (struct response_iu *)buf; + tag = response->tag; + is_cmdiu = 0; + status = response->status; + } else { + printf(" ERROR: Unknoun packet received!" + " (IU ID = %d)\n", buf[0]); + return -1; + } + + cmd_index = find_cmd_in_arr(tag); + if (cmd_index == -1) { + printf(" ERROR: command with such iptag " + "wasn't issued!\n"); + return -1; + } + if (active_cmd_arr[cmd_index].stat_received) { + printf(" ERROR: Received comp status for same" + " commad twise!\n"); + return -1; + } + if (is_cmdiu && !active_cmd_arr[cmd_index].is_cmdiu) { + printf(" ERROR: received SENSE IU for TM IU\n"); + return -1; + } + if (active_cmd_arr[cmd_index].expected_comp_sts != status) { + printf(" ERROR! Completion status isn't as " + "expected!\n" + " Expected %02x Received %02x\n", + active_cmd_arr[cmd_index].expected_comp_sts, status); + return -1; + } + printf(" Received status for command code = %02x\n", + active_cmd_arr[cmd_index].code); + active_cmd_arr[cmd_index].stat_received = 1; + return 0; +} + +/** + * fill_tm_iu() - Fills the command iu structure with given values + * @iu: pointer to the tm_iu structure to fill + * @tm_function: TM function type to fill + * @lun: LUN number + * + */ +void fill_tm_iu(struct tm_iu *iu, u8 tm_function, u8 lun) +{ + memset((void *)iu, 0 ,sizeof(struct tm_iu)); + iu->iu_id = 0x05; /* task management iu*/ + iu->reserved1 = 0; + iu->tag = get_next_ip_tag(); + iu->tm_function = tm_function; + iu->reserved5 = 0; + /* Reserved for all tm_functions but ABORT_TASK and QUERY_TASK */ + iu->task_tag = 0; + memset(iu->lun, 0, 8); + iu->lun[0] = lun; /* Workaround: Right now @init we set lun_id[0] = i */ +} + +/** + * exec_test_tm_reset_lun() - Test the LOGICAL LUN RESET TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_reset_lun(struct libusb_device *dev) +{ + struct tm_iu reset_lun_iu; + struct cmd_iu write_iu, read_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_tm_reset_lun_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_tm_reset_lun_done; + } + + reset_active_cmd_arr(); + + /* Issue 2 commands to be canceled later on by the LUN_RESET TM */ + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&write_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_reset_lun_done; + } + + /* No status is expected for this command */ + add_cmd_to_arr(write_iu.cdb[0], write_iu.tag, 1, -1); + + fill_cmd_iu(&read_iu, 0x08, UASP_LUN_NUM, 0); + read_iu.cdb[4] = 0x02; /* read 2 blocks (of 512 bytes) */ + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&read_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_reset_lun_done; + } + + /* No status is expected for this command */ + add_cmd_to_arr(read_iu.cdb[0], read_iu.tag, 1, -1); + + /* Now issue the LUN_RESET TM */ + fill_tm_iu(&reset_lun_iu, 0x08, UASP_LUN_NUM); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&reset_lun_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_reset_lun_done; + } + + + add_cmd_to_arr(reset_lun_iu.tm_function, reset_lun_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + /* read status */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_reset_lun_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_reset_lun_done; + + /* Verify that no additional data is about to be received */ + if (!libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000)) { + printf(" ERROR: REceived additional data on " + "status ep!\n"); + ret = -1; + goto exec_test_tm_reset_lun_done; + } + ret = 0; +exec_test_tm_reset_lun_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + +/** + * exec_test_tm_abort_task() - Test the ABORT_TASK TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_abort_task(struct libusb_device *dev) +{ + struct tm_iu abort_cmd_iu; + struct cmd_iu write_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_tm_abort_task_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_tm_abort_task_done; + } + + reset_active_cmd_arr(); + + /* Issue a command to be canceled later on by the ABORT_TASK TM */ + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&write_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_abort_task_done; + } + + /* No status is expected for this command */ + add_cmd_to_arr(write_iu.cdb[0], write_iu.tag, 1, -1); + + /* Now issue the ABORT TASK TM */ + fill_tm_iu(&abort_cmd_iu, 0x01, UASP_LUN_NUM); + abort_cmd_iu.task_tag = write_iu.tag; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&abort_cmd_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_abort_task_done; + } + + + add_cmd_to_arr(abort_cmd_iu.tm_function, abort_cmd_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + /* read status */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_abort_task_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_abort_task_done; + + /* Verify that no additional data is about to be received */ + if (!libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000)) { + printf(" ERROR: REceived additional data on " + "status ep!\n"); + ret = -1; + goto exec_test_tm_abort_task_done; + } + ret = 0; + +exec_test_tm_abort_task_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + +/** + * exec_test_tm_abort_task_set() - Test the ABORT TASK SET TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_abort_task_set(struct libusb_device *dev) +{ + struct tm_iu abort_ts_iu, query_ts_iu; + struct cmd_iu write_iu, read_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_tm_abort_ts_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_tm_abort_ts_done; + } + + reset_active_cmd_arr(); + + /* Issue 2 commands to be canceled later on by the ABORT_TASK_SET TM */ + fill_cmd_iu(&write_iu, 0x0a, UASP_LUN_NUM, 0); + write_iu.cdb[4] = 0x02; /* write 2 blocks (of 512 bytes) */ + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&write_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_abort_ts_done; + } + + /* No status is expected for this command */ + add_cmd_to_arr(write_iu.cdb[0], write_iu.tag, 1, -1); + + fill_cmd_iu(&read_iu, 0x08, UASP_LUN_NUM, 0); + read_iu.cdb[4] = 0x02; /* read 2 blocks (of 512 bytes) */ + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&read_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_abort_ts_done; + } + + /* No status is expected for this command */ + add_cmd_to_arr(read_iu.cdb[0], read_iu.tag, 1, -1); + + /* Now issue the ABORT_TASK_SET TM */ + fill_tm_iu(&abort_ts_iu, 0x02, UASP_LUN_NUM); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&abort_ts_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_abort_ts_done; + } + + + add_cmd_to_arr(abort_ts_iu.tm_function, abort_ts_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + + /* Issue another TM that should not be canceled */ + fill_tm_iu(&query_ts_iu, 0x81, UASP_LUN_NUM); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&query_ts_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_abort_ts_done; + } + + + add_cmd_to_arr(query_ts_iu.tm_function, query_ts_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + /* read status for both TM IUs issued*/ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_abort_ts_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_abort_ts_done; + memset(buf, 0, sizeof(buf)); + + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_abort_ts_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_abort_ts_done; + + /* Verify that no additional data is about to be received */ + if (!libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000)) { + printf(" ERROR: REceived additional data on " + "status ep!\n"); + ret = -1; + goto exec_test_tm_abort_ts_done; + } + ret = 0; +exec_test_tm_abort_ts_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + +/** + * exec_test_tm_reset_nexus() - Test the RESET NEXUS TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_reset_nexus(struct libusb_device *dev) +{ + struct tm_iu reset_nexus_iu; + struct cmd_iu inq_iu, unit_ready_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_tm_reset_nexus_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts || !bulkin) { + printf("Didn't find endpoints!\n"); + goto exec_test_tm_reset_nexus_done; + } + + reset_active_cmd_arr(); + + /* Issue 2 commands to be completed befor the RESET_NEXUS TM */ + fill_cmd_iu(&inq_iu, 0x12, UASP_LUN_NUM, 0x24); + printf("Sending INQUIRY command...\n"); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&inq_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_reset_nexus_done; + } + + add_cmd_to_arr(inq_iu.cdb[0], inq_iu.tag, 1, -1); + /* No status is expected for this command */ + fill_cmd_iu(&unit_ready_iu, 0x00, UASP_LUN_NUM, 0); + printf("Sending TEST UNIT READY command...\n"); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&unit_ready_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_reset_nexus_done; + } + + /* No status is expected for this command */ + add_cmd_to_arr(unit_ready_iu.cdb[0], unit_ready_iu.tag, 1, -1); + + /* Now issue the RESET_NEXUS TM */ + printf("Sending RESET NEXUS TM...\n"); + fill_tm_iu(&reset_nexus_iu, 0x10, UASP_LUN_NUM); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&reset_nexus_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_reset_nexus_done; + } + + + add_cmd_to_arr(reset_nexus_iu.tm_function, reset_nexus_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + /* Try reading inquiry result - should fail */ + /* + * Due to the implementation in dummy_hcd this woun't fail. + * See implementation of dummy_queue() for details + */ + memset(buf, 0, sizeof(buf)); + printf("Try Reading INQUERY result...\n"); + if (!libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, CMDIU_SIZE, &transferred, 2000)){ + printf(" ERROR: Received data on bulk ep!\n"); + /* Un-comment if running on a real UDC + ret = -1; + goto exec_test_tm_reset_nexus_done;*/ + } + + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_reset_nexus_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_reset_nexus_done; + + /* Verify that no additional data is about to be received */ + if (!libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000)) { + printf(" ERROR: REceived additional data on " + "status ep!\n"); + ret = -1; + goto exec_test_tm_reset_nexus_done; + } + + ret = 0; +exec_test_tm_reset_nexus_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + + +/** + * exec_test_tm_query_async_ev() - Test the QUERY ASYNC EVENT TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_query_async_ev(struct libusb_device *dev) +{ + struct tm_iu query_tm_iu; + struct response_iu *res_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int resp_info = 0; + int ret = -1; + + /* Reset the nexus in order for UNIT_ATTENTION to be LUN_RESET */ + if (exec_test_tm_reset_nexus(dev)) + return -1; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto test_tm_query_async_ev_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto test_tm_query_async_ev_done; + } + + reset_active_cmd_arr(); + fill_tm_iu(&query_tm_iu, 0x82, UASP_LUN_NUM); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&query_tm_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto test_tm_query_async_ev_done; + } + add_cmd_to_arr(query_tm_iu.tm_function, query_tm_iu.tag, 0, + RESPONSE_TM_FUNCTION_SUCCEEDED); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto test_tm_query_async_ev_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto test_tm_query_async_ev_done; + + res_iu = (struct response_iu *)buf; + resp_info = (res_iu->resp_info[0] << 16) | + (res_iu->resp_info[1] << 8) | + res_iu->resp_info[2]; + + if (resp_info != (SS_RESET_OCCURRED | (1 << 20))) + printf(" Reseived strange RESPONCE info = %06x", + resp_info); + + ret = 0; +test_tm_query_async_ev_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + +/** + * exec_test_tm_query_task() - Test the QUERY TASK TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_query_task(struct libusb_device *dev) +{ + struct tm_iu query_task_iu; + struct cmd_iu inq_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *bulkin, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_tm_query_task_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + bulkin = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_DATA_IN); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts || !bulkin) { + printf("Didn't find endpoints!\n"); + goto exec_test_tm_query_task_done; + } + + reset_active_cmd_arr(); + + /* Issue a command to be queried later on */ + fill_cmd_iu(&inq_iu, 0x12, UASP_LUN_NUM, 0x24); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&inq_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_query_task_done; + } + + printf("Issued INQUERY command...\n"); + add_cmd_to_arr(inq_iu.cdb[0], inq_iu.tag, 1, STATUS_GOOD); + + /* Now issue the QUERY TASK TM */ + fill_tm_iu(&query_task_iu, 0x80, UASP_LUN_NUM); + query_task_iu.task_tag = inq_iu.tag; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&query_task_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_query_task_done; + } + + printf("Issued QUERY TASK TM...\n"); + add_cmd_to_arr(query_task_iu.tm_function, query_task_iu.tag, 0, + RESPONSE_TM_FUNCTION_SUCCEEDED); + + /* If we're working in HS mode we should receive a READ READY IU */ + if (get_dev_speed() < USB_SPEED_SUPER) { + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + UASP_SIZEOF_RW_READY_IU, + &transferred, 2000); + + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_query_task_done; + } + /* Verify the tag */ + if (((struct rw_ready_iu*)buf)->tag != inq_iu.tag || + ((struct rw_ready_iu*)buf)->iu_id != IU_ID_READ_READY) { + printf(" ERROR: Received Incorrect IU!!!" + " (iu_id = %d, tag = %d, expected_tag = %d)\n\n", + ((struct rw_ready_iu*)buf)->iu_id, + ((struct rw_ready_iu*)buf)->tag, inq_iu.tag); + goto exec_test_tm_query_task_done; + } + } + + /* read status of TM */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_query_task_done; + } else { + ret = analize_received_status(buf); + } + + printf("Reading INQUERY data...\n"); + /* Complete the INQUERY command handling */ + memset(buf, 0, sizeof(buf)); + if (libusb_bulk_transfer(udev, bulkin->bEndpointAddress, + buf, CMDIU_SIZE, &transferred, 2000)){ + printf(" ERROR: INQUERY failed\n"); + ret = -1; + goto exec_test_tm_query_task_done; + } + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_query_task_done; + } else { + ret = analize_received_status(buf); + } + + if (ret) + goto exec_test_tm_query_task_done; + + /* + * Issue another QUERY TASK TM. This time the result should be + * COMPLETE since the command completed + */ + fill_tm_iu(&query_task_iu, 0x80, UASP_LUN_NUM); + query_task_iu.task_tag = inq_iu.tag; + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&query_task_iu, TMIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_query_task_done; + } + + + printf("Issued seconf QUERY TASK TM...\n"); + add_cmd_to_arr(query_task_iu.tm_function, query_task_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + /* read status */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_query_task_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_query_task_done; + + ret = 0; + +exec_test_tm_query_task_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + + +/** + * exec_test_tm_query_task_set() - Test the QUERY TASK SET TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_query_task_set(struct libusb_device *dev) +{ + struct tm_iu query_task_set_iu; + struct cmd_iu unit_ready_iu1, unit_ready_iu2; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_query_task_set_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_query_task_set_done; + } + + reset_active_cmd_arr(); + + /* Issue 2 commands to be queried later on */ + fill_cmd_iu(&unit_ready_iu1, 0x00, UASP_LUN_NUM, 0x00); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&unit_ready_iu1, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_query_task_set_done; + } + + printf("Issued TEST UNIT TEADY1 command...\n"); + add_cmd_to_arr(unit_ready_iu1.cdb[0], unit_ready_iu1.tag, 1, + STATUS_GOOD); + + fill_cmd_iu(&unit_ready_iu2, 0x00, UASP_LUN_NUM, 0x00); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&unit_ready_iu2, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_query_task_set_done; + } + + printf("Issued TEST UNIT TEADY2 command...\n"); + add_cmd_to_arr(unit_ready_iu2.cdb[0], unit_ready_iu2.tag, 1, + STATUS_GOOD); + + /* Now issue the QUERY TASK SET TM - both command are in processing */ + fill_tm_iu(&query_task_set_iu, 0x81, UASP_LUN_NUM); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&query_task_set_iu, + TMIU_SIZE, &transferred, 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_query_task_set_done; + } + + printf("Issued QUERY TASK SET TM " + "(both commands are in processing)...\n"); + add_cmd_to_arr(query_task_set_iu.tm_function, query_task_set_iu.tag, 0, + RESPONSE_TM_FUNCTION_SUCCEEDED); + + /* read status */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_query_task_set_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_query_task_set_done; + + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_query_task_set_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_query_task_set_done; + + + memset(buf, 0, sizeof(buf)); + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_query_task_set_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_query_task_set_done; + + /* + * Issue another QUERY TASK SET TM. This time the result should be + * COMPLETE since both commands are completed + */ + fill_tm_iu(&query_task_set_iu, 0x81, UASP_LUN_NUM); + + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&query_task_set_iu, + TMIU_SIZE, &transferred, 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_query_task_set_done; + } + + + printf("Issued seconf QUERY TASK SET TM...\n"); + add_cmd_to_arr(query_task_set_iu.tm_function, query_task_set_iu.tag, 0, + RESPONSE_TM_FUNCTION_COMPLETE); + + /* read status */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_query_task_set_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_query_task_set_done; + + ret = 0; + +exec_test_query_task_set_done: + reset_active_cmd_arr(); + libusb_close(udev); + return ret; +} + +/** + * exec_test_tm_overlapped_tag() - Verifies correct behavior in + * case of TM overlapped tag attempted + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_overlapped_tag(struct libusb_device *dev) +{ + struct tm_iu tag_error_tm; + struct cmd_iu unit_ready_iu; + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *cmd_ep, *sts; + unsigned char buf[1024]; + int transferred; + int ret = -1; + + if (!dev) + return -1; + + /* After a reset occured check the unit attention */ + if (exec_send_request_sense(dev)) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto exec_test_tm_overlapped_tag_done; + } + + cmd_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_CMD); + sts = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, 0, + PIPE_ID_STS); + if (!cmd_ep || !sts) { + printf("Didn't find endpoints!\n"); + goto exec_test_tm_overlapped_tag_done; + } + + reset_active_cmd_arr(); + + /* Issue command for the overlapped tag condition */ + fill_cmd_iu(&unit_ready_iu, 0x00, UASP_LUN_NUM, 0x00); + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&unit_ready_iu, CMDIU_SIZE, + &transferred, + 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_overlapped_tag_done; + } + + printf("Issued TEST UNIT TEADY command (tag = %d)...\n", + unit_ready_iu.tag); + + /* Now issue a TM with the same tag */ + fill_tm_iu(&tag_error_tm, 0x81, UASP_LUN_NUM); + tag_error_tm.tag = unit_ready_iu.tag; + ret = libusb_bulk_transfer(udev, cmd_ep->bEndpointAddress, + (unsigned char*)&tag_error_tm, + TMIU_SIZE, &transferred, 2000); + if (ret) { + printf("Transfer error %d \n",ret); + goto exec_test_tm_overlapped_tag_done; + } + + printf("Issued a TM with the same tag (= %d)...\n", + tag_error_tm.tag); + add_cmd_to_arr(tag_error_tm.tm_function, tag_error_tm.tag, 0, + RESPONSE_OVERLAPPED_TAG_ATTEMPTED); + + /* read status */ + memset(buf, 0, sizeof(buf)); + /* + * We read data according to SENSE_U size since it's bigger + * than RESPONSE IU + */ + ret = libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000); + if (ret) { + printf("libusb_bulk_transfer error = %d\n",ret); + goto exec_test_tm_overlapped_tag_done; + } else + ret = analize_received_status(buf); + + if (ret) + goto exec_test_tm_overlapped_tag_done; + + /* Verify that no additional data is about to be received */ + if (!libusb_bulk_transfer(udev, sts->bEndpointAddress, buf, + SENSEIU_SIZE, &transferred, 2000)) { + printf(" ERROR: REceived additional data on " + "status ep!\n"); + ret = -1; + goto exec_test_tm_overlapped_tag_done; + } + + ret = 0; +exec_test_tm_overlapped_tag_done: + reset_active_cmd_arr(); + libusb_close(udev); + /* If test sucseded, verify that the device is functional */ + if (!ret && exec_send_request_sense(dev)) { + printf(" ERROR: After overlapped tag the device is not" + "functional!!!\n"); + ret = -1; + } + return ret; +} + diff --git a/tools/usb/unittests/usb/UASP_tests.h b/tools/usb/unittests/usb/UASP_tests.h new file mode 100644 index 0000000..7b01782 --- /dev/null +++ b/tools/usb/unittests/usb/UASP_tests.h @@ -0,0 +1,434 @@ +/* + * UASP_tests.h - This file defines tests to be run on a UASP supporting device. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _UASP_TESTS_H +#define _UASP_TESTS_H + +extern "C" { +#include <linux/usb/ch9.h> +} + +#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3]) + +#define SCSI_SENSE_BUFFERSIZE 96 + +#define UASP_LUN_NUM 0 + +typedef unsigned char u8; +typedef unsigned short u16; + +/* IU identifier summary - see table 10 of the UAS Spec */ +enum iu_id { + IU_ID_COMMAND = 0x01, + IU_ID_SENSE = 0x03, + IU_ID_RESPONSE = 0x04, + IU_ID_TASK_MANAGEMENT = 0x05, + IU_ID_READ_READY = 0x06, + IU_ID_WRITE_READY = 0x07, +}; + +/* COMMAND IU - Section 6.2.2 from UAS Spec */ +struct cmd_iu { + u8 iu_id; /* should be set to 01h*/ + u8 reserved; + u16 tag; /* section 4.2 of the UAS spec*/ + + u8 b; + + u8 reserved5; /* Should be set to 0 */ + u8 length; /* + * length is represented only by bits 2-7. + * bits 0-1 are reserved + */ + u8 reserved7; /*place holder. should be 0*/ + u8 lun[8]; + u8 cdb[16]; + u8 *add_cdb; /* Additional cdb bytes*/ +}; +#define CMDIU_SIZE 36 + + +/* TM FUNCTION IU - see table 19 of the UAS Spec */ +struct tm_iu { + u8 iu_id; /* Should be set to 05h */ + u8 reserved1; + u16 tag; /* section 4.2 of the UAS spec*/ + u8 tm_function; /* valid values defined in tm_function_data */ + u8 reserved5; + /* Reserved for all tm_functions but ABORT_TASK and QUERY_TASK */ + u16 task_tag; + u8 lun[8]; +}; +#define TMIU_SIZE 16 + +/* SENSE IU - section 6.2.5 of the UAS spec */ +struct sense_iu { + u8 iu_id; /* should be 0x03h*/ + u8 reserved1; + u16 tag; /* section 4.2 of the UAS spec*/ + u16 status_qual; + u8 status; /* Status code*/ + u8 rsvd8[6]; + u16 len; + u8 sense_data[SCSI_SENSE_BUFFERSIZE]; +}; +#define SENSEIU_SIZE (16 + SCSI_SENSE_BUFFERSIZE) + +/* STATUS values of SENSE IU as defined in SAM-4 */ +enum status_code_data { + STATUS_GOOD = 0x00, + STATUS_CHECK_CONDITION = 0x02, + STATUS_CONDITION_MET = 0x04, + STATUS_BUSY = 0x08, + STATUS_RESERVATION_CONFLICT = 0x18, + STATUS_TASK_SET_FULL = 0x28, + STATUS_ACA_ACTIVE = 0x30, + STATUS_TASK_ABORTED = 0x40, +}; + +/* RESPONSE IU - see table 17 of the UAS Spec */ +struct response_iu { + u8 iu_id; /* Should be set to 04h*/ + u8 reserved; + u16 tag; /* section 4.2 of the UAS spec*/ + u8 resp_info[3]; + u8 status; /* Response code*/ +}; +#define RESPONSEIU_SIZE 8 + +/* Response code values of RESPONSE IU - see table 18 of the UAS Spec */ +enum response_code_data { + RESPONSE_TM_FUNCTION_COMPLETE = 0x00, + RESPONSE_INVALID_IU = 0x02, + RESPONSE_TM_FUNCTION_NOT_SUPPORTED = 0x04, + RESPONSE_TM_FUNCTION_FAILED = 0x05, + RESPONSE_TM_FUNCTION_SUCCEEDED = 0x08, + RESPONSE_INCORRECT_LUN = 0x09, + RESPONSE_OVERLAPPED_TAG_ATTEMPTED = 0x0A, +}; + +/* READ/WRITE READY IU - see table 14/15 of the UAS Spec */ +struct rw_ready_iu { + u8 iu_id; + u8 reserved; + u16 tag; /* section 4.2 of the UAS spec */ +}; +#define UASP_SIZEOF_RW_READY_IU 4 + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE 0 +#define SS_COMMUNICATION_FAILURE 0x040800 +#define SS_INVALID_COMMAND 0x052000 +#define SS_INVALID_FIELD_IN_CDB 0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +#define SS_MEDIUM_NOT_PRESENT 0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +#define SS_RESET_OCCURRED 0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +#define SS_UNRECOVERED_READ_ERROR 0x031100 +#define SS_WRITE_ERROR 0x030c02 +#define SS_WRITE_PROTECTED 0x072700 +#define SS_OVERLAPPED_COMMANDS_ATTEMPTED 0x0b4e00 + +inline u16 get_next_ip_tag() +{ + static u8 my_ip_tag = 1; + return my_ip_tag++; +} + +/** + * fill_cmd_iu() - Fills the command iu structure with given values + * @iu: pointer to the cmd_iu structure to fill + * @cdb_opcode: OpCode of the CDB to send + * @lun: LUN number + * @add_length: additional_length field of the CDB + * + */ +void fill_cmd_iu(struct cmd_iu *iu, u8 cdb_opcode, u8 lun, u8 add_length); + +/** + * exec_send_mode_sense10() - Test the MODE_SENSE10 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the MODE_SENSE10 SCSI command to the device and verifies + * the correct reply from it. + * It consists of several tests (according to the fields of the + * MODE_SENSE10 CDB) : + * - First test case: + * page code = 0x08 (cashing) + * pc = 0 (page control = return current values) + * - Second test case: + * page code = 0x08 (cashing) + * pc = 01 (page control = return changable values) + * + * Return 0 on success, -1 otherwise + */ +int exec_send_mode_sense10(struct libusb_device *dev); + +/** + * exec_send_mode_sense() - Test the MODE_SENSE(6) SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the MODE_SENSE(6) SCSI command to the device and + * verifies the correct reply from it. + * It consists of several tests (according to the fields of the MODE_SENSE CDB): + * - First test case: + * page code = 0x08 (cashing) + * pc = 0 (page control = return current values) + * - Second test case: + * page code = 0x08 (cashing) + * pc = 01 (page control = return changable values) + * + * Return 0 on success, -1 otherwise + */ +int exec_send_mode_sense(struct libusb_device *dev); + +/** + * exec_send_prevent_allow_removal() - Test the PREVENT_ALLOW_MEDIA_REMOVAL + * SCSI command + * @dev:pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_send_prevent_allow_removal(struct libusb_device *dev); + +/** + * exec_send_read_capacity() - Test the READ_CAPACITY SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the READ_CAPACITY SCSI command to the device and + * verifies the correct reply from it. + * + * Return 0 on success, -1 otherwise + */ +int exec_send_read_capacity(struct libusb_device *dev); + +/** + * exec_send_inquiry() - Test the INQUIRY SCSI command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the INQUIRY SCSI command to the device and verifies the + * correct reply from it. + * + * Return 0 on success, -1 otherwise + */ +int exec_send_inquiry(struct libusb_device *dev); + +/** + * exec_send_request_sense() - Test the REQUEST_SENCE command + * @dev: pointer to the libusb device to run the test on + * + * This function sends the REQUEST_SENCE SCSI command to the device and + * verifies the correct reply from it. + * + * Return 0 on success, -1 otherwise + */ +int exec_send_request_sense(struct libusb_device *dev); + +/** + * exec_test_unit_ready() - Test the TEST_UNIT_READY command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_unit_ready(struct libusb_device *dev); + +/** + * exec_test_read6() - Test the READ6 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read6(struct libusb_device *dev); + +/** + * exec_test_read10() - Test the READ10 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read10(struct libusb_device *dev); + +/** + * exec_test_read12() - Test the READ12 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read12(struct libusb_device *dev); + +/** + * exec_test_write6() - Test the WRITE6 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write6(struct libusb_device *dev); + +/** + * exec_test_write10() - Test the WRITE10 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write10(struct libusb_device *dev); + + +/** + * exec_test_write12() - Test the WRITE12 SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write12(struct libusb_device *dev); + +/** + * exec_test_write_huge() - Test the WRITE10 SCSI command with alot of data + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_write_huge(struct libusb_device *dev); + +/** + * exec_test_read_format_capacities() - Test the READ FORMAT CAPACITIES + * SCSI command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_read_format_capacities(struct libusb_device *dev); + +/** + * exec_test_start_stop() - Test the TEST_START_STOP_UNIT command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + * + * TODO: this test isn't full. It doesn't check that the unit was indeed + * started/ejected etc. It just verifies the completion status. + */ +int exec_test_start_stop(struct libusb_device *dev); + +/** + * exec_test_verify() - Test the VERIFY command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_verify(struct libusb_device *dev); + +/** + * exec_test_synchronize_cache() - Test the SYNCHRONIZE CACHE + * command + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_synchronize_cache(struct libusb_device *dev); + +/** + * exec_test_cmd_overlapped_tag() - Verifies correct behavior in + * case of CMD overlapped tag attempted + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_cmd_overlapped_tag(struct libusb_device *dev); + +/** + * exec_test_tm_reset_lun() - Test the LOGICAL LUN RESET TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_reset_lun(struct libusb_device *dev); + +/** + * exec_test_tm_abort_task() - Test the ABORT_TASK TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_abort_task(struct libusb_device *dev); + +/** + * exec_test_tm_abort_task_set() - Test the ABORT TASK SET TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_abort_task_set(struct libusb_device *dev); + +/** + * exec_test_tm_reset_nexus() - Test the RESET NEXUS TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_reset_nexus(struct libusb_device *dev); + +/** + * exec_test_tm_query_async_ev() - Test the QUERY ASYNC EVENT TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_query_async_ev(struct libusb_device *dev); + +/** + * exec_test_tm_abort_cmd() - Test the QUERY TASK TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_query_task(struct libusb_device *dev); + +/** + * exec_test_tm_query_task_set() - Test the QUERY TASK SET TM + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_query_task_set(struct libusb_device *dev); + +/** + * exec_test_tm_overlapped_tag() - Verifies correct behavior in + * case of TM overlapped tag attempted + * @dev: pointer to the libusb device to run the test on + * + * Return 0 on success, -1 otherwise + */ +int exec_test_tm_overlapped_tag(struct libusb_device *dev); +#endif /*_UASP_TESTS_H*/ diff --git a/tools/usb/unittests/usb/composite_tests.cc b/tools/usb/unittests/usb/composite_tests.cc new file mode 100644 index 0000000..ea79f36 --- /dev/null +++ b/tools/usb/unittests/usb/composite_tests.cc @@ -0,0 +1,1646 @@ +/* + * composite_tests.c - USB composite device general tests + * + * Coding convention: + * External functions begin with test_ sufix. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include "libusb_utils.h" +#include "hs_expected_desc.h" +#include "ss_expected_desc.h" +#include "usb_tests.h" +#include "ut_config.h" + + +/** + * dump_dev_descriptor() - prints the received device descriptor + * @dev_desc: device descriptor to print + */ +static void dump_dev_descriptor(struct libusb_device_descriptor dev_desc) +{ + printf("Device descriptor:\n" + "bLength %5u\n" + "bDescriptorType %5u\n" + "bcdUSB 0x%02x\n" + "bDeviceClass %5u\n" + "bDeviceSubClass %5u\n" + "bDeviceProtocol %5u\n" + "bMaxPacketSize0 %5u\n" + "idVendor %5u\n" + "idProduct 0x%02x\n" + "bcdDevice 0x%02x\n" + "bNumConfigurations %5u\n", + dev_desc.bLength, dev_desc.bDescriptorType, dev_desc.bcdUSB, + dev_desc.bDeviceClass, dev_desc.bDeviceSubClass, + dev_desc.bDeviceProtocol, dev_desc.bMaxPacketSize0, + dev_desc.idVendor, dev_desc.idProduct, dev_desc.bcdDevice, + dev_desc.bNumConfigurations); +} + +/** + * dump_ep_desc() - prints the endpoint descriptor + * @ep_desc: endpoint descriptor to print + */ +static void dump_ep_desc(struct libusb_endpoint_descriptor *ep_desc) +{ + printf("Endpoint descriptor:\n" + "bLength %5u\n" + "bDescriptorType %5u\n" + "bEndpointAddress %5u (%s endpoint)\n", + ep_desc->bLength, ep_desc->bDescriptorType, + ep_desc->bEndpointAddress, + ((ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) ? + "IN" : "OUT")); + + printf("bmAttributes %5u ",ep_desc->bmAttributes); + + switch (usb_endpoint_type( + (const struct usb_endpoint_descriptor *)ep_desc)){ + case USB_ENDPOINT_XFER_CONTROL: + printf("Transfer Type CONTROL\n"); + break; + case USB_ENDPOINT_XFER_ISOC: + printf("Transfer Type ISOC\n"); + break; + case USB_ENDPOINT_XFER_BULK: + printf("Transfer Type BULK\n"); + break; + case USB_ENDPOINT_XFER_INT: + printf("Transfer Type INTR\n"); + break; + default: + printf("Transfer Type Unknown\n"); + break; + } + printf("wMaxPacketSize 0x%02x\n" + "bInterval %5u\n", + ep_desc->wMaxPacketSize, ep_desc->bInterval); +} + + +/** + * check_ep_descriptor() - Verify the recived endpoint descriptor + * @ep_desc: the endpoint descriptor to check + * @ref_ep_desc: reference endpoint descriptor + * + * Returns 0 on sucsess -1 for failure + * + * This function checks the validity of a given endpoint descriptor of the + * connected device according to the supplied reference descriptor + */ +static int check_ep_descriptor(struct libusb_endpoint_descriptor *ep_desc, + struct libusb_endpoint_descriptor *ref_ep_desc) +{ + if ((ep_desc->bmAttributes != ref_ep_desc->bmAttributes) || + (ep_desc->wMaxPacketSize != ref_ep_desc->wMaxPacketSize) || + (ep_desc->bInterval != ref_ep_desc->bInterval) || + ((ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) != + (ref_ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK))) + return -1; + return 0; +} + +/** + * check_dev_desc() - Verify the recived device descriptor + * @dev: libusb device to check + * @ref_dev_desc: reference device descriptor to check according to + * + * Returns 0 on sucsess -1 for failure + * + * This function checks the validity of the device descriptor of the connected + * device according to the provided reference device descriptor + */ +static int check_dev_desc(libusb_device *dev, + struct libusb_device_descriptor ref_dev_desc) +{ + struct libusb_device_descriptor dev_desc; + if (libusb_get_device_descriptor(dev,&dev_desc)) + { + printf("Couldn't get device descriptor\n"); + return -1; + } + + if (dev_desc.bcdUSB != ref_dev_desc.bcdUSB || + dev_desc.bMaxPacketSize0 != ref_dev_desc.bMaxPacketSize0) + { + printf("Incompatible Device descriptor! Expected:\n"); + dump_dev_descriptor(ref_dev_desc); + printf("\nReceived:\n"); + dump_dev_descriptor(dev_desc); + return -1 ; + } + if (ut_debug) + dump_dev_descriptor(dev_desc); + return 0; +} + +/** + * soursesink_test_setup() - Send a control request to setup/begin a spesific + * test (to be handled by f_soursesink). + * @udev: libusb device handle for the opened device + * @dev: libusb device + * @reques: the request code to send . Handled requests are: + * 0x5e - set up the bulk buffer size + * @wValue: in case of request = 0x5e: size of the bulk buffer + * + * Returns: the number of bytes actually transferred on success, + * LIBUSB_ERROR_TIMEOUT if the transfer timed out + * LIBUSB_ERROR_PIPE if the control request was not supported by the device + * LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * another LIBUSB_ERROR code on other failures + * + * NOTE: the requests sent by this function are propriatary and are handled + * by g_zero (in sourcesink configuration) + */ +int soursesink_test_setup(struct libusb_device_handle *udev, + libusb_device *dev, + uint8_t request, + uint16_t wValue) +{ + if (!udev || !dev) + return LIBUSB_ERROR_IO; + + return libusb_control_transfer(udev, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_RECIPIENT_INTERFACE, + request, wValue, 0, NULL, 0, + BULK_TRANSFERR_TIMEOUT); +} + +/* HS Device tests */ + +/** + * check_hs_intr_desc() - Verify the recived interface descriptor + * @dev: libusb device to check descriptors for + * + * Returns 0 on success -1 for failure + * + * This function checks the validity of HS Interface descriptors (including + * endpoint descriptors) of the connected device according to the expected + * descriptors in hs_expected_desc.h + */ +static int check_hs_intr_desc(libusb_device *dev) +{ + struct libusb_config_descriptor *config; + struct libusb_interface_descriptor *interface_desc; + int i,j; + + config = (struct libusb_config_descriptor*) + malloc(sizeof(struct libusb_config_descriptor)); + if (!config) { + printf("Error in allocating memory\n"); + return -1; + } + + if (libusb_get_active_config_descriptor(dev, &config)) + goto check_hs_intr_err; + + for (i = 0; i < config->interface->num_altsetting; i++) { + interface_desc = (struct libusb_interface_descriptor *) + &(config->interface->altsetting[i]); + /* Go over the interface endpoints*/ + for (j = 0; j < interface_desc->bNumEndpoints; j++) { + struct libusb_endpoint_descriptor *ep_desc = + (struct libusb_endpoint_descriptor *) + &(interface_desc->endpoint[j]); + struct libusb_endpoint_descriptor *ref_ep_desc; + switch (ep_desc->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK){ + case USB_ENDPOINT_XFER_CONTROL: + /* TODO */ + break; + case USB_ENDPOINT_XFER_ISOC: + /* TODO */ + break; + case USB_ENDPOINT_XFER_BULK: + if (ep_desc->bEndpointAddress & + LIBUSB_ENDPOINT_IN) + ref_ep_desc = &hs_bulk_in_ep_desc; + else + ref_ep_desc = &hs_bulk_out_ep_desc; + break; + case USB_ENDPOINT_XFER_INT: + ref_ep_desc = &hs_intr_ep_desc; + break; + default: + printf("Unknown endpoint type!\n"); + goto check_hs_intr_err; + } + + if (!ref_ep_desc) + goto check_hs_intr_err; + + if (check_ep_descriptor(ep_desc, ref_ep_desc)){ + printf("Incompatible Endpoint descriptor! " + "Expected:\n"); + dump_ep_desc(ref_ep_desc); + printf("\nReceived:\n"); + dump_ep_desc(ep_desc); + goto check_hs_intr_err; + } + if (ut_debug) + dump_ep_desc(ep_desc); + } + } + + free(config); + return 0; +check_hs_intr_err: + free(config); + return -1; +} + +/** + * test_hs_descriptors() - checks the validity of HS device descriptors + * according to the expected descriptors in hs_expected_desc.h + * @dev: libusb device to check + * + * Returns 0 for sucsess -1 for failure + */ +int test_hs_descriptors(libusb_device *dev) +{ + struct libusb_device_handle *udev; + int ret; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto test_hs_desc_err; + } + + if (check_dev_desc(dev, hs_device_descriptor)) + goto test_hs_desc_err; + + if (check_hs_intr_desc(dev)) + goto test_hs_desc_err; + + ret = 0; + goto test_hs_desc_done; + +test_hs_desc_err: + ret = -1; +test_hs_desc_done: + libusb_close(udev); + return ret; +} + + +/* SS device tests */ + +/** + * dump_usb_ext_cap_desc() - prints the USB 2.0 extension device capability + * descriptor + * @usb_ext_cap: the descriptor to print + */ +static void dump_usb_ext_cap_desc( + struct libusb_usb_ext_cap_descriptor *usb_ext_cap) +{ + if (!usb_ext_cap) + return; + printf(" USB 2.0 extension device capability descriptor:\n" + " bLength %5u\n" + " bDescriptorType %5u\n" + " bDevCapabilityType %5u\n" + " bmAttributes 0x%02x, %s\n" + , + usb_ext_cap->bLength, + usb_ext_cap->bDescriptorType, + usb_ext_cap->bDevCapabilityType, + usb_ext_cap->bmAttributes, + (usb_ext_cap->bmAttributes & 0x1) ? + "Supports LPM" : "Doesn't support LPM"); +} + +/** + * dump_ss_usb_cap_desc() - prints the SuperSpeed USB capability descriptor + * @ss_usb_cap: the descriptor to print + */ +static void dump_ss_usb_cap_desc( + struct libusb_ss_usb_cap_descriptor *ss_usb_cap) +{ + static const char *speed[] = { + "None", + "Low Speed", + "Full Speed", + "Low & Full Speed", + "High Speed", + "Low & High Speed", + "Full & High Speed", + "Low, Full & High Speed", + "5Gbps Speed", + "Low & 5Gbps Speed", + "Full & 5Gbps Speed", + "Low, Full & 5Gbps Speed", + "High & 5Gbps Speed", + "Low, High & 5Gbps Speed", + "Full, High & 5Gbps Speed", + "Low, Full, High & 5Gbps Speed" + }; + + if (!ss_usb_cap) + return; + printf(" SuperSpeed USB capability descriptor:\n" + " bLength %5u\n" + " bDescriptorType %5u\n" + " bDevCapabilityType %5u\n" + " bmAttributes 0x%02x, %s\n" + " wSpeedSupported 0x%02x,\n %s%s\n" + " bFunctionalitySupport 0x%02x,\n %s%s\n" + " bU1devExitLat %5u\n" + " bU2devExitLat %5u\n", + ss_usb_cap->bLength, + ss_usb_cap->bDescriptorType, + ss_usb_cap->bDevCapabilityType, + ss_usb_cap->bmAttributes, + (ss_usb_cap->bmAttributes & 0x2) ? + "Supports LTM" : "Doesn't support LTM", + ss_usb_cap->wSpeedSupported, + " Supports ", + speed[ss_usb_cap->wSpeedSupported & 0xF], + ss_usb_cap->bFunctionalitySupport, + " Min speed at which all the functionality is available is ", + speed[ss_usb_cap->bFunctionalitySupport & 0xF], + ss_usb_cap->bU1devExitLat, + ss_usb_cap->bU2DevExitLat); +} + +/** + * dump_bos_desc()- prints the BOS descriptor. + * @bos: bos descriptor to print + */ +static void dump_bos_desc(struct libusb_bos_descriptor bos) +{ + printf("BOS descriptor:\n" + " bLength %5u\n" + " bDescriptorType %5u\n" + " wTotalLength %5u\n" + " bNumDeviceCaps %5u\n", + bos.bLength, bos.bDescriptorType, + bos.wTotalLength, bos.bNumDeviceCaps); +} + +/** + * dump_ep_comp_desc() - prints the SS Endpoint Companion Descriptor + * @ep_comp_desc: the descriptor to print + */ +static void dump_ep_comp_desc(struct libusb_ss_ep_comp_descriptor *ep_comp_desc) +{ + printf("Endpoint Companion Descriptor:\n" + " bLength %5u\n" + " bDescriptorType %5u\n" + " bMaxBurst %5u\n" + " bmAttributes %5u\n" + " wBytesPerInterval %5u\n", + ep_comp_desc->bLength, ep_comp_desc->bDescriptorType, + ep_comp_desc->bMaxBurst, ep_comp_desc->bmAttributes, + ep_comp_desc->wBytesPerInterval); +} + +/** + * check_ep_comp_descriptor() - checks the validity of endpoint companion + * descriptor + * @ep_comp_desc: the descriptor to check + * @ref_ep_comp_desc: reference descriptor to check according to + * + * Returns 0 for sucsess -1 for failure + * + * This function verifies the validity of the SS endpoint companion descriptor + * according to the provided reference endpoint companion descriptor + */ +static int check_ep_comp_descriptor( + struct libusb_ss_ep_comp_descriptor *ep_comp_desc, + struct libusb_ss_ep_comp_descriptor *ref_ep_comp_desc) +{ + if ((ep_comp_desc->bLength != ref_ep_comp_desc->bLength) || + (ep_comp_desc->bDescriptorType != + ref_ep_comp_desc->bDescriptorType) || + (ep_comp_desc->bMaxBurst != ref_ep_comp_desc->bMaxBurst) || + (ep_comp_desc->bmAttributes != ref_ep_comp_desc->bmAttributes) || + (ep_comp_desc->wBytesPerInterval != + ref_ep_comp_desc->wBytesPerInterval)) + return -1; + return 0; +} + +/** + * check_ss_intr_desc() - checks the validity of the interface + * @descriptor dev: libusb device to check descriptors for + * @num_expected_strms_in_ep: the number of expected streams for IN EP's + * ep_comp descriptor + * @num_expected_strms_out_ep: the number of expected streams for OUT EP's + * ep_comp descriptor + * + * Returns 0 on sucsess -1 for failure + * + * This function checks the validity of SS Interface descriptors (including + * endpoint descriptors) of the connected device according to the expected + * descriptors in ss_expected_desc.h + */ +static int check_ss_intr_desc(libusb_device *dev, int num_expected_strms_in_ep, + int num_expected_strms_out_ep) +{ + struct libusb_config_descriptor *config; + int i,j,k; + + if (libusb_get_active_config_descriptor(dev, &config)) + goto check_ss_intr_err; + + /* Go over the configuration interfaces */ + for (k = 0; k < config->bNumInterfaces; k++) { + struct libusb_interface interface = config->interface[k]; + /* Go over interface alternate settings */ + for (i = 0; i < interface.num_altsetting; i++) { + struct libusb_interface_descriptor *interface_desc = + (struct libusb_interface_descriptor *) + &(interface.altsetting[i]); + /* Go over the interface endpoints */ + for (j = 0; j < interface_desc->bNumEndpoints; j++) { + struct libusb_endpoint_descriptor *ep_desc = + (struct libusb_endpoint_descriptor *) + &(interface_desc->endpoint[j]); + struct libusb_endpoint_descriptor *ref_ep_desc; + struct libusb_ss_ep_comp_descriptor + ref_ep_comp_desc_copy; + struct libusb_ss_ep_comp_descriptor + *ref_ep_comp_desc; + switch (ep_desc->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK){ + case USB_ENDPOINT_XFER_CONTROL: + /* TODO */ + break; + case USB_ENDPOINT_XFER_ISOC: + /* TODO */ + break; + case USB_ENDPOINT_XFER_BULK: + if (ep_desc->bEndpointAddress & + LIBUSB_ENDPOINT_IN){ + ref_ep_desc = + &ss_bulk_in_ep_desc; + memcpy(&ref_ep_comp_desc_copy, + &ss_bulk_in_ep_comp_desc, + sizeof(struct libusb_ss_ep_comp_descriptor)); + ref_ep_comp_desc_copy.bmAttributes = + num_expected_strms_in_ep; + ref_ep_comp_desc = + &ref_ep_comp_desc_copy; + }else { + ref_ep_desc = + &ss_bulk_out_ep_desc; + memcpy(&ref_ep_comp_desc_copy, + &ss_bulk_out_ep_comp_desc, + sizeof(struct libusb_ss_ep_comp_descriptor)); + ref_ep_comp_desc_copy.bmAttributes = + num_expected_strms_out_ep; + ref_ep_comp_desc = + &ref_ep_comp_desc_copy; + } + break; + case USB_ENDPOINT_XFER_INT: + ref_ep_desc = &ss_intr_ep_desc; + ref_ep_comp_desc = + &ss_intr_ep_comp_desc; + break; + default: + printf("Unknown endpoint type!\n"); + goto check_ss_intr_err; + } + + if (!ref_ep_desc) + goto check_ss_intr_err; + + if (check_ep_descriptor(ep_desc, ref_ep_desc)){ + printf("Incompatible Endpoint " + "descriptor! Expected:\n"); + dump_ep_desc(ref_ep_desc); + printf("\nReceived:\n"); + dump_ep_desc(ep_desc); + goto check_ss_intr_err; + } + + /* Check endpoint companion descriptor */ + if (!ep_desc->ep_comp) { + printf("Endpoint companion descriptor " + "is missing!\n"); + goto check_ss_intr_err; + } + if (check_ep_comp_descriptor(ep_desc->ep_comp, + ref_ep_comp_desc)) { + printf("Incompatible Endpoint " + "companion descriptor! " + "Expected:\n"); + dump_ep_comp_desc(ref_ep_comp_desc); + printf("\nReceived:\n"); + dump_ep_comp_desc(ep_desc->ep_comp); + goto check_ss_intr_err; + } + + if (ut_debug) { + dump_ep_desc(ep_desc); + dump_ep_comp_desc(ep_desc->ep_comp); + } + } + } + } + + return 0; +check_ss_intr_err: + return -1; +} + +/** + * check_bos_desc() - checks the validity of the BOS descriptor + * @dev: the libusb device to check the descriptors for + * + * Returns 0 for sucsess -1 for failure + * + * This function checks the SS USB device BOS descriptor (and its sub + * descriptors) according to the expected descriptors in ss_expected_desc.h + */ +static int check_bos_desc(libusb_device *dev) +{ + struct libusb_device_handle *udev; + struct libusb_bos_descriptor bos; + int ret; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + + memset (&bos, 0, sizeof(bos)); + ret = libusb_utils_get_bos_desc(dev, udev, &bos); + if (ret < 0) { + perror("can't get BOS descriptor"); + goto test_bos_error; + } + + if (ut_debug){ + dump_bos_desc(bos); + dump_usb_ext_cap_desc(bos.usb_ext_cap); + dump_ss_usb_cap_desc(bos.ss_usb_cap); + } + + /* BOS descriptor */ + if ((bos.bLength != ss_bos_desc.bLength) || + (bos.bDescriptorType != ss_bos_desc.bDescriptorType) || + (bos.wTotalLength != ss_bos_desc.wTotalLength) || + (bos.bNumDeviceCaps != ss_bos_desc.bNumDeviceCaps)){ + printf("Incompatible BOS descriptor! Expected:\n"); + dump_bos_desc(ss_bos_desc); + printf("\nReceived:\n"); + dump_bos_desc(bos); + goto test_bos_error; + } + + /* USB 2.0 extension device capability descriptor */ + if (bos.usb_ext_cap) { + struct libusb_usb_ext_cap_descriptor *usb_ext_cap; + struct libusb_usb_ext_cap_descriptor *exp_usb_ext_cap; + + usb_ext_cap = bos.usb_ext_cap; + exp_usb_ext_cap = &ss_usb20_ext_desc; + if ((usb_ext_cap->bLength != exp_usb_ext_cap->bLength) || + (usb_ext_cap->bDescriptorType != + exp_usb_ext_cap->bDescriptorType) || + (usb_ext_cap->bDevCapabilityType != + exp_usb_ext_cap->bDevCapabilityType) || + (usb_ext_cap->bmAttributes != + exp_usb_ext_cap->bmAttributes) || + (usb_ext_cap->bmAttributes != + exp_usb_ext_cap->bmAttributes)){ + printf("Incompatible USB 2.0 extension device " + "capability descriptor! Expected:\n"); + dump_usb_ext_cap_desc(exp_usb_ext_cap); + printf("\nReceived:\n"); + dump_usb_ext_cap_desc(usb_ext_cap); + goto test_bos_error; + } + } else + goto test_bos_error; + + /* SuperSpeed USB capability descriptor */ + if (bos.ss_usb_cap) { + struct libusb_ss_usb_cap_descriptor *ss_usb_cap; + struct libusb_ss_usb_cap_descriptor *exp_ss_usb_cap; + + ss_usb_cap = bos.ss_usb_cap; + exp_ss_usb_cap = &ss_usb_capability_desc; + if((ss_usb_cap->bLength != exp_ss_usb_cap->bLength) || + (ss_usb_cap->bDescriptorType != + exp_ss_usb_cap->bDescriptorType) || + (ss_usb_cap->bDevCapabilityType != + exp_ss_usb_cap->bDevCapabilityType) || + (ss_usb_cap->bmAttributes != exp_ss_usb_cap->bmAttributes) || + (ss_usb_cap->wSpeedSupported != + exp_ss_usb_cap->wSpeedSupported) || + (ss_usb_cap->bFunctionalitySupport != + exp_ss_usb_cap->bFunctionalitySupport) || + (ss_usb_cap->bU1devExitLat != + exp_ss_usb_cap->bU1devExitLat) || + (ss_usb_cap->bU2DevExitLat != + exp_ss_usb_cap->bU2DevExitLat)){ + printf("Incompatible SuperSpeed USB capability " + "descriptor! Expected:\n"); + dump_ss_usb_cap_desc(exp_ss_usb_cap); + printf("\nReceived\n"); + dump_ss_usb_cap_desc(ss_usb_cap); + goto test_bos_error; + } + }else + goto test_bos_error; + + ret = 0; + goto test_bos_done; + +test_bos_error: + ret = -1; +test_bos_done: + libusb_close(udev); + return ret; +} + +/** + * test_ss_descriptors() - checks the validity of SS device descriptors + * according to the expected descriptors in ss_expected_desc.h + * @dev: libusb device to check + * @num_expected_strms_in_ep: the number of expected streams for IN EP's + * ep_comp descriptor + * @num_expected_strms_out_ep: the number of expected streams for OUT EP's + * ep_comp descriptor + * + * Returns 0 for sucsess -1 for failure + */ +int test_ss_descriptors(libusb_device *dev, int num_expected_strms_in_ep, + int num_expected_strms_out_ep) +{ + struct libusb_device_handle *udev; + int ret; + + if (!dev) + return -1; + + ret = libusb_open(dev, &udev); + if (ret) { + printf("Couldn't open device (%d) \n", ret); + return -1; + } + + if (check_dev_desc(dev, ss_device_descriptor)) + goto test_ss_desc_err; + + if (check_ss_intr_desc(dev, num_expected_strms_in_ep, + num_expected_strms_out_ep)) + goto test_ss_desc_err; + + if (check_bos_desc(dev)) + goto test_ss_desc_err; + + ret = 0; + goto test_ss_desc_done; + +test_ss_desc_err: + ret = -1; +test_ss_desc_done: + libusb_close(udev); + return ret; +} + +/** + * test_connect_disconnect() - initiates a connect/disconnect sequence by + * the device. + * @dev: libusb device + * @dev_speed: the original speed of the connected device (before the test) + * @num_expected_strms_in_ep: the number of expected streams for IN EP's + * ep_comp descriptor (the descriptors are used the verify the connection) + * @num_expected_strms_out_ep: the number of expected streams for OUT EP's + * ep_comp descriptor (the descriptors are used the verify the connection) + * + * Returns 0 for sucsess -1 for failure + * + * After the device is connected it's descriptors are verified according to the + * speed. The connection speed should be maintained! + */ +int test_connect_disconnect(libusb_device *dev, + enum usb_device_speed dev_speed, + int num_expected_strms_in_ep, + int num_expected_strms_out_ep) +{ + struct libusb_device_handle *udev; + libusb_device *new_dev; + int ret = -1; + uint16_t wValue; + + struct libusb_device_descriptor dev_desc; + if (libusb_get_device_descriptor(dev, &dev_desc)) + { + printf("Couldn't get device descriptor\n"); + return -1; + } + + if (ut_debug) + printf("In test_connect_disconnect\n"); + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + + ret = libusb_control_transfer(udev, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_RECIPIENT_DEVICE, + CONN_DISCONN_TEST, 0, 0, NULL, 0, + BULK_TRANSFERR_TIMEOUT); + + /* + * We ignore the LIBUSB_ERROR_NO_DEVICE because the device disconnects + * before the response is handled by the host + */ + if ((ret < 0) && (ret != LIBUSB_ERROR_NO_DEVICE)){ + printf("Couldn't send setup test control packet = %d\n", ret); + goto test_connect_disconnect_err; + } + + libusb_close(udev); + + /* Wait for test completion and verify dev. connection */ + (void)sleep(2); + + /* + * After the reenumeration we need to update the libusb device handle. + * The devnum isn't valid anymore so we need to update the productid + * and the vendorid according to device descriptor + */ + libusb_utils_exit(); + libusb_utils_init(); + new_dev = get_libusb_dev(); + if (!new_dev) { + return -1; + } + + /* Verify successfull conection by checking descriptors */ + switch (dev_speed) { + case USB_SPEED_SUPER: + printf("num_expected_strms_in_ep = %d\n", + num_expected_strms_in_ep); + printf("num_expected_strms_out_ep = %d\n", + num_expected_strms_out_ep); + ret = test_ss_descriptors(new_dev, num_expected_strms_in_ep, + num_expected_strms_out_ep); + break; + default: + ret = test_hs_descriptors(new_dev); + } + + goto test_connect_disconnect_done; + +test_connect_disconnect_err: + libusb_close(udev); +test_connect_disconnect_done: + return ret; +} + +/** + * test_get_status_functionality() - verify the GET_STATUS request handling + * @dev: Libusb device hook + * @in_udev: External hook to the libusb device + * @bmRequestType: The request's bmRequestType + * @expected_res: The expected post-action status + * + * Returns 0 for sucsess, (-1) for failure + * + * This is a general function that sends a GET_STATUS request to {HS / SS} + * {device / EP / interface} with test specific parameters + */ +static int test_get_status_functionality( + libusb_device *dev, + struct libusb_device_handle *in_udev, + uint8_t bmRequestType, + uint16_t wIndex, + unsigned char *expected_res) +{ + struct libusb_device_handle *udev = NULL; + unsigned char data[2] = {0}; + int transfer_res = 0, ret_val = 0; + bool init_libusb = 0; + + if (!in_udev) { + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + init_libusb = 1; + } + else { + udev = in_udev; + } + + transfer_res = libusb_control_transfer(udev, /* libusb_device_handle */ + bmRequestType, /* bmRequestType */ + LIBUSB_REQUEST_GET_STATUS, /* bRequest */ + 0, /* wValue */ + wIndex, /* wIndex */ + data, /* returned data */ + 2, /* wLength */ + CTL_REQ_TRANSFERR_TIMEOUT);/* timeout */ + + if ((transfer_res == LIBUSB_ERROR_NO_DEVICE) || + (transfer_res == LIBUSB_ERROR_TIMEOUT) || + (transfer_res == LIBUSB_ERROR_IO) || + (transfer_res == LIBUSB_ERROR_PIPE)) + { + printf("LIBUSB error (%d)\n", transfer_res); + ret_val = -1; + } + + if ( (data[0] != expected_res[0]) || (data[1] != expected_res[1]) ){ + printf("data (0x%x, 0x%x) != expected_res (0x%x, 0x%x)..\n", + data[0], data[1], expected_res[0], + expected_res[1]); + ret_val = -1; + } + + if (init_libusb) + libusb_close(udev); + + return ret_val; +} + +/** + * test_ss_get_status_default_device() - verify the GET_STATUS(dev) request + * handling + * @dev: Libusb device hook + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a GET_STATUS request to the ss device in default state + * (when LTM, U1 & U2 are not enabled) and checks that the response is as + * expected (section 9.4.5 in the USB3 standard) + */ +int test_ss_get_status_default_device(libusb_device *dev) +{ + return test_get_status_functionality(dev, NULL, + (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE), + 0x00, /* For GetStatus(DEVICE) request wIndex=0 */ + ss_get_status_default_device_expected); +} + +/** + * test_ss_get_status_default_interface() - verify the GET_STATUS(intr) request + * handling + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a GET_STATUS request to the ss interface in default state + * (section 9.4.5 in the USB3 standard) + */ +int test_ss_get_status_default_interface(libusb_device *dev, + int interface_id) +{ + return test_get_status_functionality(dev, NULL, + (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + interface_id, ss_get_status_default_interface_expected); +} + +/** + * test_ss_get_status_default_ep() - verify the GET_STATUS(ep) request handlind + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a GET_STATUS request to the ss endpoint in default state + * (section 9.4.5 in the USB3 standard). It's run for the BULK IN endpoint and + * assumes the device has such. + */ +int test_ss_get_status_default_ep(libusb_device *dev, + int interface_id) +{ + struct libusb_endpoint_descriptor *in_ep; + struct libusb_device_handle *udev = NULL; + int rc = -1; + + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + + in_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + + if (!in_ep) { + printf("Didn't find BULK IN endpoint!\n"); + goto ss_get_status_default_ep_done; + } + + rc = test_get_status_functionality(dev, udev, + ( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_ENDPOINT), + (uint16_t)in_ep->bEndpointAddress, + ss_get_status_default_ep_expected); + +ss_get_status_default_ep_done: + libusb_close(udev); + return rc; +} + +/** + * test_hs_get_status_default_device() - verify the GET_STATUS(dev) request + * handling + * @dev: Libusb device hook + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a GET_STATUS request to the hs device in default state + * and checks that the response is as expected (section 9.4.5 in the USB2 + * standard) + */ +int test_hs_get_status_default_device(libusb_device *dev) +{ + return test_get_status_functionality(dev, NULL, + ( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE), + 0x00, /* For GetStatus(DEVICE) request wIndex=0 */ + hs_get_status_default_device_expected); +} + +/** + * test_hs_get_status_default_interface() - verify the GET_STATUS(intr) request + * handling + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a GET_STATUS request to the hs interface in default state + * (section 9.4.5 in the USB2 standard) + */ +int test_hs_get_status_default_interface(libusb_device *dev, + int interface_id) +{ + return test_get_status_functionality(dev, NULL, + (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + interface_id, hs_get_status_default_interface_expected); +} + +/** + * test_hs_get_status_default_ep() - verify the GET_STATUS(ep) request handlind + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a GET_STATUS request to the hs endpoint in default state + * (section 9.4.5 in the USB2 standard) + */ +int test_hs_get_status_default_ep(libusb_device *dev, + int interface_id) +{ + struct libusb_endpoint_descriptor *in_ep; + struct libusb_device_handle *udev = NULL; + int rc = -1; + + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + + in_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + + if (!in_ep) { + printf("Didn't find BULK IN endpoint!\n"); + goto hs_get_status_default_ep_done; + } + + rc = test_get_status_functionality(dev, udev, + ( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_ENDPOINT), + (uint16_t)in_ep->bEndpointAddress, + hs_get_status_default_ep_expected); + +hs_get_status_default_ep_done: + libusb_close(udev); + return rc; +} + +/** + * test_set_feature() - verify the SET_FEATURE request handling + * @dev: Libusb device hook + * @bmRequestType: The request's bmRequestType + * @wValue: The request's wValue + * @wIndex: The request's wIndex + * @pre_status:- The expected status before the set cmd + * @post_status: The expected status after the set cmd + * + * Returns 0 for sucsess, (-1) for failure + * + * This is a general function that sends a SET_FEATURE request + * to {HS / SS} {device / EP / interface} with test specific + * parameters. The tests verifies the new settings. + */ +static int test_set_feature(libusb_device *dev, + uint8_t bmRequestType, + uint16_t wValue, + uint16_t wIndex, + unsigned char *pre_status, + unsigned char *post_status) +{ + struct libusb_device_handle *udev = NULL; + int transfer_res = 0, ret_val = -1; + + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + + /* Make sure that pre status is as expected */ + ret_val = test_get_status_functionality(dev, udev, + LIBUSB_ENDPOINT_IN | bmRequestType, + wIndex, pre_status); + + if (ret_val) + { + printf("Set feature test: Initial status != expected..\n"); + goto exit_set_feature; + } + + transfer_res = libusb_control_transfer(udev, /* device_hdl */ + bmRequestType, /* req type */ + LIBUSB_REQUEST_SET_FEATURE, /* bRequest */ + wValue, /* wValue */ + wIndex, /* wIndex */ + NULL, /* ret data */ + 0, /* wLength */ + CTL_REQ_TRANSFERR_TIMEOUT); /* timeout */ + + if ((transfer_res == LIBUSB_ERROR_NO_DEVICE) || + (transfer_res == LIBUSB_ERROR_TIMEOUT) || + (transfer_res == LIBUSB_ERROR_IO) || + (transfer_res == LIBUSB_ERROR_PIPE) ) { + printf("LIBUSB error : (%d)\n", transfer_res); + ret_val = -1; + goto exit_set_feature; + } + + /* Make sure that post status is as expected */ + ret_val = test_get_status_functionality(dev, udev, + LIBUSB_ENDPOINT_IN | bmRequestType, + wIndex, post_status); + + if (ret_val) { + printf("Set feature test:Post SET status != expected..\n"); + goto exit_set_feature; + } + +exit_set_feature: + libusb_close(udev); + return ret_val; +} + +/** + * test_clear_feature() - verify the CLEAR_FEATURE + * request handling + * @dev: Libusb device hook + * @bmRequestType: The request's bmRequestType + * @wValue: The request's wValue + * @wIndex: The request's wIndex + * @pre_status:- The expected status before the set cmd + * @post_status: The expected status after the set cmd + * + * Returns 0 for sucsess, (-1) for failure + * + * This is a general function that sends a CLEAR_FEATURE request + * to {HS / SS} {device / EP / interface} with test specific + * parameters. The test verifies the new settings. + */ +static int test_clear_feature(libusb_device *dev, + uint8_t bmRequestType, + uint16_t wValue, + uint16_t wIndex, + unsigned char *pre_status, + unsigned char *post_status) +{ + struct libusb_device_handle *udev = NULL; + int transfer_res = 0, ret_val = -1; + + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + + /* Make sure that pre status is as expected */ + ret_val = test_get_status_functionality(dev, udev, + LIBUSB_ENDPOINT_IN | bmRequestType, + wIndex, pre_status); + + if (ret_val) + { + printf("Clear feature test: Initial status != expected..\n"); + goto exit_clear_feature; + } + + /* Send the CLEAR_FEATURE: */ + transfer_res = libusb_control_transfer(udev, /* device_hdl */ + bmRequestType, /* req type */ + LIBUSB_REQUEST_CLEAR_FEATURE, /* bRequest */ + wValue, /* wValue */ + wIndex, /* wIndex */ + NULL, /* ret data */ + 0, /* wLength */ + CTL_REQ_TRANSFERR_TIMEOUT); /* timeout */ + + if ( (transfer_res == LIBUSB_ERROR_NO_DEVICE) || + (transfer_res == LIBUSB_ERROR_TIMEOUT) || + (transfer_res == LIBUSB_ERROR_IO) || + (transfer_res == LIBUSB_ERROR_PIPE)) { + printf("LIBUSB error in CLEAR_FEATURE (%d)\n", transfer_res); + ret_val = -1; + goto exit_clear_feature; + } + + /* Make sure that we are back to the initial status */ + ret_val = test_get_status_functionality(dev, udev, + LIBUSB_ENDPOINT_IN | bmRequestType, + wIndex, post_status); + + if (ret_val) + printf("Clear feature test:Post CLEAR status != expected..\n"); + +exit_clear_feature: + libusb_close(udev); + return ret_val; +} + +/** + * test_set_feature_functionality() - verify the SET_FEATURE request handling + * @dev: Libusb device hook + * @bmRequestType: The request's bmRequestType + * @wValue: The request's wValue + * @wIndex: The request's wIndex + * @pre_status:- The expected status before the set cmd + * @post_status: The expected status after the set cmd + * + * Returns 0 for sucsess, (-1) for failure + * + * This is a general function that sends a SET_FEATURE request to {HS / SS} + * {device / EP / interface} with test specific parameters, after verifying the + * new settings, the tests clears the change. + */ +static int test_set_feature_functionality(libusb_device *dev, + uint8_t bmRequestType, + uint16_t wValue, + uint16_t wIndex, + unsigned char *pre_status, + unsigned char *post_status) +{ + int ret_val = -1; + + ret_val = test_set_feature(dev, + bmRequestType, + wValue, + wIndex, + pre_status, + post_status); + + if (ret_val < 0) { + printf("test_set_feature failed\n"); + return ret_val; + } + + ret_val = test_clear_feature(dev, + bmRequestType, + wValue, + wIndex, + post_status, + pre_status); + + if (ret_val < 0) { + printf("test_set_feature failed\n"); + return ret_val; + } + + return ret_val; +} + +/** + * test_ss_set_feature_u1_device() - verify the SET_FEATURE(U1) handling + * @dev: Libusb device hook + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss device in default state, + * to set the U1 power level capability + */ +int test_ss_set_feature_u1_device(libusb_device *dev) +{ + return test_set_feature_functionality(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE), U1_ENABLE_FEATURE_SEL, + /* For SetFeature/GetStatus for DEVICE requests + * wIndex = 0x00 + */ + 0x00, + ss_get_status_default_device_expected, + ss_get_status_U1_enabled_device_expected); +} + +/** + * test_ss_set_feature_u2_device() - verify the SET_FEATURE(U2) handling + * @dev: Libusb device hook + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss device in default state, + * to set the U2 power level capability + */ +int test_ss_set_feature_u2_device(libusb_device *dev) +{ + return test_set_feature_functionality(dev, + ( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE), U2_ENABLE_FEATURE_SEL, + /* For SetFeature/GetStatus for DEVICE requests + * wIndex = 0x00 + */ + 0x00, + ss_get_status_default_device_expected, + ss_get_status_U2_enabled_device_expected); +} + +/** + * test_ss_set_feature_ltm_device() - verify the SET_FEATURE(LTM) handling + * @dev: Libusb device hook + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss device in default state, + * to set the LTM capability + */ +int test_ss_set_feature_ltm_device(libusb_device *dev) +{ + return test_set_feature_functionality(dev, + ( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE), LTM_ENABLE_FEATURE_SEL, + /* For SetFeature/GetStatus for DEVICE requests + * wIndex = 0x00 + */ + 0x00, + ss_get_status_default_device_expected, + ss_get_status_LTM_enabled_device_expected); +} + +/** + * test_ss_set_feature_halt_ep() - verify the SET_FEATURE(HALT_EP) handling + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss EP in default state, to + * set the halt feature It's run for the BULK IN endpoint and assumes the + * device has such. + */ +int test_ss_set_feature_halt_ep(libusb_device *dev, + int interface_id) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *in_ep; + int ret_val = -1; + + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + in_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + libusb_close(udev); + + if (!in_ep) { + printf("Didn't find BULK IN endpoint!\n"); + goto ss_set_feature_halt_ep_done; + } + + ret_val = test_set_feature_functionality(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_ENDPOINT), + HALT_ENABLE_FEATURE_SEL, + (uint16_t)in_ep->bEndpointAddress, + ss_get_status_default_ep_expected, + ss_get_status_halt_enabled_ep_expected); + +ss_set_feature_halt_ep_done: + return ret_val; +} + +/** + * test_hs_set_feature_halt_ep() - verify the SET_FEATURE(HALT_EP) handling + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the hs EP in default state, + * to set the halt feature. It's run for the BULK IN endpoint and assumes the + * device has such. + */ +int test_hs_set_feature_halt_ep(libusb_device *dev, + int interface_id) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *in_ep; + int ret_val = -1; + + if (!dev) { + printf("libusb device == NULL..\n"); + return -1; + } + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + return -1; + } + in_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + libusb_close(udev); + + if (!in_ep) { + printf("Didn't find BULK IN endpoint!\n"); + goto hs_set_feature_halt_ep_done; + } + + ret_val = test_set_feature_functionality(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_ENDPOINT), + HALT_ENABLE_FEATURE_SEL, + (uint16_t)in_ep->bEndpointAddress, + hs_get_status_default_ep_expected, + hs_get_status_halt_enabled_ep_expected); + +hs_set_feature_halt_ep_done: + return ret_val; +} + +/** + * test_ss_set_feature_suspend_low_power_interface() - verify the + * SET_FEATURE(FUNCTION_SUSPEND) functionality + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss interface in default + * state, to set the suspend functionality for low power + */ +int test_ss_set_feature_suspend_low_power_interface(libusb_device *dev, + int interface_id) +{ + int ret_val = 0; + + /* Suspend the interface */ + ret_val = test_set_feature(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + SUSPEND_ENABLE_FEATURE_SEL, + interface_id | (FUNC_SUSPEND_OPT_LOW_POWER << 8), + hs_get_status_default_interface_expected, + ss_get_status_suspend_low_power_interface_expected); + + if (ret_val < 0) + goto ss_set_feature_suspend_interface_done; + + /* Check that the device suspended the interface */ + ret_val = usb_tests_read_gadget_sysfs_file((char*)GADGET_ZERO_FUNC_SUSPENDED_SYSFS_PATH); + if (ret_val != 1) { + printf("Function is not in suspend state, %d", ret_val); + goto ss_set_feature_suspend_interface_done; + } + + /* Resume the interface */ + ret_val = test_set_feature(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + SUSPEND_ENABLE_FEATURE_SEL, + interface_id, + ss_get_status_suspend_low_power_interface_expected, + hs_get_status_default_interface_expected); + + if (ret_val < 0) + goto ss_set_feature_suspend_interface_done; + + /* Check that the device resumed the interface */ + ret_val = usb_tests_read_gadget_sysfs_file((char*)GADGET_ZERO_FUNC_SUSPENDED_SYSFS_PATH); + if (ret_val != 0) { + printf("Function is in suspend state, %d", ret_val); + goto ss_set_feature_suspend_interface_done; + } + +ss_set_feature_suspend_interface_done: + return ret_val; +} + +/** + * test_ss_set_feature_suspend_remote_wakeup_interface() - verify the + * SET_FEATURE(FUNCTION_SUSPEND) functionality + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss interface in default + * state, to set the suspend functionality for remote wakeup + */ +int test_ss_set_feature_suspend_remote_wakeup_interface(libusb_device *dev, + int interface_id) +{ + int ret_val = 0; + + /* Suspended the interface */ + ret_val = test_set_feature(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + SUSPEND_ENABLE_FEATURE_SEL, + interface_id | (FUNC_SUSPEND_OPT_LOW_POWER << 8), + hs_get_status_default_interface_expected, + ss_get_status_suspend_low_power_interface_expected); + + if (ret_val < 0) + goto ss_set_feature_suspend_remote_wakeup_interface_done; + + /* Check that the device suspended the interface */ + ret_val = usb_tests_read_gadget_sysfs_file((char*)GADGET_ZERO_FUNC_SUSPENDED_SYSFS_PATH); + if (ret_val != 1) { + printf("Function is not in suspend state, %d", ret_val); + ret_val = -1; + goto ss_set_feature_suspend_remote_wakeup_interface_done; + } + + /* Set the Function Remote Wake capability */ + ret_val = usb_tests_write_gadget_sysfs_file_int( + (char*)ZERO_GADGET_ZERO_FUNC_WAKEUP_CAPABLE_SYSFS_PATH, 1); + if (ret_val != 0) { + printf("write file failed, %d", ret_val); + goto ss_set_feature_suspend_remote_wakeup_interface_done; + } + + /* Set the Function Remote Wake Enabled feature */ + ret_val = test_set_feature(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + SUSPEND_ENABLE_FEATURE_SEL, + interface_id | (FUNC_SUSPEND_OPT_WAKEUP_EN << 8), + ss_get_status_suspend_remote_wu_cap_interface_expected, + ss_get_status_suspend_remote_wu_en_cap_interface_expected); + + if (ret_val != 0) + goto ss_set_feature_suspend_remote_wakeup_interface_done; + + /* Check that the device enabled the Function Remote Wake */ + ret_val = usb_tests_read_gadget_sysfs_file( + (char*)ZERO_GADGET_ZERO_FUNC_WAKEUP_ENABLED_SYSFS_PATH); + if (ret_val != 1) { + printf("Function wake is not enabled, %d", ret_val); + goto ss_set_feature_suspend_remote_wakeup_interface_done; + } + + /* Trigger Function Remote Wake by the device */ + ret_val = usb_tests_write_gadget_sysfs_file_int( + (char*)ZERO_GADGET_ZERO_FUNC_WAKEUP_TRIGGER_SYSFS_PATH, 1); + if (ret_val != 0) { + printf("write file failed, %d", ret_val); + goto ss_set_feature_suspend_remote_wakeup_interface_done; + } + + /* Resume the interface */ + ret_val = test_set_feature(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + SUSPEND_ENABLE_FEATURE_SEL, + interface_id, + ss_get_status_suspend_remote_wu_en_cap_interface_expected, + ss_get_status_suspend_remote_wu_cap_interface_expected); + + if (ret_val < 0) + goto ss_set_feature_suspend_remote_wakeup_interface_done; + + /* Check that the device resumed the interface */ + ret_val = usb_tests_read_gadget_sysfs_file((char*)GADGET_ZERO_FUNC_SUSPENDED_SYSFS_PATH); + if (ret_val != 0) { + printf("Function is in suspend state, %d", ret_val); + goto ss_set_feature_suspend_remote_wakeup_interface_done; + } + + /* Clear the Function Remote Wake capability */ + ret_val = usb_tests_write_gadget_sysfs_file_int( + (char*)ZERO_GADGET_ZERO_FUNC_WAKEUP_CAPABLE_SYSFS_PATH, 0); + if (ret_val != 0) { + printf("write file failed, %d", ret_val); + goto ss_set_feature_suspend_remote_wakeup_interface_done; + } + + if (ret_val < 0) + goto ss_set_feature_suspend_remote_wakeup_interface_done; + +ss_set_feature_suspend_remote_wakeup_interface_done: + return ret_val; +} + +/** + * test_hs_set_feature_suspend_remote_wakeup_interface() - verify the + * SET_FEATURE(FUNCTION_SUSPEND) functionality + * @dev: Libusb device hook + * @interface_id: interface id to run the test on + * + * Returns 0 for sucsess, (-1) for failure + * + * This function sends a SET_FEATURE request to the ss interface in default + * state, to set the suspend functionality for remote wakeup + */ +int test_hs_set_feature_suspend_interface(libusb_device *dev, + int interface_id) +{ + return test_set_feature_functionality(dev, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_INTERFACE), + SUSPEND_ENABLE_FEATURE_SEL, + interface_id, + hs_get_status_default_interface_expected, + hs_get_status_default_interface_expected); +} + diff --git a/tools/usb/unittests/usb/composite_tests.h b/tools/usb/unittests/usb/composite_tests.h new file mode 100644 index 0000000..db68db0 --- /dev/null +++ b/tools/usb/unittests/usb/composite_tests.h @@ -0,0 +1,65 @@ +/* + * composite_tests.h - USB composite device general tests + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef COMPOSITE_TESTS_H +#define COMPOSITE_TESTS_H + +#include <linux/kernel.h> +#include <linux/usb/ch9.h> +#include "libusb_utils.h" + +int soursesink_test_setup(struct libusb_device_handle *udev, libusb_device *dev, + uint8_t request, uint16_t wValue); +int test_hs_descriptors(libusb_device *dev); +int test_ss_descriptors(libusb_device *dev, int num_expected_strms_in_ep, + int num_expected_strms_out_ep); +int test_connect_disconnect(libusb_device *dev, enum usb_device_speed dev_speed, + int num_expected_strms_in_ep, + int num_expected_strms_out_ep); +int test_ss_get_status_default_device(libusb_device *dev); +int test_ss_get_status_default_interface(libusb_device *dev, int interface_id); +int test_ss_get_status_default_ep(libusb_device *dev, int interface_id); +int test_hs_get_status_default_device(libusb_device *dev); +int test_hs_get_status_default_interface(libusb_device *dev, int interface_id); +int test_hs_get_status_default_ep(libusb_device *dev, int interface_id); +int test_ss_set_feature_u1_device(libusb_device *dev); +int test_ss_set_feature_u2_device(libusb_device *dev); +int test_ss_set_feature_ltm_device(libusb_device *dev); +int test_ss_set_feature_halt_ep(libusb_device *dev, int interface_id); +int test_hs_set_feature_halt_ep(libusb_device *dev, int interface_id); +int test_ss_set_feature_suspend_low_power_interface(libusb_device *dev, + int interface_id); +int test_ss_set_feature_suspend_remote_wakeup_interface(libusb_device *dev, + int interface_id); +int test_hs_set_feature_suspend_interface(libusb_device *dev, int interface_id); + +#endif /*COMPOSITE_TESTS_H*/ diff --git a/tools/usb/unittests/usb/g_serial_tests.cc b/tools/usb/unittests/usb/g_serial_tests.cc new file mode 100644 index 0000000..3da7870 --- /dev/null +++ b/tools/usb/unittests/usb/g_serial_tests.cc @@ -0,0 +1,198 @@ +/* + * g_serial_tests.c - generic USB serial function driver tests + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <linux/usb/ch9.h> + +#include "ut_config.h" +#include "libusb_utils.h" +#include "composite_tests.h" + +/** + * test_single_bulk_in() - Initiate a single bulk in transfer + * @dev: libusb device to test + * @data_size: size of the data buffer to receive + * @interface_id: interface id to run the test on + * + * Returns 0 on sucsess -1 for failure + * + * TODO: add data validity check + * add debug information! + */ +int test_single_bulk_in(libusb_device *dev, int data_size, + int interface_id) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *in_ep; + unsigned char *data_in; + int transferred = 0; + int ret; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto test_single_bulk_in_err; + } + + data_in = (unsigned char *)malloc(data_size+10); + if (!data_in) { + printf("Error allocating memory!\n"); + goto test_single_bulk_in_err; + } + + /* + * First send the control request to setup the buffer size on + * the device + */ + if (soursesink_test_setup(udev, dev, SET_BULK_BUF_SIZE, data_size) < 0){ + printf("Coldn't send setup test control packet\n"); + goto test_single_bulk_in_err; + } + + in_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + + if (!in_ep) { + printf("Didn't find BULK IN endpoint!\n"); + goto test_single_bulk_in_err; + } + + ret = libusb_bulk_transfer(udev, in_ep->bEndpointAddress, data_in, + data_size, &transferred, + BULK_TRANSFERR_TIMEOUT); + if (ret) { + printf("Transferr error %d (endpoint = %u)\n",ret, + in_ep->bEndpointAddress); + goto test_single_bulk_in_err; + } + + if (transferred != data_size) { + printf("The number of bytes actually " + "transferred (%d) != data size (%d)", + transferred, data_size); + goto test_single_bulk_in_err; + } + + ret = 0; + goto test_single_bulk_in_done; +test_single_bulk_in_err: + ret = -1; +test_single_bulk_in_done: + libusb_close(udev); + free(data_in); + return ret; +} + +/** + * test_single_bulk_out() - Initiate a single bulk out transfer + * @dev: libusb device to test + * @data_size: size of the data buffer to send + * @interface_id: interface id to run the test on + * + * Returns 0 on sucsess -1 for failure + * + * TODO: add data validity check + * add debug information! + */ +int test_single_bulk_out(libusb_device *dev, int data_size, + int interface_id) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *out_ep; + unsigned char *data_out; + int transferred = 0; + int ret, i; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + goto test_single_bulk_out_err; + } + + data_out = (unsigned char *)malloc(data_size+10); + if (!data_out) { + printf("Error allocating memory!\n"); + goto test_single_bulk_out_err; + } + + /*Fill in the data buffer*/ + for (i = 0; i < data_size; i++) + snprintf((char*)(&data_out[i]), 1, "%d", i); + + /*First send the control request to start the test in f_sourcesink*/ + if (soursesink_test_setup(udev, dev, 0x5e, data_size) < 0){ + printf("Codn't send setup test controll packet\n"); + goto test_single_bulk_out_err; + } + + out_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + + if (!out_ep) { + printf("Didn't find BULK OUT endpoint!\n"); + goto test_single_bulk_out_err; + } + + ret = libusb_bulk_transfer(udev, out_ep->bEndpointAddress, data_out, + data_size, &transferred, + BULK_TRANSFERR_TIMEOUT); + if (ret) { + printf("Transferr error %d (endpoint = %u)\n",ret, + out_ep->bEndpointAddress); + goto test_single_bulk_out_err; + } + + if (transferred != data_size) { + printf("The number of bytes actually transferred (%d) != " + "data size (%d)", transferred, data_size); + goto test_single_bulk_out_err; + } + + ret = 0; + goto test_single_bulk_out_done; +test_single_bulk_out_err: + ret = -1; +test_single_bulk_out_done: + libusb_close(udev); + free(data_out); + return ret; +} + diff --git a/tools/usb/unittests/usb/g_serial_tests.h b/tools/usb/unittests/usb/g_serial_tests.h new file mode 100644 index 0000000..48a2723 --- /dev/null +++ b/tools/usb/unittests/usb/g_serial_tests.h @@ -0,0 +1,68 @@ +/* + * g_serial_tests.h - generic USB serial function driver tests + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef G_SERIAL_TESTS_H +#define G_SERIAL_TESTS_H + +#include <linux/kernel.h> +#include "libusb_utils.h" + +/** + * test_single_bulk_in() - Initiate a single bulk in transfer + * @dev: libusb device to test + * @data_size: size of the data buffer to receive + * @interface_id: interface id to run the test on + * + * Returns 0 on sucsess -1 for failure + * + * TODO: add data validity check + * add debug information! + */ +int test_single_bulk_in(libusb_device *dev, int data_size, + int interface_id); + + +/** + * test_single_bulk_out() - Initiate a single bulk out transfer + * @dev: libusb device to test + * @data_size: size of the data buffer to send + * @interface_id: interface id to run the test on + * + * Returns 0 on sucsess -1 for failure + * + * TODO: add data validity check + * add debug information! + */ +int test_single_bulk_out(libusb_device *dev, int data_size, + int interface_id); + +#endif /*G_SERIAL_TESTS_H*/ diff --git a/tools/usb/unittests/usb/hs_expected_desc.h b/tools/usb/unittests/usb/hs_expected_desc.h new file mode 100644 index 0000000..3223038 --- /dev/null +++ b/tools/usb/unittests/usb/hs_expected_desc.h @@ -0,0 +1,164 @@ +/* + * hs_expected_desc.h - Expected descriptors when opperation in HS mode + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include "libusb_utils.h" + +/* This is the expected value for the HS device descriptor */ +struct libusb_device_descriptor hs_device_descriptor = { + 18, /* bLength */ + LIBUSB_DT_DEVICE, /* bDescriptorType */ + 0x0210, /* bcdUSB */ + 2, /* bDeviceClass = LIBUSB_CLASS_COMM */ + 0, /* bDeviceSubClass */ + 0, /* bDeviceProtocol */ + 64, /* bMaxPacketSize0 */ + 0x0525, /* idVendor; May be different */ + 0xa4a7, /* idProduct; May be different */ + 0, /* bcdDevice; TODO: update */ + 0, /* iManufacturer; May be different */ + 1, /* iProduct; May be different */ + 2, /* iSerialNumber; May be different */ + 1 /* bNumConfigurations */ +}; + +/* This is the expected value for the HS device BULK OUT endpoint descriptor */ +struct libusb_endpoint_descriptor hs_bulk_out_ep_desc = { + 7, /* bLength */ + LIBUSB_DT_ENDPOINT, /* bDescriptorType */ + LIBUSB_ENDPOINT_OUT, /* bEndpointAddress */ + 2, /* + * bmAttributes:Transfer Type Bulk + * Synch Type None + * Usage Type Data + */ + 512, /* wMaxPacketSize */ + 0, /* bInterval */ + 0, /* bRefresh; Not used since not audio device */ + 0, /* bSynchAddress; Not used */ + NULL, /* ep_comp */ + NULL, /* extra */ + 0 /* extra_length */ +}; + +/* This is the expected value for the HS device BULK IN endpoint descriptor */ +struct libusb_endpoint_descriptor hs_bulk_in_ep_desc = { + 7, /* bLength */ + LIBUSB_DT_ENDPOINT, /* bDescriptorType */ + LIBUSB_ENDPOINT_IN, /* bEndpointAddress */ + 2, /* + * bmAttributes:Transfer Type Bulk + * Synch Type None + * Usage Type Data + */ + 512, /* wMaxPacketSize */ + 0, /* bInterval */ + 0, /* bRefresh; Not used since not audio device */ + 0, /* bSynchAddress; Not used */ + NULL, /* ep_comp */ + NULL, /* extra */ + 0 /* extra_length */ +}; + +/* This is the expected value for the HS device INTERRUPT endpoint descriptor */ +struct libusb_endpoint_descriptor hs_intr_ep_desc = { + 7, /* bLength */ + LIBUSB_DT_ENDPOINT, /* bDescriptorType */ + LIBUSB_ENDPOINT_IN, /* bEndpointAddress */ + 3, /* + * bmAttributes:Transfer Type Interrupt + * Synch Type None + * Usage Type Data + */ + 0xa, /* wMaxPacketSize */ + 9, /* bInterval */ + 0, /* bRefresh; Not used since not audio device */ + 0, /* bSynchAddress; Not used */ + NULL, /* ep_comp */ + NULL, /* extra */ + 0 /* extra_length */ +}; + +/* This is the expected value for the HS device zero interface descriptor */ +struct libusb_interface_descriptor hs_zero_intr_descriptor = { + 9, /* bLength */ + LIBUSB_DT_INTERFACE, /* bDescriptorType */ + 0, /* bInterfaceNumber */ + 0, /* bAlternateSetting */ + 1, /* bNumEndpoints */ + LIBUSB_CLASS_COMM, /* bInterfaceClass; May be different*/ + 0, /* bInterfaceSubClass; Should be different */ + 0, /* bInterfaceProtocol; Should be different */ + 0, /* iInterface; Should be different */ + NULL, /* endpoint */ + NULL, /* extra */ + NULL /* extra_length */ +}; + +/* This is the expected value for the HS device interface descriptor */ +struct libusb_interface_descriptor hs_intr_descriptor = { + 9, /* bLength */ + LIBUSB_DT_INTERFACE, /* bDescriptorType */ + 1, /* bInterfaceNumber */ + 0, /* bAlternateSetting */ + 2, /* bNumEndpoints */ + LIBUSB_CLASS_DATA, /* bInterfaceClass; May be different */ + 0, /* bInterfaceSubClass; Should be different */ + 0, /* bInterfaceProtocol; Should be different */ + 0, /* iInterface; Should be different */ + NULL, /* endpoint */ + NULL, /* extra */ + NULL /* extra_length */ +}; + + +/* + * Expected returned data values for the HS GET_STATUS tests + * (dummy_hcd configuration..) + */ + +/* + * Expected result is 0x0001 - that means that only self-powered is enabled + * while Remote-wakeup is disabled + */ +unsigned char hs_get_status_default_device_expected[2] = { 0x01, 0x00}; + +/* Expected result is 0x0000 (all is reserved) */ +unsigned char hs_get_status_default_interface_expected[2] = { 0x00, 0x00}; + +/* Expected result is 0x0000 - that means that this ep is not halted */ +unsigned char hs_get_status_default_ep_expected[2] = { 0x00, 0x00}; + +/* Expected result is 0x0001 - that means that this ep is halt enabled */ +unsigned char hs_get_status_halt_enabled_ep_expected[2] = { 0x01, 0x00}; diff --git a/tools/usb/unittests/usb/libusb_utils.cc b/tools/usb/unittests/usb/libusb_utils.cc new file mode 100644 index 0000000..f8e60c7 --- /dev/null +++ b/tools/usb/unittests/usb/libusb_utils.cc @@ -0,0 +1,358 @@ +/* + * libusb_utils.c - libusb utilities + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include "libusb_utils.h" + +#include <linux/usb/ch9.h> + + +static libusb_device **devs; +static int devcnt; +static int was_initialized = false; + +/** + * libusb_utils_parse_descriptor() - gets a descriptor buffer and parses it + * to the descriptor message. + * @source: the descriptor buffer to be parsed + * @descriptor: the bit mapping of the descriptor, for example use "bbwd" + * for parsing a descriptor that contains byte, byte, 16-bit word, + * 32-bit word. + * @dest: a pointer to the descriptor message + * @host_endian: set host_endian if the w values are already in host endian + * format, as opposed to bus endian. + * + */ +int libusb_utils_parse_descriptor(unsigned char *source, + char *descriptor, void *dest, + int host_endian) +{ + unsigned char *sp = source, *dp = (unsigned char*)dest; + uint16_t w; + uint32_t d; + char *cp; + + for (cp = descriptor; *cp; cp++) { + switch (*cp) { + case 'b': /* 8-bit byte */ + *dp++ = *sp++; + break; + case 'w': + /* 16-bit word, convert from little endian to CPU */ + /* Align to word boundary */ + dp += ((unsigned long)dp & 1UL); + + if (host_endian) { + memcpy(dp, sp, 2); + } else { + w = (sp[1] << 8) | sp[0]; + *((uint16_t *)dp) = w; + } + sp += 2; + dp += 2; + break; + /* 32-bit word, convert from little endian to CPU */ + case 'd': + /* Align to dword boundary */ + dp = (unsigned char*)(((unsigned long)dp + 3) + & ~3UL); + if (host_endian) { + memcpy(dp, sp, 4); + } else { + d = (sp[3] << 24) | (sp[2] << 16) | + (sp[1] << 8) | sp[0]; + *((uint32_t *)dp) = d; + } + sp += 4; + dp += 4; + break; + } + } + return sp - source; +} + +/** + * libusb_utils_get_bos_desc() - returns the BOS descriptor + * @dev: libusb device + * @udev: libusb device handle for the opened device + * @bos: the bos descriptor + * + * Returns 0 on success -1 on failure + * + * This function is relevent only for SS device. + */ +int libusb_utils_get_bos_desc(struct libusb_device *dev, + struct libusb_device_handle *udev, + struct libusb_bos_descriptor *bos) +{ + unsigned char bos_buf[LIBUSB_DT_BOS_MAX_SIZE]; + int ret; + int ctrl_timeout = (5*1000); /* milliseconds */ + + if (!dev | !udev) + return -1; + + memset (bos_buf, 0, sizeof(bos_buf)); + + ret = libusb_control_transfer(udev, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_GET_DESCRIPTOR, + LIBUSB_DT_BOS << 8, 0, + bos_buf, sizeof bos_buf, ctrl_timeout); + + if (ret < 0 && errno != EPIPE) { + perror("can't get BOS"); + return -1; + } + + /* all supper-speed devices have a BOS */ + if ((ret == 0) || (bos_buf[1] != LIBUSB_DT_BOS)) { + printf("not a BOS descriptor, buf[1]=%x\n", bos_buf[1]); + return -1; + } + + libusb_parse_bos_desc(dev, bos, bos_buf); + + return 0; +} + +/** + * libusb_utils_get_device_by_num() - returns the device according to its + * bus number and device number + * @busnum: bus number + * @devnum: device number + * + * Returns pointer to the libusb device or NULL on failure + */ +libusb_device *libusb_utils_get_device_by_num(int busnum, int devnum) +{ + int i; + uint8_t bus, addr; + libusb_device *dev; + + for (i = 0; (dev = devs[i]) != NULL; i++) { + bus = libusb_get_bus_number(dev); + addr = libusb_get_device_address(dev); + + + if (((busnum != -1) && (busnum != bus)) || + ((devnum != -1) && (devnum != addr))) + continue; + + return dev; + } + return NULL; +} + +/** + * libusb_utils_get_device_by_product_vendor() -returns the device according to + * its product ID and vendor ID + * @vendorid: vendor ID + * @productid: product ID + * + * Returns pointer to the libusb device or NULL on failure + */ +libusb_device *libusb_utils_get_device_by_product_vendor(int vendorid, + int productid) +{ + int i; + libusb_device *dev; + + for (i = 0; (dev = devs[i]) != NULL; i++) { + struct libusb_device_descriptor dev_desc; + + if (libusb_get_device_descriptor(dev, &dev_desc) < 0) { + printf("Couldn't get device descriptor\n"); + return NULL; + } + if (((vendorid != -1) && (vendorid != (int)dev_desc.idVendor)) + || ((productid != -1) && + (productid != (int)dev_desc.idProduct))){ + printf("dev_desc.idVendor = %d, dev_desc.idProduct = %d" + "productid = %d, vendorid= %d\n", + (int)dev_desc.idVendor, + (int)dev_desc.idProduct, productid, vendorid); + continue; + } + return dev; + } + return NULL; +} + +static struct libusb_uasp_pipe_usage_desc *get_pipe_usage_desc( + unsigned char *extra_ep_data, + int extra_length +) +{ + struct libusb_uasp_pipe_usage_desc *pipe_usage_d = NULL; + if (extra_length < 0x04) + return NULL; + pipe_usage_d = (struct libusb_uasp_pipe_usage_desc *)extra_ep_data; + if (pipe_usage_d->bDescriptorType != LIBUSB_DT_PIPE_USAGE) + return NULL; + return pipe_usage_d; +} + +/** + * get_ep_from_intrf() - returns the endpoint descriptor + * @dev: libusb device + * @ep_type: endpoint type (USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}) + * @interface: the interface in which ep list to search for the endpoint + * @pipeID - for UASP device specify the pipe id of the + * endpoint. If not a UASP device pipeID=0 + * + * This function returns the endpoint descriptor (from a specified interfce) + * according to its transfer type direction, and if UASP device then pipe id. + * + * Returns the endpoint descriptor of the requested endpoint or NULL in case + * of error + */ +static struct libusb_endpoint_descriptor *get_ep_from_intrf( + struct libusb_interface *interface, + int direction, + int ep_type, + int pipeID +) +{ + int i,j; + struct libusb_uasp_pipe_usage_desc *pipe_desc = NULL; + /* Go over interface alternate settings */ + for (i = 0; i < interface->num_altsetting; i++) { + struct libusb_interface_descriptor *interface_desc = + (struct libusb_interface_descriptor *) + (interface->altsetting + i); + /* Go over the interface endpoints */ + for (j = 0; j < interface_desc->bNumEndpoints; j++) { + struct libusb_endpoint_descriptor *ep_desc = + (struct libusb_endpoint_descriptor *) + (interface_desc->endpoint + j); + if (((ep_desc->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == ep_type) && + ((ep_desc->bEndpointAddress & + LIBUSB_ENDPOINT_DIR_MASK) == direction)){ + if (!pipeID) + return ep_desc; + + pipe_desc = + get_pipe_usage_desc( + (unsigned char*)ep_desc->extra, + ep_desc->extra_length); + if (pipe_desc && + (pipe_desc->bPipeID == pipeID)) + return ep_desc; + } + } + } + return NULL; + +} + +/** + * libusb_utils_get_ep_desc() - returns the endpoint descriptor according to + * its transfer type, direction and if UASP device then pipe id. + * @dev: libusb device + * @ep_type: endpoint type (USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}) + * @intr_num: number of the interface the ep belongs to. + * If this value is -1 then we'll return the first ep that is complient + * with the direction and type, regardless of the interface + * @pipeID - for UASP device specify the pipe id of the + * endpoint. If not a UASP device pipeID=0 + * Returns the endpoint descriptor of the requested endpoint or NULL in case + * of error + */ +struct libusb_endpoint_descriptor *libusb_utils_get_ep_desc( + libusb_device *dev, + int direction, + int ep_type, + int intr_num, + int pipeID) +{ + struct libusb_config_descriptor *config; + int k; + struct libusb_endpoint_descriptor *ret_val = NULL; + + if (libusb_get_active_config_descriptor(dev, &config)) + return NULL; + + if ((intr_num > -1) && (intr_num < config->bNumInterfaces)) + ret_val = get_ep_from_intrf( + (struct libusb_interface *)(config->interface + intr_num), + direction, ep_type, pipeID); + else { + for (k = 0; k < config->bNumInterfaces; k++) { + ret_val = get_ep_from_intrf( + (struct libusb_interface *)(config->interface + k), + direction, ep_type, pipeID); + if (ret_val) + return ret_val; + } + } + return ret_val; +} + +/** + * libusb_utils_init() - initializes the libusb + * + * This function initializes the libusb and gets the list of devices. + * The function returns the number of devices + */ +int libusb_utils_init(void) +{ + int err = 0; + + if (was_initialized) + return devcnt; + + err = libusb_init(NULL); + if (err < 0) + return err; + devcnt = libusb_get_device_list(NULL, &devs); + was_initialized = true; + + return devcnt; +} + + +/** + * libusb_utils_exit() - un-inits the libusb + * + * This function un-inits the libusb and frees the device list + */ +void libusb_utils_exit(void) +{ + libusb_free_device_list(devs, 1); + was_initialized = false; + libusb_exit(NULL); +} diff --git a/tools/usb/unittests/usb/libusb_utils.h b/tools/usb/unittests/usb/libusb_utils.h new file mode 100644 index 0000000..96f9d93 --- /dev/null +++ b/tools/usb/unittests/usb/libusb_utils.h @@ -0,0 +1,149 @@ +/* + * libusb_utils.h - libusb utilities + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +extern "C" { +#include <libusb.h> +} + +/** + * libusb_utils_parse_descriptor() - gets a descriptor buffer and parses it + * to the descriptor message. + * @source: the descriptor buffer to be parsed + * @descriptor: the bit mapping of the descriptor, for example use "bbwd" for + * parsing a descriptor that contains byte, byte, 16-bit word, 32-bit word. + * @dest: a pointer to the descriptor message + * @host_endian: set host_endian if the w values are already in host endian + * format, as opposed to bus endian. + * + */ +int libusb_utils_parse_descriptor(unsigned char *source, + char *descriptor, void *dest, + int host_endian); + + +/** + * libusb_utils_get_device_by_num() - returns the device according to its + * bus number and device number + * @busnum: bus number + * @devnum: device number + * + * Returns pointer to the libusb device or NULL on failure + */ +libusb_device *libusb_utils_get_device_by_num(int busnum, int devnum); + + +/** + * libusb_utils_get_device_by_product_vendor() -returns the device according to + * its product ID and vendor ID + * @vendorid: vendor ID + * @productid: product ID + * + * Returns pointer to the libusb device or NULL on failure + */ +libusb_device *libusb_utils_get_device_by_product_vendor(int vendorid, + int productid); + +/** + * libusb_utils_get_ep_desc() - returns the endpoint descriptor according to + * its transfer type, direction and if UASP device then pipe id. + * @dev: libusb device + * @ep_type: endpoint type (USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}) + * @intr_num: number of the interface the ep belongs to. + * If this value is -1 then we'll return the first ep that is complient + * with the direction and type, regardless of the interface + * @pipeID - for UASP device specify the pipe id of the + * endpoint. If not a UASP device pipeID=0 + * Returns the endpoint descriptor of the requested endpoint or NULL in case + * of error + */ +struct libusb_endpoint_descriptor *libusb_utils_get_ep_desc( + libusb_device *dev, + int direction, + int ep_type, + int intr_num, + int pipeID); + +/** + * This function returns the endpoint descriptor according to + * its transfer type, direction and pipe usage. + * This function is used only with UASP device + * + * @param dev - libusb device + * @param ep_type - endpoint type (USB_ENDPOINT_XFER_{CONTROL, + * ISOC, BULK, INT}) + * @param intr_num - number of the interface the ep belongs to. + * If this value is -1 then we'll return the + * first ep that is complient with the direction + * and type, regardless of the interface + * @param pipeID - the usage of the pipe, one of the bellow + * PIPE_ID_CMD, PIPE_ID_STS, PIPE_ID_DATA_IN, + * PIPE_ID_DATA_OUT + * @return - the endpoint descriptor of the requested endpoint + * or NULL in case of error + */ +struct libusb_endpoint_descriptor *libusb_utils_get_ep_desc_by_usage( + libusb_device *dev, + int direction, + int ep_type, + int intr_num, + u_int8_t pipeID); + + +/** + * libusb_utils_get_bos_desc() - returns the BOS descriptor + * @dev: libusb device + * @udev: libusb device handle for the opened device + * @bos: the bos descriptor + * + * Returns 0 on success -1 on failure + * + * This function is relevent only for SS device. + */ +int libusb_utils_get_bos_desc(struct libusb_device *dev, + struct libusb_device_handle *udev, + struct libusb_bos_descriptor *bos); + +/** + * libusb_utils_init() - initializes the libusb + * + * This function initializes the libusb and gets the list of devices. + * The function returns the number of devices + */ +int libusb_utils_init(void); + +/** + * libusb_utils_exit() - un-inits the libusb + * + * This function un-inits the libusb and frees the device list + */ +void libusb_utils_exit(void); + diff --git a/tools/usb/unittests/usb/ss_expected_desc.h b/tools/usb/unittests/usb/ss_expected_desc.h new file mode 100644 index 0000000..36c2e74 --- /dev/null +++ b/tools/usb/unittests/usb/ss_expected_desc.h @@ -0,0 +1,291 @@ +/* + * ss_expected_desc.h - Expected descriptors when opperation in SS mode + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include "libusb_utils.h" + +extern "C" { +#include <linux/usb/ch9.h> +} + +/* + * Device capability type codes. Table 9-11 from USB 3.0 spec + * This should be defined in ch9.h but is not. Untill then we + * define it here + */ +#define USB_CAP_TYPE_USB20_EXTENSION 0x02 +#define USB_CAP_TYPE_SUPERSPEED_USB 0x03 +#define USB_CAP_TYPE_CONTAINER_ID 0x04 + + +/* This is the expected value for the SS device descriptor */ +struct libusb_device_descriptor ss_device_descriptor = { + 18, /* bLength; */ + LIBUSB_DT_DEVICE, /* bDescriptorType */ + 0x0300, /* bcdUSB */ + 2, /* bDeviceClass = LIBUSB_CLASS_COMM */ + 0, /* bDeviceSubClass */ + 0, /* bDeviceProtocol */ + 0x09, /* bMaxPacketSize0 */ + 0x0525, /* idVendor: May be different! */ + 0xa4a7, /* idProduct: May be different! */ + 0, /* bcdDevice. TODO: update */ + 0, /* iManufacturer. May be different! */ + 1, /* iProduct. May be different! */ + 2, /* iSerialNumber. May be different!*/ + 1 /* bNumConfigurations */ +}; + +/* This is the expected value for the SS device zero interface descriptor */ +struct libusb_interface_descriptor ss_zero_intr_descriptor = { + 9, /* bLength */ + LIBUSB_DT_INTERFACE, /* bDescriptorType */ + 0, /* bInterfaceNumber */ + 0, /* bAlternateSetting */ + 1, /* bNumEndpoints */ + LIBUSB_CLASS_COMM, /* bInterfaceClass. May be different */ + 0, /* bInterfaceSubClass. Should be different */ + 0, /* bInterfaceProtocol. Should be different */ + 0, /* iInterface. Should be different */ + NULL, /* endpoint */ + NULL, /* extra */ + NULL /* extra_length */ +}; + +/* This is the expected value for the SS device interface descriptor */ +struct libusb_interface_descriptor ss_intr_descriptor = { + 9, /* bLength */ + LIBUSB_DT_INTERFACE, /* bDescriptorType */ + 1, /* bInterfaceNumber */ + 0, /* bAlternateSetting */ + 2, /* bNumEndpoints */ + LIBUSB_CLASS_DATA, /* bInterfaceClass. May be different */ + 0, /* bInterfaceSubClass. Should be different */ + 0, /* bInterfaceProtocol. Should be different */ + 0, /* iInterface. Should be different */ + NULL, /* endpoint */ + NULL, /* extra */ + NULL /* extra_length */ +}; + + +/* This is the expected value for the SS device BULK OUT endpoint descriptor */ +struct libusb_endpoint_descriptor ss_bulk_out_ep_desc = { + 7, /* bLength */ + LIBUSB_DT_ENDPOINT, /* bDescriptorType */ + LIBUSB_ENDPOINT_OUT, /* bEndpointAddress */ + 2, /* + * bmAttributes:Transfer Type Bulk + * Synch Type None + * Usage Type Data + */ + 1024, /* wMaxPacketSize */ + 0, /* bInterval */ + 0, /* bRefresh; Not used */ + 0, /* bSynchAddress; Not used */ + NULL, /* ep_comp */ + NULL, /* extra */ + 0 /* extra_length */ +}; + +/* + * This is the expected (default) value for the SS device BULK OUT endpoint + * companion descriptor: bursting is not supported streaming is not supported + */ +struct libusb_ss_ep_comp_descriptor ss_bulk_out_ep_comp_desc = { + 6, /* bLength */ + LIBUSB_DT_SS_ENDPOINT_COMP,/* bDescriptorType */ + 0, /* bMaxBurst */ + 0, /* bmAttributes */ + 0 /* wBytesPerInterval */ +}; + + +/* This is the expected value for the SS device BULK IN endpoint descriptor */ +struct libusb_endpoint_descriptor ss_bulk_in_ep_desc = { + 7, /* bLength */ + LIBUSB_DT_ENDPOINT, /* bDescriptorType */ + LIBUSB_ENDPOINT_IN, /* bEndpointAddress */ + 2, /* + * bmAttributes:Transfer Type Bulk + * Synch Type None + * Usage Type Data + */ + 1024, /* wMaxPacketSize */ + 0, /* bInterval */ + 0, /* bRefresh. Not used since not audio device*/ + 0, /* bSynchAddress. Not used */ + NULL, /* ep_comp */ + NULL, /* extra */ + 0 /* extra_length */ +}; + +/* + * This is the expected (default) value for the SS device BULK IN endpoint + * companion descriptor: bursting is not supported, streaming is not supported + */ +struct libusb_ss_ep_comp_descriptor ss_bulk_in_ep_comp_desc = { + 6, /* bLength */ + LIBUSB_DT_SS_ENDPOINT_COMP,/* bDescriptorType */ + 0, /* bMaxBurst */ + 0, /* bmAttributes */ + 0 /* wBytesPerInterval */ +}; + +/* This is the expected value for the SS device INTERRUPT endpoint descriptor */ +struct libusb_endpoint_descriptor ss_intr_ep_desc = { + 7, /* bLength */ + LIBUSB_DT_ENDPOINT, /* bDescriptorType */ + LIBUSB_ENDPOINT_IN, /* bEndpointAddress */ + 3, /* + * bmAttributes:Transfer Type Interrupt + * Synch Type None + * Usage Type Data + */ + 0xa, /* wMaxPacketSize */ + 9, /* bInterval */ + 0, /* bRefresh. Not used since not audio device*/ + 0, /* bSynchAddress. */ + NULL, /* ep_comp */ + NULL, /* extra */ + 0 /* extra_length */ +}; + +/* + * This is the expected (default) value for the SS device INTERRUPT endpoint + * companion descriptor: bursting is not supported, streaming is not supported + */ +struct libusb_ss_ep_comp_descriptor ss_intr_ep_comp_desc = { + 6, /* bLength */ + LIBUSB_DT_SS_ENDPOINT_COMP,/* bDescriptorType */ + 0, /* bMaxBurst */ + 0, /* bmAttributes */ + 0xa /* wBytesPerInterval */ +}; + +/* This is the expected (default) value for the SS device BOS descriptor */ +struct libusb_bos_descriptor ss_bos_desc = { + 5, /* bLength */ + USB_DT_BOS, /* bDescriptorType */ + 22, /* wTotalLength */ + 2, /* bNumDeviceCaps */ + NULL, /* usb_ext_cap */ + NULL /* ss_usb_cap */ +}; + +/* + * This is the expected (default) value for the SS device USB 2.0 Extension + * descriptor + */ +struct libusb_usb_ext_cap_descriptor ss_usb20_ext_desc = { + 7, /* bLength */ + USB_DT_DEVICE_CAPABILITY,/* bDescriptorType */ + USB_CAP_TYPE_USB20_EXTENSION,/* bDevCapabilityType */ + 0X02 /* bmAttributes: Support LPM */ +}; + +/* + * This is the expected (default) value for the SS device SuperSpeed USB + * Capability descriptor: LTM not capble + */ +struct libusb_ss_usb_cap_descriptor ss_usb_capability_desc = { + 10, /* bLength */ + USB_DT_DEVICE_CAPABILITY,/* bDescriptorType */ + USB_CAP_TYPE_SUPERSPEED_USB,/* bDevCapabilityType */ + 0, /* bmAttributes */ + 0x0f, /* wSpeedSupported */ + 0x01, /* bFunctionalitySupport */ + 1, /* bU1devExitLat */ + 500 /* bU2DevExitLat */ +}; + + +/* + * Expected returned data values for the SS GET_STATUS tests + * (dummy_hcd configuration..) + */ + +/* Expected result is 0x0001 - that means that only self-powered is enabled */ +unsigned char ss_get_status_default_device_expected[2] = { 0x01, 0x00}; + +/* Expected result is 0x0005 - that means that self-powered, &U1 are enabled */ +unsigned char ss_get_status_U1_enabled_device_expected[2] = { 0x05, 0x00}; + +/* Expected result is 0x0009 - that means that self-powered, & U2 are enabled */ +unsigned char ss_get_status_U2_enabled_device_expected[2] = { 0x09, 0x00}; + +/* Expected result is 0x0011 - that means that self-powered & LTM are enabled */ +unsigned char ss_get_status_LTM_enabled_device_expected[2] = { 0x11, 0x00}; + +/* + * Expected result is 0x0000 - that means that this interface is + * Remote-wakeup capable + */ +unsigned char ss_get_status_default_interface_expected[2] = { 0x00, 0x00}; + +/* Expected result is 0x0001 - that means that this ep is halt enabled */ +unsigned char ss_get_status_halt_enabled_ep_expected[2] = { 0x01, 0x00}; + +/* Expected result is 0x0000 - that means that this ep is not halted */ +unsigned char ss_get_status_default_ep_expected[2] = { 0x00, 0x00}; + +/* + * Expected result is 0x0001 - that means that this interface's low power + * was enabled (lsb) + * In the case of g_zero due to the stub functionality, the + * expected value is 0x0000. + */ +unsigned char ss_get_status_suspend_low_power_interface_expected[2] = { + 0x00, 0x00}; + +/* + * Expected result is 0x0001 - that means that this interface's is remote + * wake up capable (bit #1) + */ +unsigned char ss_get_status_suspend_remote_wu_cap_interface_expected[2] = { + 0x01, 0x00}; + +/* + * Expected result is 0x0002 - that means that this interface's remote wake up + * was enabled (bit #2) + */ +unsigned char ss_get_status_suspend_remote_wu_en_interface_expected[2] = { + 0x02, 0x00}; + +/* +* Expected result is 0x0003 - that means that this interface's is remote +* wake up capable (bit #1) and was enabled (bit #2) +*/ +unsigned char ss_get_status_suspend_remote_wu_en_cap_interface_expected[2] = { + 0x03, 0x00}; diff --git a/tools/usb/unittests/usb/streams_tests.cc b/tools/usb/unittests/usb/streams_tests.cc new file mode 100644 index 0000000..5954bdb --- /dev/null +++ b/tools/usb/unittests/usb/streams_tests.cc @@ -0,0 +1,243 @@ +/* + * streams_tests.h - USB3 streams tests + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <linux/usb/ch9.h> + +#include "ut_config.h" +#include "libusb_utils.h" +#include "composite_tests.h" + +/** + * cb_transfer_complete() - Callback supplied to + * libusb_fill_bulk_transfer. The callback increases a counter + * implemented by the transfer's user_data variable. + * @transfer: the transfer that was cpmpleted + * + */ +static void cb_transfer_complete(struct libusb_transfer *transfer) +{ + int *completed = (int*)transfer->user_data; + fprintf(stderr, "cb_transfer_complete, user_data is %d \n", *completed); + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) + fprintf(stderr, "cb_transfer_complete with error %d\n", + transfer->status); + else + (*completed)++; +} + +/** + * test_streams_bulk_loopback() - Initiate N bulk OUT transfers + * on N streams, and verify reception on bulk IN EP. + * @dev: libusb device to test + * @data_size: size of the data buffer to send + * @interface_id: interface id to run the test on + * @num_streams: number of streams + * + * Returns 0 on sucsess -1 for failure + */ +int test_streams_bulk_loopback(libusb_device *dev, int data_size, + int interface_id, int num_streams) +{ + struct libusb_device_handle *udev; + struct libusb_endpoint_descriptor *out_ep, *in_ep; + unsigned char *data_out[num_streams]; + unsigned char *data_in[num_streams]; + int ret, i, j; + struct libusb_transfer *transfer[num_streams]; + int completed = 0; + unsigned int eps = 0; + + if (!dev) + return -1; + + if (libusb_open(dev, &udev)) { + printf("Couldn't open device\n"); + ret = -1; + goto test_bulk_loopback_done; + } + + for (j = 0; j < num_streams; j++) { + transfer[j] = libusb_alloc_transfer(0); + if (!transfer[j]) { + printf("Couldn't alloc transfer\n"); + ret = -1; + goto test_bulk_loopback_done; + } + } + + for (j = 0; j < num_streams; j++) { + data_out[j] = (unsigned char *)malloc(data_size+10); + data_in[j] = (unsigned char *)malloc(data_size+10); + } + + + /* Fill in the OUT data buffer with a pattern corresponding to stream_id */ + for (j = 0; j < num_streams; j++) + for (i = 0; i < data_size; i++) + { + data_out[j][i] = j+1; + data_in[j][i] = 0; + } + + /* We should reset the gadget so it would expect stream IDs starting + from 1 */ + if (libusb_reset_device(udev) < 0) + { + printf("Couldn't reset device"); + ret = -1; + goto test_bulk_loopback_done; + } + + out_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_OUT, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + + if (!in_ep) { + printf("Didn't find BULK OUT endpoint!\n"); + ret = -1; + goto test_bulk_loopback_done; + } + + in_ep = libusb_utils_get_ep_desc(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_TRANSFER_TYPE_BULK, + interface_id, PIPE_ID_UNDEF); + + if (!in_ep) { + printf("Didn't find BULK IN endpoint!\n"); + ret = -1; + goto test_bulk_loopback_done; + } + + eps |= (1 << (in_ep->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK)); + eps |= (0x10000 << (out_ep->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK)); + + printf("Allocting streams for ep map %d\n", eps); + + /* Allocate streams (Current implementation allocates 256 streams) */ + if (libusb_alloc_streams(udev, eps) < 0) + { + printf("Codn't alloc streams for OUT EP\n"); + ret = -1; + goto test_bulk_loopback_done; + } + + for (j = 0; j < num_streams; j++) { + libusb_fill_bulk_transfer(transfer[j], udev, out_ep->bEndpointAddress, + data_out[j], data_size, cb_transfer_complete, &completed, + BULK_TRANSFERR_TIMEOUT); + transfer[j]->flags = LIBUSB_TRANSFER_SHORT_NOT_OK + | LIBUSB_TRANSFER_FREE_TRANSFER; + transfer[j]->stream_id = j+1; + if (libusb_submit_transfer(transfer[j]) < 0) { + printf("Codn't submit transfer\n"); + ret = -1; + goto test_bulk_loopback_done; + } + } + + while (completed < num_streams) + libusb_handle_events(NULL); + + for (j = 0; j < num_streams; j++) { + if (transfer[j]->actual_length != data_size) { + printf("The number of bytes actually transferred (%d) != " + "data size (%d)", transfer[j]->actual_length, data_size); + ret = -1; + goto test_bulk_loopback_done; + } + } + + completed = 0; + + for (j = 0; j < num_streams; j++) { + transfer[j] = libusb_alloc_transfer(0); + if (!transfer[j]) { + printf("Couldn't alloc transfer\n"); + ret = -1; + goto test_bulk_loopback_done; + } + } + + for (j = 0; j < num_streams; j++) { + libusb_fill_bulk_transfer(transfer[j], udev, in_ep->bEndpointAddress, + data_in[j], data_size, cb_transfer_complete, &completed, + BULK_TRANSFERR_TIMEOUT); + transfer[j]->flags = LIBUSB_TRANSFER_SHORT_NOT_OK + | LIBUSB_TRANSFER_FREE_TRANSFER; + transfer[j]->stream_id = j+1; + if (libusb_submit_transfer(transfer[j]) < 0) { + printf("Codn't submit transfer\n"); + ret = -1; + goto test_bulk_loopback_done; + } + } + + while (completed < num_streams) + libusb_handle_events(NULL); + + for (j = 0; j < num_streams; j++) { + if (transfer[j]->actual_length != data_size) { + printf("The number of bytes actually transferred (%d) != " + "data size (%d)\n", transfer[j]->actual_length, data_size); + ret = -1; + goto test_bulk_loopback_done; + } + if (data_in[j][0] != transfer[j]->stream_id) { + printf("Epected data on stream is %d instead of %d\n", data_in[j][0], + transfer[j]->stream_id); + ret = -1; + goto test_bulk_loopback_done; + } + } + + if (libusb_free_streams(udev, eps) < 0) + { + printf("Codn't free streams for OUT EP\n"); + ret = -1; + goto test_bulk_loopback_done; + } + + ret = 0; +test_bulk_loopback_done: + libusb_close(udev); + + for (j = 0; j < num_streams; j++) { + free(data_out[j]); + free(data_in[j]); + } + + return ret; +} + diff --git a/tools/usb/unittests/usb/streams_tests.h b/tools/usb/unittests/usb/streams_tests.h new file mode 100644 index 0000000..5b1db91 --- /dev/null +++ b/tools/usb/unittests/usb/streams_tests.h @@ -0,0 +1,51 @@ +/* + * streams_tests.h - USB3 streams tests + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef STREAMS_TESTS_H +#define STREAMS_TESTS_H + +#include <linux/kernel.h> +#include "libusb_utils.h" + +/** + * test_streams_bulk_loopback() - Initiate N bulk OUT transfers + * on N streams, and verify reception on bulk IN EP. + * @dev: libusb device to test + * @data_size: size of the data buffer to send + * @interface_id: interface id to run the test on + * @num_streams: number of streams + * + * Returns 0 on sucsess -1 for failure + */ +int test_streams_bulk_loopback(libusb_device *dev, int data_size, + int interface_id, int num_streams); + +#endif /*STREAMS_TESTS_H*/ diff --git a/tools/usb/unittests/usb/usb_devel_mode.cc b/tools/usb/unittests/usb/usb_devel_mode.cc new file mode 100644 index 0000000..159a99b --- /dev/null +++ b/tools/usb/unittests/usb/usb_devel_mode.cc @@ -0,0 +1,185 @@ +/* + * This file implements the option of running the Unit Test FW in + * development mode. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include "usb_devel_mode.h" +#include "UASP_tests.h" + +/* This enum defines the tests that can be run in development mode */ +enum devel_commands{ + RUN_ALL_TESTS = 1, + SEND_SC_INQUIRY, + SEND_SC_REQUEST_SENSE, + TEST_UNIT_READY, + READ_CAPACITY, + MODE_SENSE, + MODE_SENSE10, + ALLOW_MEDIUM_REMOVAL, + READ_6, + READ_10, + READ_12, + WRITE_6, + WRITE_10, + WRITE_12, + WRITE10_HUGE, + READ_FORMAT_CAPACITIES, + TEST_START_STOP_UNIT, + TEST_VERIFY, + TEST_SYNC_CACHE, + TEST_TM_RESET_LUN, + TEST_TM_ABORT_TASK, + TEST_TM_ABORT_TASK_SET, + TEST_TM_RESET_NEXUS, + TEST_QUERY_ASYNC_EVENT, + TEST_QUERY_TASK, + TEST_QUERY_TASK_SET, + TEST_TM_TAG_OVERLAPP, + TEST_CMD_TAG_OVERLAPP, + ILEGAL_CMD /* Should be the last one! */ +}; + +struct exec_cmd { + int (*func)(struct libusb_device *dev); + char test_name[100]; +}; + +/** + * print_mem() - dump memory in the given location + * @buf: pointer to the memory buffer to print + * @size: size of buffer to print + * + */ +void print_mem(unsigned char *buf, int size) +{ + int i; + printf("Memory dump at %x:\n ", buf); + for (i = 0; i < size; i++) { + printf(" 0x%02x", buf[i]); + if (!(i % 24)) + printf("\n "); + } + printf("\n"); +} + +static int run_all_UASP_tests(struct libusb_device *dev); +static struct exec_cmd cmd_arr[] = { + {run_all_UASP_tests, "All UASP Tests"}, + {exec_send_inquiry, "INQUIRY CMD-IU (OpCode = 0x12)"}, + {exec_send_request_sense, "REQUEST_SENSE CMD-IU (OpCode = 0x03)"}, + {exec_test_unit_ready, "TEST_UNIT_READY (OpCode = 0x00)"}, + {exec_send_read_capacity, "READ_CAPACITY (OpCode = 0x25)"}, + {exec_send_mode_sense, "MODE_SENSE6 (OpCode = 0x01)"}, + {exec_send_mode_sense10, "MODE_SENSE10 (OpCode = 0x5a)"}, + {exec_send_prevent_allow_removal, + "ALLOW_MEDIUM_REMOVAL (OpCode = 0x1e)"}, + {exec_test_read6, "READ_6 (OpCode = 0x08)"}, + {exec_test_read10, "READ_10 (OpCode = 0x28)"}, + {exec_test_read12, "READ_12 (OpCode = 0xa8)"}, + {exec_test_write6, "WRITED_6 (OpCode = 0x0a)"}, + {exec_test_write10, "WRITE_10 (OpCode = 0x2a)"}, + {exec_test_write12, "WRITE_12 (OpCode = 0xaa)"}, + {exec_test_write_huge, "WRITE10 with huge data"}, + {exec_test_read_format_capacities, + "READ_FORMAT_CAPACITIES (OpCode = 0x23)"}, + {exec_test_start_stop, "START_STOP_UNIT (OpCode = ox1b)"}, + {exec_test_verify, "VERIFY (OpCode = 0x2f)"}, + {exec_test_synchronize_cache, "SYNCHRONIZE CACHE (OpCode = 0x35)"}, + {exec_test_tm_reset_lun, "TM LOGICAL UNIT RESET (Code = 0x08)"}, + {exec_test_tm_abort_task, "TM ABORT TASK (Code = 0x01)"}, + {exec_test_tm_abort_task_set, "TM ABORT TASK SET (Code = 0x02)"}, + {exec_test_tm_reset_nexus, "TM RESET NEXUS (Code = 0x10)"}, + {exec_test_tm_query_async_ev, "TM QUERY ASYNC EVENT (Code = 0x82)"}, + {exec_test_tm_query_task, "TM QUERY TASK (Code = 0x80)"}, + {exec_test_tm_query_task_set, "TM QUERY TASK SET (Code = 0x81)"}, + {exec_test_tm_overlapped_tag, "Test TM IU Tag Overlapping"}, + {exec_test_cmd_overlapped_tag, "Test CMD IU Tag Overlapping"}, +}; + +static int run_all_UASP_tests(struct libusb_device *dev) +{ + int i, rc; + for (i = 1; i < ILEGAL_CMD -1; i++) { + printf("\n\n Running Test %s:\n", cmd_arr[i].test_name); + rc = cmd_arr[i].func(dev); + if (rc) { + printf("\n Test #%i (%s) Failed!\n", i+1, + cmd_arr[i].test_name); + return rc; + } + sleep(1); + } + return rc; +} + +int run_in_devel_mode(struct libusb_device *dev) +{ + int choice = 0; + int ret_val = 0; + int i = 0; + + printf("\n\n\n---------------------------------------------" + "---------------------------------------------------\n"); + + printf("Choose command to perform:\nUASP commands:\n" + " 0. Exit\n"); + for (i = 0; i < ILEGAL_CMD - 1; i++) + printf(" %d. Run %s test\n", i+1, cmd_arr[i].test_name); + printf("Enter your choice: "); + (void)scanf("%d",&choice); + + while ((choice > 0) && (choice < ILEGAL_CMD)){ + if (cmd_arr[choice-1].func) + ret_val = cmd_arr[choice-1].func(dev); + else + printf("Sorry, %d command is not yet implemented\n", + choice); + + printf("\n\n\n---------------------------------------------" + "---------------------------------------------------\n"); + + printf("Choose command to perform:\nUASP commands:\n" + " 0. Exit\n"); + for (i = 0; i < ILEGAL_CMD - 1; i++) + printf(" %d. Run %s test\n", i+1, + cmd_arr[i].test_name); + printf("Enter your choice: "); + scanf("%d",&choice); + } + + return ret_val; +} diff --git a/tools/usb/unittests/usb/usb_devel_mode.h b/tools/usb/unittests/usb/usb_devel_mode.h new file mode 100644 index 0000000..03d9603 --- /dev/null +++ b/tools/usb/unittests/usb/usb_devel_mode.h @@ -0,0 +1,50 @@ +/* + * This file defines the option of running the Unit Test FW in + * development mode. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _USB_DEVEL_MODE_H +#define _USB_DEVEL_MODE_H + +#include "libusb_utils.h" + +int run_in_devel_mode(struct libusb_device *dev); + + +/** + * print_mem() - dump memory in the given location + * @buf: pointer to the memory buffer to print + * @size: size of buffer to print + * + */ +void print_mem(unsigned char *buf, int size); + +#endif /*_USB_DEVEL_MODE_H*/ diff --git a/tools/usb/unittests/usb/usb_tests.cc b/tools/usb/unittests/usb/usb_tests.cc new file mode 100644 index 0000000..bbbdbf2 --- /dev/null +++ b/tools/usb/unittests/usb/usb_tests.cc @@ -0,0 +1,651 @@ +/* + * This file defines the unit tests for a SuperSpeed/HighSpeed USB device. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <limits.h> +#include "g_serial_tests.h" +#include "UASP_tests.h" +#include "streams_tests.h" +#include "composite_tests.h" +#include "libusb_utils.h" +#include <gtest/gtest.h> +#include <stdio.h> +#include <stdlib.h> +#include <argp.h> +#include "ut_config.h" +#include "usb_tests.h" + +/** + * If this flag is set to 1, debug information wil be printed. Received as + * input parameter from user + */ +int ut_debug = 0; + +/** + * usb_tests_params - defines the tests parameters + * @busnum: the connected usb device bus number + * @devnum: the connected usb device number + * @vendorid: the connected usb device Vendor ID + * @productid: the connected usb deviceProduct ID + * @dev: the libusb devise to run the tests on + * @dev_speed: The speed of the connected usb device + * @num_expected_strms_in_ep: number of expected streams for IN EP's + * ep_comp desc + * @num_expected_strms_out_ep: number of expected streams for OUT EP's + * ep_comp desc + * @intr_num: number of the interface to run the test on + * @devel: Setting this flag to 1 will result in using the UT env for + * development purposes and none of the test suites will be run + * @uasp_dev: Setting this flag to 1 will result in running only the UASP + * test suite + * @streams_dev: Setting this flag to 1 will result in running + * only streams tests + */ +struct usb_tests_params { + int busnum; + int devnum; + int vendorid; + int productid; + struct libusb_device *dev; + enum usb_device_speed dev_speed; + int num_expected_strms_in_ep; + int num_expected_strms_out_ep; + int intr_num; + int devel; + int uasp_dev; + char gadget_sysfs_path[MAX_STRING_LEN]; + int streams_dev; +}; + +/* Tests parameters */ +static struct usb_tests_params tests_params; + +/** + * print_params() - This function prints the usb tests parameters + * @p:pointer to the usb_tests_params structure + * + */ +void print_params(struct usb_tests_params *p) +{ + printf("busnum = %d\n" + "devnum = %d\n" + "vendorid = %d\n" + "productid = %d\n" + "debug = %d\n" + "num_expected_strms_in_ep = %d\n" + "num_expected_strms_out_ep = %d\n" + "interface_number = %d\n" + "devel = %d\n" + "uasp_dev = %d\n" + "gadget_sysfs_path = %s\n", + "streams_dev = %d\n", + p->busnum, p->devnum, p->vendorid, p->productid, ut_debug, + p->num_expected_strms_in_ep, p->num_expected_strms_out_ep, + p->intr_num, p->devel, p->uasp_dev, p->gadget_sysfs_path, + p->streams_dev); +} + +/** + * options - Data structures defined for the parameters parsing as + * described in argp.h + * + * An array of parameters options to be used by argp to parse the parameters. + * The last field of the array should be NULL for terminating the search of + * the parameters. + */ +static struct argp_option options[] = { + /*{name, key, arg, flags, doc group}*/ + { "busnum", 1, "integer", 0, "Bus number", 1 }, + { "devnum", 2, "integer", 0, "Device number",1 }, + { "productid", 3, "integer", 0, "Product ID", 2 }, + { "vendorid", 4, "integer", 0, "Vendor ID", 2 }, + { "debug", 5, "integer", 0, "Debug Info", 3 }, + { "gtest_output",6,"string", 0, "gtest_output", 3 }, + { "num_expected_strms_in_ep",7,"integer", 0, + "num_expected_strms for IN EP", 4 }, + { "num_expected_strms_out_ep",8,"integer", 0, + "num_expected_strms for OUT EP", 4 }, + { "interface", 9, "integer", 0, + "interface number to run the tests on", 5}, + { "devel", 10, "integer", 0, "Development", 6}, + { "uasp_dev", 11, "integer", 0, "Run UASP tests", 6}, + { "gadget_sysfs_path", 12, "string", 0, "Gadget SYSFS Path", 6}, + { "streams_dev", 13, "integer", 0, "Run streams tests", 6}, + {0, 0, 0, 0, 0, 0}, +}; + +/** + * parse_opt() - This is an argp parsing function. + * @key: + * @arg: + * @state: + * + */ +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + int x; + char string[MAX_STRING_LEN]; + + struct usb_tests_params *p = (struct usb_tests_params*)state->input; + if (arg && key != 12) + sscanf(arg, "%i", &x); + else if (arg) + sscanf(arg, "%s", string); + + switch (key) { + case 1: + p->busnum = x; + break; + case 2: + p->devnum = x; + break; + case 3: + p->productid = x; + break; + case 4: + p->vendorid = x; + break; + case 5: + ut_debug = x; + break; + case 7: + p->num_expected_strms_in_ep = x; + break; + + case 8: + p->num_expected_strms_out_ep = x; + break; + case 9: + p->intr_num = x; + break; + case 10: + p->devel = x; + break; + case 11: + p->uasp_dev = x; + break; + case 12: + strcpy(p->gadget_sysfs_path, string); + break; + case 13: + p->streams_dev = x; + } + return 0; +} + + +/** + * argp - Parsing state. + * An argp structure contains a set of options declarations, a function to + * deal with parsing one, documentation string, a possible vector of child + * argp's, and perhaps a function to filter help output. When actually + * parsing options, getopt is called with the union of all the argp + * structures chained together through their CHILD pointers, with conflicts + * being resolved in favor of the first occurrence in the chain. + * + */ +static struct argp argp = { options, parse_opt, + "Googletest arguments", /*args_doc*/ + "usb tests parameters", /*doc*/ + 0, /*children*/ + 0, /* help_filter*/ + 0 /*argp_domain*/ +}; + + +/** + * get_dev_speed() - returns the speed of the connected device. + * + * Return speed of the connected device. + * In case of an error return USB_SPEED_UNKNOWN + */ +enum usb_device_speed get_dev_speed(void){ + return tests_params.dev_speed; +} + +/** + * This function returns the true if the devel input gflag was + * set, meaning none of the test suites should be run. + * + * Returns bool - the value of tests_params.devel + */ +bool is_devel_mode(void) +{ + return tests_params.devel; +} + +/** + * This function returns the true if the uasp_dev input flag was + * set, meaning only the UASP test suite should be run. + * + * Returns bool - the value of tests_params.uasp_dev + */ +bool is_uasp_device(void) +{ + return tests_params.uasp_dev; +} + +/** + * This function returns the true if the streams_dev input flag + * was set, meaning streams tests should be run. + * + * Returns bool - the value of tests_params.streams_dev + */ +bool is_streams_device(void) +{ + return tests_params.streams_dev; +} + +/** + * get_libusb_dev() - finds and returns the libusb device + * + * Return pointer to the libusb device or NULL on failier + * + * This function finds and returns the libusb device according to the input + * parameters: either device number and bus number or product id and vendor id + * + */ +libusb_device *get_libusb_dev(void) +{ + if (tests_params.busnum && tests_params.devnum) { + tests_params.dev = libusb_utils_get_device_by_num( + tests_params.busnum, tests_params.devnum); + } + else + tests_params.dev = libusb_utils_get_device_by_product_vendor( + tests_params.vendorid, tests_params.productid); + return tests_params.dev; +} + +/** + * usb_tests_read_gadget_sysfs_file() - read from gadget sysfs file + * @path: path for the gadget sysfs file + * + * Return the integer read from the file + * + * This function reads an integer from given gadget sysfs file + */ +int usb_tests_read_gadget_sysfs_file(char* path) +{ + char filename[MAX_STRING_LEN]; + FILE* file; + ssize_t nread; + int data; + + sprintf(filename, "%s%s", tests_params.gadget_sysfs_path, path); + file = fopen(filename, "r"); + if (file == NULL) + return -1; + + nread = fscanf(file, "%d", &data); + if (nread <= 0) + return -1; + + fclose(file); + return data; +} + +/** + * usb_tests_write_gadget_sysfs_file_int() - writes to gadget sysfs file an + * integer value + * @path: path for the gadget sysfs file + * @value: value to write to the file + * + * Return 0 for sucsess, -1 for failure + * + * This function writes an integer from given gadget sysfs file + */ +int usb_tests_write_gadget_sysfs_file_int(char* path, int value) +{ + char filename[MAX_STRING_LEN]; + FILE* file; + ssize_t nwrite; + + sprintf(filename, "%s%s", tests_params.gadget_sysfs_path, path); + file = fopen(filename, "w"); + if (file == NULL) + return -1; + + nwrite = fprintf(file, "%d", value); + if (nwrite != 1) + return -1; + + fclose(file); + return 0; +} + +/** + * usb_tests_write_gadget_sysfs_file_str() - writes to gadget + * sysfs file a string value + * @path: path for the gadget sysfs file + * @value: value to write to the file + * + * Return 0 for sucsess, -1 for failure + * + * This function writes an integer from given gadget sysfs file + */ +int usb_tests_write_gadget_sysfs_file_str(char* path, char *value) +{ + char filename[MAX_STRING_LEN]; + FILE* file; + ssize_t nwrite; + + sprintf(filename, "%s%s", tests_params.gadget_sysfs_path, path); + file = fopen(filename, "w"); + if (file == NULL) + return -1; + + nwrite = fprintf(file, "%s", value); + if (nwrite != strlen(value)) + return -1; + + fclose(file); + return 0; +} + +/** + * usb_tests_init() - init the libusb utility to be used by the tests. + * @argc: number of command line arguments + * @argv: command line arguments array + * + * Return 0 for success, -1 for failure + * + * This function initializes the libusb utility to be used by the tests. + * This function should be called prior to any libusb functions. + */ +int usb_tests_init(int argc, char **argv) +{ + int ret_val = 0; + memset ((void*)&tests_params, 0, sizeof(tests_params)); + + ret_val = argp_parse(&argp, argc, argv, 0, 0, &tests_params); + /* Verify input parameters */ + if ((!tests_params.busnum || !tests_params.devnum) && + (!tests_params.productid || !tests_params.vendorid)) { + printf("Missing input! You must supply either busnum and " + "devnum, or productid and vendorid\n"); + return -1; + } + + libusb_utils_init(); + + (void)get_libusb_dev(); + if (!tests_params.dev) { + printf("Wrong input! Couldn't allocate device\n"); + libusb_utils_exit(); + return -1; + } + + if (!ut_debug) + libusb_set_debug(NULL,0); + + tests_params.dev_speed = (enum usb_device_speed) + libusb_get_dev_speed(tests_params.dev); + + if (strlen(tests_params.gadget_sysfs_path) == 0) + strcpy(tests_params.gadget_sysfs_path, + DEFAULT_GADGET_SYSFS_PATH); + + + return 0; +} + +/** + * usb_tests_exit() - exit the libusb utility. + */ +void usb_tests_exit() +{ + libusb_utils_exit(); +} + +/* HS test cases */ + +/* HS Descriptors tests */ +TEST(CompositeHSTests, test_hs_descriptors) { + EXPECT_EQ(0,test_hs_descriptors(tests_params.dev)); +} + +/* HS GET_STATUS tests */ +TEST(CompositeHSTests, test_hs_get_status_default_device) { + EXPECT_EQ(0, test_hs_get_status_default_device(tests_params.dev)); +} + +TEST(CompositeHSTests, test_hs_get_status_default_interface) { + EXPECT_EQ(0, + test_hs_get_status_default_interface(tests_params.dev, + tests_params.intr_num)); +} + +TEST(CompositeHSTests, test_hs_get_status_default_ep) { + EXPECT_EQ(0, test_hs_get_status_default_ep(tests_params.dev, + tests_params.intr_num)); +} + +/* HS SET_FEATURE tests */ +TEST(CompositeHSTests, test_hs_set_feature_suspend_interface) { + EXPECT_EQ(0, test_hs_set_feature_suspend_interface(tests_params.dev, + tests_params.intr_num)); +} + +TEST(CompositeHSTests, test_hs_set_feature_halt_ep) { + EXPECT_EQ(0, test_hs_set_feature_halt_ep(tests_params.dev, + tests_params.intr_num)); +} + +/* SS test cases */ + +/* SS Descriptors tests */ +TEST(CompositeSSTests, test_ss_descriptors) { + EXPECT_EQ(0, test_ss_descriptors(tests_params.dev, + tests_params.num_expected_strms_in_ep, + tests_params.num_expected_strms_out_ep)); +} + +/* SS GET_STATUS tests */ +TEST(CompositeSSTests, test_ss_get_status_default_device) { + EXPECT_EQ(0, test_ss_get_status_default_device(tests_params.dev)); +} + +TEST(CompositeSSTests, test_ss_get_status_default_interface) { + EXPECT_EQ(0, + test_ss_get_status_default_interface(tests_params.dev, + tests_params.intr_num)); +} + +TEST(CompositeSSTests, test_ss_get_status_default_ep) { + EXPECT_EQ(0, test_ss_get_status_default_ep(tests_params.dev, + tests_params.intr_num)); +} + +/* SS SET_FEATURE tests */ + +TEST(CompositeSSTests, test_ss_set_feature_u1_device) { + EXPECT_EQ(0, test_ss_set_feature_u1_device(tests_params.dev)); +} + +TEST(CompositeSSTests, test_ss_set_feature_u2_device) { + EXPECT_EQ(0, test_ss_set_feature_u2_device(tests_params.dev)); +} + +TEST(CompositeSSTests, test_ss_set_feature_ltm_device) { + EXPECT_EQ(0, test_ss_set_feature_ltm_device(tests_params.dev)); +} + +TEST(CompositeSSTests, test_ss_set_feature_halt_ep) { + EXPECT_EQ(0, test_ss_set_feature_halt_ep(tests_params.dev, + tests_params.intr_num)); +} + +TEST(CompositeSSTests, test_ss_set_feature_suspend_low_power_interface) { + EXPECT_EQ(0, test_ss_set_feature_suspend_low_power_interface( + tests_params.dev, tests_params.intr_num)); +} + +TEST(CompositeSSTests, test_ss_set_feature_suspend_remote_wakeup_interface) { + EXPECT_EQ(0, test_ss_set_feature_suspend_remote_wakeup_interface( + tests_params.dev, tests_params.intr_num)); +} + + +/* General test cases */ +TEST(SerialTests, test_single_bulk_in){ + EXPECT_EQ(0, test_single_bulk_in(tests_params.dev, 40, + tests_params.intr_num)); +} + +TEST(SerialTests, test_single_bulk_out){ + EXPECT_EQ(0, test_single_bulk_out(tests_params.dev, 40, + tests_params.intr_num)); +} + +/* Streams test cases*/ +TEST(StreamsTests, test_streams_bulk_loopback) { + EXPECT_EQ(0, test_streams_bulk_loopback(tests_params.dev, 40, + tests_params.intr_num, 8)); +} + +/* This test should be the last one since it changes the libusb device */ +TEST(DummyTests, test_connect_disconnect) { + EXPECT_EQ(0, test_connect_disconnect(tests_params.dev, + tests_params.dev_speed, + tests_params.num_expected_strms_in_ep, + tests_params.num_expected_strms_out_ep)); +} + +/* UASP Test cases */ +TEST(UASPTests, exec_send_inquiry) { + EXPECT_EQ(0, exec_send_inquiry(tests_params.dev)); +} + +TEST(UASPTests, exec_send_request_sense) { + EXPECT_EQ(0, exec_send_request_sense(tests_params.dev)); +} + +TEST(UASPTests, exec_test_unit_ready) { + EXPECT_EQ(0, exec_test_unit_ready(tests_params.dev)); +} + + +TEST(UASPTests, exec_send_read_capacity) { + EXPECT_EQ(0, exec_send_read_capacity(tests_params.dev)); +} + +TEST(UASPTests, exec_send_mode_sense) { + EXPECT_EQ(0, exec_send_mode_sense(tests_params.dev)); +} + +TEST(UASPTests, exec_send_mode_sense10) { + EXPECT_EQ(0, exec_send_mode_sense10(tests_params.dev)); +} + +TEST(UASPTests, exec_send_prevent_allow_removal) { + EXPECT_EQ(0, exec_send_prevent_allow_removal(tests_params.dev)); +} + +TEST(UASPTests, exec_test_read6) { + EXPECT_EQ(0, exec_test_read6(tests_params.dev)); +} + +TEST(UASPTests, exec_test_read10) { + EXPECT_EQ(0, exec_test_read10(tests_params.dev)); +} + +TEST(UASPTests, exec_test_read12) { + EXPECT_EQ(0, exec_test_read12(tests_params.dev)); +} + +TEST(UASPTests, exec_test_write6) { + EXPECT_EQ(0, exec_test_read12(tests_params.dev)); +} +TEST(UASPTests, exec_test_write10) { + EXPECT_EQ(0, exec_test_read12(tests_params.dev)); +} + +TEST(UASPTests, exec_test_write12) { + EXPECT_EQ(0, exec_test_read12(tests_params.dev)); +} + +TEST(UASPTests, exec_test_write_huge) { + EXPECT_EQ(0, exec_test_write_huge(tests_params.dev)); +} + +TEST(UASPTests, exec_test_read_format_capacities){ + EXPECT_EQ(0, exec_test_read_format_capacities(tests_params.dev)); +} + +TEST(UASPTests, exec_test_start_stop){ + EXPECT_EQ(0, exec_test_start_stop(tests_params.dev)); +} + +TEST(UASPTests, exec_test_verify){ + EXPECT_EQ(0, exec_test_verify(tests_params.dev)); +} + +TEST(UASPTests, exec_test_synchronize_cache){ + EXPECT_EQ(0, exec_test_synchronize_cache(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_reset_lun){ + EXPECT_EQ(0, exec_test_tm_reset_lun(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_abort_task){ + EXPECT_EQ(0, exec_test_tm_abort_task(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_abort_task_set){ + EXPECT_EQ(0, exec_test_tm_abort_task_set(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_reset_nexus){ + EXPECT_EQ(0, exec_test_tm_reset_nexus(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_query_async_ev){ + EXPECT_EQ(0, exec_test_tm_query_async_ev(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_query_task){ + EXPECT_EQ(0, exec_test_tm_query_task(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_query_task_set){ + EXPECT_EQ(0, exec_test_tm_query_task_set(tests_params.dev)); +} + +TEST(UASPTests, exec_test_tm_overlapped_tag){ + EXPECT_EQ(0, exec_test_tm_overlapped_tag(tests_params.dev)); +} + +TEST(UASPTests, exec_test_cmd_overlapped_tag){ + EXPECT_EQ(0, exec_test_cmd_overlapped_tag(tests_params.dev)); +} + diff --git a/tools/usb/unittests/usb/usb_tests.h b/tools/usb/unittests/usb/usb_tests.h new file mode 100644 index 0000000..0d1b2ba --- /dev/null +++ b/tools/usb/unittests/usb/usb_tests.h @@ -0,0 +1,146 @@ +/* + * usb_tests.h - general usb tests functions + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef USB_TEST_H +#define USB_TEST_H + +extern "C" { +#include <linux/usb/ch9.h> +} + +#include "libusb.h" + +#define GADGET_SUSPENED_SYSFS_PATH "suspened" +#define GADGET_ZERO_FUNC_SUSPENDED_SYSFS_PATH "sourcesink/func_suspend" +#define ZERO_GADGET_ZERO_FUNC_WAKEUP_CAPABLE_SYSFS_PATH \ + "sourcesink/func_wakeup_capable" +#define ZERO_GADGET_ZERO_FUNC_WAKEUP_ENABLED_SYSFS_PATH \ + "sourcesink/func_wakeup_enabled" +#define ZERO_GADGET_ZERO_FUNC_WAKEUP_TRIGGER_SYSFS_PATH \ + "sourcesink/func_wakeup_trigger" + +/** + * get_libusb_dev() - finds and returns the libusb device + * + * Return pointer to the libusb device or NULL on failier + * + * This function finds and returns the libusb device according to the input + * parameters: either device number and bus number or product id and vendor id + * + */ +libusb_device *get_libusb_dev(void); + + +/** + * usb_tests_init() - init the libusb utility to be used by the tests. + * @argc: number of command line arguments + * @argv: command line arguments array + * + * Return 0 for sucsess, -1 for failier + * + * This function initializes the libusb utility to be used by the tests. + * This function should be called prior to any libusb functions. + */ +int usb_tests_init(int argc, char **argv); + +/** + * get_dev_speed() - returns the speed of the connected device. + * + * Return speed of the connected device. + * In case of an error return USB_SPEED_UNKNOWN + */ +enum usb_device_speed get_dev_speed(void); + +/** + * usb_tests_exit() - exit the libusb utility. + */ +void usb_tests_exit(); + +/** + * This function returns the true if the devel input gflag was + * set, meaning none of the test suites should be run. + * + * Return bool - the value of tests_params.devel + */ +bool is_devel_mode(void); + +/** + * This function returns the true if the uasp_dev input gflag + * was set, meaning only the UASP test suite should be run. + * + * Returns bool - the value of tests_params.uasp_dev + */ +bool is_uasp_device(void); + +/** + * This function returns the true if the streams_dev input flag + * was set, meaning streams tests should be run. + * + * Returns bool - the value of tests_params.streams_dev + */ +bool is_streams_device(void); + +/* + * usb_tests_read_gadget_sysfs_file() - read from gadget sysfs file + * @path: path for the gadget sysfs file + * + * Return the integer read from the file + * + * This function reads an integer from given gadget sysfs file + */ +int usb_tests_read_gadget_sysfs_file(char *path); + +/** + * usb_tests_write_gadget_sysfs_file_int() - writes to gadget sysfs file an + * integer value + * @path: path for the gadget sysfs file + * @value: value to write to the file + * + * Return 0 for sucsess, -1 for failure + * + * This function writes an integer from given gadget sysfs file + */ +int usb_tests_write_gadget_sysfs_file_int(char *path, int value); + +/** + * usb_tests_write_gadget_sysfs_file_str() - writes to gadget + * sysfs file a string value + * @path: path for the gadget sysfs file + * @value: value to write to the file + * + * Return 0 for sucsess, -1 for failure + * + * This function writes an integer from given gadget sysfs file + */ +int usb_tests_write_gadget_sysfs_file_str(char *path, char *value); + +#endif /*USB_TEST_H*/ diff --git a/tools/usb/unittests/usb/usb_tests_main.cc b/tools/usb/unittests/usb/usb_tests_main.cc new file mode 100644 index 0000000..cabbfbe --- /dev/null +++ b/tools/usb/unittests/usb/usb_tests_main.cc @@ -0,0 +1,83 @@ +/* + * usb_tests_main.cc - main file of the Unit Tests Framework + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + + +#include <iostream> +#include <stdio.h> + +#include <gtest/gtest.h> +#include "usb_tests.h" + +#include "usb_devel_mode.h" + +int main(int argc, char **argv) { + + int ret_val = 0; + char *updated_argv[argc+1]; + char hs_filter[] = "--gtest_filter=-*SS*:*UASP*:*Streams*"; + char ss_filter[] = "--gtest_filter=-*HS*:*UASP*:*Streams*"; + int i; + + if (usb_tests_init(argc, argv)) + return -1; + + if (is_devel_mode()) + return run_in_devel_mode(get_libusb_dev()); + + /* get current device speed and update tests filter according to it*/ + for (i = 0; i < argc; i++) { + updated_argv[i] = argv[i]; + } + + if (is_uasp_device()) + updated_argv[i] = "--gtest_filter=*UASP*"; + else if (is_streams_device()) + updated_argv[i] = "--gtest_filter=*Streams*"; + else + switch (get_dev_speed()) { + case USB_SPEED_SUPER: + updated_argv[i] = ss_filter; + break; + default: + updated_argv[i] = hs_filter; + } + argc++; + + testing::InitGoogleTest(&argc, updated_argv); + + ret_val = RUN_ALL_TESTS(); + + usb_tests_exit(); + + return ret_val; +} diff --git a/tools/usb/unittests/usb/ut_config.h b/tools/usb/unittests/usb/ut_config.h new file mode 100644 index 0000000..9148796 --- /dev/null +++ b/tools/usb/unittests/usb/ut_config.h @@ -0,0 +1,89 @@ +/* + * ut_config.h - Unittests global variables and defenitions + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef UT_CONFIG +#define UT_CONFIG + +/* + * This is the timeout (in millseconds) to wait before giving up + * on a bulk transfer due to no response being received. + */ +#define BULK_TRANSFERR_TIMEOUT 2000 + +/* + * This is the timeout (in millseconds) to wait before giving up + * on a control request due to no response being received. + */ +#define CTL_REQ_TRANSFERR_TIMEOUT 2000 + +/* + * This is the timeout (in seconds) to wait for the device to + * recconect in connect/disconnect test + */ +#define WAIT_FOR_CONN 2 + +/* + * This is control request code to be sent to gadget zero + * (soursesink) to initiate a connect/disconnect sequence + */ +#define CONN_DISCONN_TEST 0x52 + +/* + * This is control request code to be sent to gadget zero + * (soursesink) to set up the bulk buffer size + */ +#define SET_BULK_BUF_SIZE 0x5e + +/* + * These are features selectors of the HALT, U1, U2, LTM , + * SUSPEND & REMOTE_WU for the SET_FEATURE command + */ +#define HALT_ENABLE_FEATURE_SEL 0 +#define SUSPEND_ENABLE_FEATURE_SEL 0 +#define U1_ENABLE_FEATURE_SEL 48 +#define U2_ENABLE_FEATURE_SEL 49 +#define LTM_ENABLE_FEATURE_SEL 50 + +#define FUNC_SUSPEND_OPT_LOW_POWER 0x1 +#define FUNC_SUSPEND_OPT_WAKEUP_EN 0x2 + +#define MAX_STRING_LEN 255 +#define DEFAULT_GADGET_SYSFS_PATH \ + "/sys/devices/platform/dummy_udc/gadget/" + +/* + * If this flag is set to 1, debug information wil be printed. + * Received as input parameter from user + */ +extern int ut_debug; + +#endif /*UT_CONFIG*/ -- 1.7.0.4 -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html