[PATCH/RFC 1/5] usb:tools: usb unittests framework

Tatyana Brokhman
2011-06-16T13:31:51Z

This patch introduces a user-space framework for developing unit tests in
order to test the USB functionality of a connected device.
These tests communicate with the USB device via libusb interface.
They are meant to run with the g_zero and dummy_hcd module since several
proprietary control messages were added to those modules. But a smaller
subset of the tests can be run on any USB device and on real UDCs.

Implemented tests:
1. Test device descriptors - this test is applicable both for HS and SS
devices
2. Test the SET_FEATURE requests
3. Test bulk in
4. Test bulk out
5. Test connect/disconnect
6. Streams capability testing
7. UAS test suite

This patch also includes patches that should be applied to libusb.
Some of them were already sent upstream for approval but not yet accepted.
Other will be sent in the near future.

For more info please read the files under Documentation.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
.../usb/unittests/Documentation/autoconfig_readme | 20 +
.../usb/unittests/Documentation/create-gadget-img | 47 +
tools/usb/unittests/Documentation/unittests-info | 526 +++++
tools/usb/unittests/Documentation/unittests-setup | 127 ++
.../0001-Add-support-to-USB3-descriptors.patch | 420 ++++
...2-Add-support-for-libusb_get_device_speed.patch | 172 ++
.../libusb_patches/0003-Add-UAS-defines.patch | 56 +
.../0004-libusb-Add-stream-support-to-LIBUSB.patch | 314 +++
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 | 1645 +++++++++++++++
tools/usb/unittests/usb/composite_tests.h | 293 +++
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 +
29 files changed, 10377 insertions(+), 0 deletions(-)
create mode 100644 tools/usb/unittests/Documentation/autoconfig_readme
create mode 100644 tools/usb/unittests/Documentation/create-gadget-img
create mode 100644 tools/usb/unittests/Documentation/unittests-info
create mode 100644 tools/usb/unittests/Documentation/unittests-setup
create mode 100644 tools/usb/unittests/libusb_patches/0001-Add-support-to-USB3-descriptors.patch
create mode 100644 tools/usb/unittests/libusb_patches/0002-Add-support-for-libusb_get_device_speed.patch
create mode 100644 tools/usb/unittests/libusb_patches/0003-Add-UAS-defines.patch
create mode 100644 tools/usb/unittests/libusb_patches/0004-libusb-Add-stream-support-to-LIBUSB.patch
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/Documentation/autoconfig_readme b/tools/usb/unittests/Documentation/autoconfig_readme
new file mode 100644
index 0000000..07112e1
--- /dev/null
+++ b/tools/usb/unittests/Documentation/autoconfig_readme
@@ -0,0 +1,20 @@
+
+Questions can be refereed to tlinder@codeaurora.org.
+Copyright (C) 2011 Code Aurora Forum. All rights reserved
+
+Description
+-----------
+This script is used to automatically configure the kernel .config file
+(instead of using menuconfig).
+This script should be ran after using defconfig.
+
+Please note that the script modifies the .config file under out-32 (and
+should be executed in the out-32 directory).
+
+The script activates the dummy_HCD controller and configures the gadget
+to operate in a SS mode.
+
+--
+Created by a consultant of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
+
diff --git a/tools/usb/unittests/Documentation/create-gadget-img b/tools/usb/unittests/Documentation/create-gadget-img
new file mode 100644
index 0000000..edb34a7
--- /dev/null
+++ b/tools/usb/unittests/Documentation/create-gadget-img
@@ -0,0 +1,47 @@
+
+Questions can be refereed to tlinder@codeaurora.org.
+Copyright (C) 2011 Code Aurora Forum. All rights reserved
+
+
+This is how disk is built:
+-------------------------
+VM points to the location of the Virtual Machine
+
+cd $VM
+mkdir rootfs
+# create unformatted image
+qemu-img create -f raw gadget.img 600M
+# format it with ext2
+mkfs.ext2 -F gadget.img
+# mount
+fuseext2 gadget.img rootfs -o rw+
+# populate disk with basic Linux installation
+debootstrap --arch=i386 karmic rootfs
+
+#prepare image for real life
+echo "proc /proc proc defaults 0 0" >> rootfs/etc/fstab
+echo "/dev/sda / ext2 defaults 0 0" >> rootfs/etc/fstab
+
+echo "user ALL=(ALL) ALL" >> rootfs/etc/sudoers
+
+echo "auto lo" >> rootfs/etc/network/interfaces
+echo "iface lo inet loopback" >> rootfs/etc/network/interfaces
+echo "auto eth0" >> rootfs/etc/network/interfaces
+echo "iface eth0 inet dhcp" >> rootfs/etc/network/interfaces
+
+#unmount it
+fusermount -u rootfs
+
+Boot in a single mode (use -append "root=/dev/sda single"); in the VM, execute:
+
+useradd user
+passwd -d user
+echo "root:root00" | chpasswd
+apt-get --yes install openssh-server
+halt
+
+NOTE: instructions are incomplete
+
+--
+Created by a consultant of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
\ No newline at end of file
diff --git a/tools/usb/unittests/Documentation/unittests-info b/tools/usb/unittests/Documentation/unittests-info
new file mode 100644
index 0000000..163b270
--- /dev/null
+++ b/tools/usb/unittests/Documentation/unittests-info
@@ -0,0 +1,526 @@
+
+Questions can be refereed to tlinder@codeaurora.org.
+Copyright (C) 2011 Code Aurora Forum. All rights reserved
+
+1: INPUT PARAMETERS
+-------------------
+
+Usb_test receives the following input parameters:
+1.int busnum - the bus number of the USB device to run the tests on
+2.int devnum - the device number of the USB device to run the tests on
+3.int productid - the product id of the USB device to run the tests on
+4.int vendorid - the vendor id of the USB device to run the tests on
+The above data can be retrieved by running lsusb command on the VM/Linux host
+the USB device is connected to.
+Note: You should provide either busnum and devnum or productid and vendorid
+as an input.
+5.int num_expected_strms_in_ep - the number of expected streams for IN EP's
+ ep_comp desc
+6.int num_expected_strms_out_ep - the number of expected streams for OUT EP's
+ ep_comp desc
+7.int intr_num - the number of the interface to run the test on
+8.int devel - set this flag to 1 if you wish to run in development mode.
+ (Refer to section 3 for more details)
+9.int uasp_dev - set this flag to 1 if running the test on a UAS Gadget driver
+10.int debug - this flag indicates if debug information will be printed or not.
+ The default is that no debug info will be printed (debug = 0). You can change
+ that by setting debug = 1 (optional)
+11.int streams_dev - Setting this flag to 1 will result in running only streams
+ tests
+12.char gadget_sysfs_path[MAX_STRING_LEN] - Gadget sysfs path. The default is:
+ "/sys/devices/platform/dummy_udc/gadget/"
+
+Example:
+./usb_tests --busnum=2 --devnum=3 --debug=1
+
+
+2: RUNNING A SUBSET OF THE TESTS (ACCORDING TO DEVICE SPEED)
+------------------------------------------------------------
+
+On Unittests initialization the speed of the connected device is read and the
+appropriate test suite is excluded from the tests to run. Meaning if it's a
+HS/SS device CompositeSSTests/ CompositeHSTests won't be run.
+Beside this exception GoogleTest will run all the test suites.
+
+
+3. RUNNING IN DEVELOPMENT MODE
+------------------------------
+
+It's possible to choose a test to run. In order to do so run the test in
+development mode, meaning
+ ./usb_tests --busnum=2 --devnum=3 -devel=1
+This will open a list of test for you to choose which test to run.
+At the moment this option is developed for UAS tests only but other tests can be
+easily added to this menu.
+
+4: IMPLEMENTED TESTS
+--------------
+
+4.1: DUMMY TESTS
+
+4.1.1 test_connect_disconnect
+ Test Suite: DummyTests
+ Test Name: test_connect_disconnect
+ Test Description:
+ This test verifies the connect&disconnect sequence.
+ Verification is done by testing the correct enumeration descriptors were sent
+ (according to speed).
+
+
+4.2: COMPOSITE HS TESTS
+
+This test suite is applicable only for a HS device. The test in this suite
+verify chapter 9 requests that are applicable only to HS device.
+For example: HS descriptors.
+
+4.2.1 Test_hs_descriptors
+ Test Suite: CompositeHSTests
+ Test Name: test_hs_descriptors
+ Test Description:
+ This test verifies the validity of the HS device and interface descriptors
+ returned as part of the enumeration sequence.
+ Verification is done according to the expected descriptors defined in
+ hs_expected_desc.h
+
+4.2.2 Test_hs_get_status_default_device
+ Test Suite: CompositeHSTests
+ Test Name: test_hs_get_status_default_device
+ Test Description:
+ 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)
+
+4.2.3 Test_hs_get_status_default_interface
+ Test Suite: CompositeHSTests
+ Test Name: test_hs_get_status_default_interface
+ Test Description:
+ This function sends a GET_STATUS request to the hs interface in default state
+ (section 9.4.5 in the USB2 standard)
+
+4.2.4 Test_hs_get_status_default_endpoint
+ Test Suite: CompositeHSTests
+ Test Name: test_hs_get_status_default_endpoint
+ Test Description:
+ This function sends a GET_STATUS request to the hs endpoint in default state
+ (section 9.4.5 in the USB2 standard)
+
+4.2.5 Test_hs_set_feature_suspend_interface
+ Test Suite: CompositeHSTests
+ Test Name: test_hs_set_feature_suspend_interface
+ Test Description:
+ This function sends a SET_FEATURE request to the ss interface in default
+ state, to set the suspend functionality for remote wakeup.
+
+4.2.6 Test_hs_set_feature_halt_ep
+ Test Suite: CompositeHSTests
+ Test Name: test_hs_set_feature_halt_ep
+ Test Description:
+ 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.
+
+
+4.3: COMPOSITE SS TESTS
+
+This test suite is applicable only for a SS device. The test in this suite
+verify chapter 9 modifications that were made/added by the USB 3.0 spec.
+
+4.3.1 Test_ss_descriptors
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_descriptors
+ Test Description:
+ This test verifies the validity of the HS device, interface and BOS
+ descriptors returned as part of the enumeration sequence.
+ Verification is done according to the expected descriptors defined in
+ ss_expected_desc.h
+
+4.3.2 Test_ss_get_status_default_device
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_get_status_default_device
+ Test Description:
+ 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)
+ Verification of the GetStatus() request is done by the SetFeature()
+ (with bmRequestType = 0x80H) request sent prior to the GetStatus() request.
+
+4.3.3 Test_ss_get_status_default_interface
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_get_status_default_interface
+ Test Description:
+ This function sends a GET_STATUS request to the ss interface in default state
+ (section 9.4.5 in the USB3 standard)
+ Verification of the GetStatus() request is done by the SetFeature()
+ (with bmRequestType = 0x81H) request sent prior to the GetStatus() request.
+ Refer to Section 9.4.5 of the USB 3.0 spec for details on GetStatus request.
+
+4.3.4 Test_ss_get_status_default_ep
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_get_status_default_ep
+ Test Description:
+ 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.
+ Verification of the GetStatus() request is done by the SetFeature()
+ (with bmRequestType = 0x81H) request sent prior to the GetStatus() request.
+ Refer to Section 9.4.5 of the USB 3.0 spec for details on GetStatus request.
+
+4.3.5 Test_ss_set_feature_u1_device
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_set_feature_u1_device
+ Test Description:
+ This function sends a SET_FEATURE request to the ss device in default state,
+ to set the U1 power level capability.
+ Verification that the SetFeature request was successful is done by GetStatus()
+ request with bmRequestType = 0x81H. Refer to Section 9.4.5 of the USB 3.0 spec
+ for details on GetStatus request.
+ Refer to section 9.4.9 and Table 9-6 of the USB 3.0 spec for more details on
+ the SetFeature request.
+
+4.3.6 Test_ss_set_feature_u2_device
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_set_feature_u2_device
+ Test Description:
+ This function sends a SET_FEATURE request to the ss device in default state,
+ to set the U2 power level capability.
+ Verification that the SetFeature request was successful is done by GetStatus()
+ request with bmRequestType = 0x81H. Refer to Section 9.4.5 of the USB 3.0
+ spec for details on GetStatus request.
+ Refer to section 9.4.9 and Table 9-6 of the USB 3.0 spec for more details on
+ the SetFeature request.
+
+4.3.7 Test_ss_set_feature_ltm_device
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_set_feature_u2_device
+ Test Description:
+ This function sends a SET_FEATURE request to the ss device in default state,
+ to set the LTM capability.
+ Verification that the SetFeature request was successful is done by GetStatus()
+ request with bmRequestType = 0x81H. Refer to Section 9.4.5 of the USB 3.0
+ spec for details on GetStatus request.
+ Refer to section 9.4.9 and Table 9-6 of the USB 3.0 spec for more details on
+ the SetFeature request.
+
+4.3.8 Test_ss_set_feature_halt_ep
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_set_feature_halt_ep
+ Test Description:
+ 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.
+ Verification that the SetFeature request was successful is done by GetStatus()
+ request with bmRequestType = 0x81H. Refer to Section 9.4.5 of the USB 3.0
+ spec for details on GetStatus request.
+ Refer to section 9.4.9 and Table 9-6 of the USB 3.0 spec for more details on
+ the SetFeature request.
+
+4.3.9 Test_ss_set_feature_suspend_low_power_interface
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_set_feature_suspend_low_power_interface
+ Test Description:
+ This function sends a SET_FEATURE request to the ss interface in default
+ state, to set the suspend functionality for low power.
+ Verification that the SetFeature request was successful is done by GetStatus()
+ request with bmRequestType = 0x81H. Refer to Section 9.4.5 of the USB 3.0
+ spec for details on GetStatus request.
+ Refer to section 9.4.9 and Table 9-6 of the USB 3.0 spec for more details on
+ the SetFeature request.
+
+4.3.10 Test_ss_set_feature_suspend_remote_wakeup_interface
+ Test Suite: CompositeSSTests
+ Test Name: test_ss_set_feature_suspend_remote_wakeup_interface
+ Test Description:
+ This function sends a SET_FEATURE request to the ss interface in default
+ state, to set the suspend functionality for remote wakeup.
+ Verification that the SetFeature request was successful is done by GetStatus()
+ request with bmRequestType = 0x81H. Refer to Section 9.4.5 of the USB 3.0
+ spec for details on GetStatus request.
+ Refer to section 9.4.9 and Table 9-6 of the USB 3.0 spec for more details on
+ the SetFeature request.
+
+
+4.4: SERIAL TESTS
+
+The tests in this test suite are general data transfer tests that are applicable
+to all devices (HS and SS) and test the data transfers in the Gadget framework,
+not in a specific FD. The test in this test suite should be performed on the
+g_zero module using f_sourcesink gadget.
+
+4.4.1 Test_single_bulk_in
+ Test Suite: SerialTests
+ Test Name: test_single_bulk_in
+ Test Description:
+ This test verifies a single BULK transfer on a BULK IN endpoint. Data transfer
+ size is an input parameter for the test.
+
+4.4.2 Test_single_bulk_out
+ Test Suite: SerialTests
+ Test Name: test_single_bulk_out
+ Test Description:
+ This test verifies a single BULK transfer on a BULK OUT endpoint. Data
+ transfer size is an input parameter for the test.
+
+
+4.5 STREAMS TESTS
+
+The tests in this test suite intended to test the streaming capability added by
+the SS USB spec, thus they are applicable only to SS devices.
+
+4.5.1 Tests_streams_bulk_loopback
+ Test Suite: StreamsTests
+ Test Name: test_streams_bulk_loopback
+ Test Description:
+ This test initiates N bulk OUT transfers on N streams, and verifies reception
+ on bulk IN EP.
+
+
+4.6 UAS TESTS
+
+This tests are meant to run on a UAS supporting device. Their intention is to
+test various COMAND/TASK MANAGEMENT IUs handling as defined by the UAS spec.
+The COMMAND IUs include SCSI commands.
+Verification of all the test successful completion is done according to the
+SENCE IU received upon completion.
+The below tests are applicable to UAS device operating both in SS and in HS
+mode.
+
+4.6.1 exec_send_inquiry
+ Test Suite: UASTests
+ Test Name: exec_send_inquiry
+ Test Description:
+ This function sends the INQUIRY SCSI command (opCode = 0x12), encapsulated in
+ a COMMAND IU, to the device and verifies the correct reply from it.
+
+4.6.2 exec_send_request_sense
+ Test Suite: UASTests
+ Test Name: exec_send_request_sense
+ Test Description:
+ This function sends the REQUEST SENSE SCSI command (opCode = 0x03),
+ encapsulated in a COMMAND IU, to the device and verifies the correct reply
+ from it.
+
+4.6.3 exec_test_unit_ready
+ Test Suite: UASTests
+ Test Name: exec_test_unit_ready
+ Test Description:
+ This function sends the TEST UNIT READY SCSI command (opCode = 0x00),
+ encapsulated in a COMMAND IU, to the device and verifies the correct reply
+ from it.
+
+4.6.4 exec_send_read_capacity
+ Test Suite: UASTests
+ Test Name: exec_send_read_capacity
+ Test Description:
+ This function sends the READ CAPACITY SCSI command (opCode = 0x25),
+ encapsulated in a COMMAND IU, to the device and verifies the correct reply
+ from it.
+
+4.6.5 exec_send_mode_sense
+ Test Suite: UASTests
+ Test Name: exec_send_mode_sense
+ Test Description:
+ This function sends the MODE SENSE6 SCSI command (opCode = 0x01), encapsulated
+ in a COMMAND IU, to the device and verifies the correct reply from it.
+
+4.6.6 exec_send_mode_sense10
+ Test Suite: UASTests
+ Test Name: exec_send_mode_sense10
+ Test Description:
+ This function sends the MODE SENSE10 SCSI command (opCode = 0x5a),
+ encapsulated in a COMMAND IU, to the device and verifies the correct
+ completion of it.
+
+4.6.7 exec_send_prevent_allow_removal
+ Test Suite: UASTests
+ Test Name: exec_send_prevent_allow_removal
+ Test Description:
+ This function sends the ALLOW MEDIUM REMOVAL SCSI command (opCode = 0x1e),
+ encapsulated in a COMMAND IU, to the device and verifies the correct
+ completion of it.
+
+4.6.8 exec_test_read6
+ Test Suite: UASTests
+ Test Name: exec_test_read6
+ Test Description:
+ This function sends the READ6 SCSI command (opCode = 0x08), encapsulated in a
+ COMMAND IU, to the device and verifies the correct completion of it.
+ At the beginning of the test a verification buffer is written to the device.
+ The read data is compared to that buffer. Upon test completion the device data
+ file content is restored to its original state.
+
+4.6.9 exec_test_read10
+ Test Suite: UASTests
+ Test Name: exec_test_read10
+ Test Description:
+ This function sends the READ10 SCSI command (opCode = 0x28), encapsulated in
+ a COMMAND IU, to the device and verifies the correct completion of it.
+ At the beginning of the test a verification buffer is written to the device.
+ The read data is compared to that buffer. Upon test completion the device data
+ file content is restored to its original state.
+
+4.6.10 exec_test_read12
+ Test Suite: UASTests
+ Test Name: exec_test_read12
+ Test Description:
+ This function sends the READ12 SCSI command (opCode = 0xa8), encapsulated in
+ a COMMAND IU, to the device and verifies the correct completion of it.
+ At the beginning of the test a verification buffer is written to the device.
+ The read data is compared to that buffer. Upon test completion the device data
+ file content is restored to its original state.
+
+4.6.11 exec_test_write6
+ Test Suite: UASTests
+ Test Name: exec_test_write6
+ Test Description:
+ This function sends the WRITE6 SCSI command (opCode = 0x0a), encapsulated in
+ a COMMAND IU, to the device and verifies the correct completion of it.
+ Upon test completion the device data file content is restored to its original
+ state.
+ TODO: Add write verification
+
+4.6.12 exec_test_write10
+ Test Suite: UASTests
+ Test Name: exec_test_write10
+ Test Description:
+ This function sends the WRITE10 SCSI command (opCode = 0x2a), encapsulated in
+ a COMMAND IU, to the device and verifies the correct completion of it.
+ Upon test completion the device data file content is restored to its original
+ state.
+ TODO: Add write verification
+
+4.6.13 exec_test_write12
+ Test Suite: UASTests
+ Test Name: exec_test_write12
+ Test Description:
+ This function sends the WRITE12 SCSI command (opCode = 0xaa), encapsulated in
+ a COMMAND IU, to the device and verifies the correct completion of it.
+ Upon test completion the device data file content is restored to its original
+ state.
+ TODO: Add write verification
+
+4.6.14 exec_test_write_huge
+ Test Suite: UASTests
+ Test Name: exec_test_write_huge
+ Test Description:
+ This function sends the WRITE10 SCSI command (opCode = 0x2a), encapsulated in
+ a COMMAND IU, with a huge amount of data to write and verifies the correct
+ completion of it.
+ Upon test completion the device data file content is restored to its original
+ state.
+ TODO: Add write verification
+
+4.6.15 exec_test_read_format_capacities
+ Test Suite: UASTests
+ Test Name: exec_test_read_format_capacities
+ Test Description:
+ This function sends the READ FORMAT CAPACITIES SCSI command (opCode = 0x23),
+ encapsulated in a COMMAND IU and verifies the correct completion of it.
+
+4.6.16 exec_test_start_stop
+ Test Suite: UASTests
+ Test Name: exec_test_start_stop
+ Test Description:
+ This function sends the START STOP UNIT SCSI command (opCode = 0x1b),
+ encapsulated in a COMMAND IU and verifies the correct completion of it.
+ This test verifies several versions of the command:
+ a)(LoEj,Start) = 00 (stop motor)
+ b)(LoEj,Start) = 01 (start motor)
+ c)(LoEj,Start) = 10 (Eject media)
+ After the media is ejected the lun is closed. We need to re-open it manually
+ in order to be able to continue working with it. This is done by writing to
+ the file attribute the name of the file the module was loaded with.
+ d)(LoEj,Start) = 11 (LOAD media)
+
+4.6.17 exec_test_verify
+ Test Suite: UASTests
+ Test Name: exec_test_verify
+ Test Description:
+ This function sends the VERIFY SCSI command (opCode = 0x2f), encapsulated in
+ a COMMAND IU and verifies the correct completion of it.
+
+4.6.18 exec_test_synchronize_cache
+ Test Suite: UASTests
+ Test Name: exec_test_synchronize_cache
+ Test Description:
+ This function sends the SINCHRONIZE CACHE SCSI command (opCode = 0x35),
+ encapsulated in a COMMAND IU and verifies the correct completion of it.
+
+4.6.19 exec_test_tm_reset_lun
+ Test Suite: UASTests
+ Test Name: exec_test_tm_reset_lun
+ Test Description:
+ This function sends the LOGICAL UNIT RESET TASK MANAGEMENTcommand
+ (Code = 0x08), and verifies the correct completion of it according to the
+ RESPONSE IU.
+ At the beginning of the test 2 commands are issued to the device that should
+ be canceled by the RESET LUN TM.
+
+4.6.20 exec_test_tm_abort_task
+ Test Suite: UASTests
+ Test Name: exec_test_tm_abort_task
+ Test Description:
+ This function sends the ABORT TASK TASK MANAGEMENTcommand (Code = 0x01), and
+ verifies the correct completion of it according to the RESPONSE IU.
+ At the beginning of the test a command is issued to the device that should be
+ canceled by the ABORT TASK TM.
+
+4.6.21 exec_test_tm_abort_task_set
+ Test Suite: UASTests
+ Test Name: exec_test_tm_abort_task_set
+ Test Description:
+ This function sends the ABORT TASK SET TASK MANAGEMENTcommand (Code = 0x02),
+ and verifies the correct completion of it according to the RESPONSE IU.
+ At the beginning of the test 2 commands are issued to the device that should
+ be canceled by the ABORT TASK SET TM.
+
+4.6.22 exec_test_tm_reset_nexus
+ Test Suite: UASTests
+ Test Name: exec_test_tm_reset_nexus
+ Test Description:
+ This function sends the RESET NEXUS TASK MANAGEMENTcommand (Code = 0x10), and
+ verifies the correct completion of it according to the RESPONSE IU.
+ At the beginning of the test 2 commands are issued to the device that should
+ be canceled by the RESET NEXUS TM.
+
+4.6.23 exec_test_tm_query_async_ev
+ Test Suite: UASTests
+ Test Name: exec_test_tm_query_async_ev
+ Test Description:
+ This function sends the QUERY ASYNC EVENT TASK MANAGEMENTcommand
+ (Code = 0x82), and verifies the correct completion of it according to the
+ RESPONSE IU.
+
+4.6.24 exec_test_tm_query_task
+ Test Suite: UASTests
+ Test Name: exec_test_tm_query_task
+ Test Description:
+ This function sends the QUERY TASK TASK MANAGEMENTcommand (Code = 0x80), and
+ verifies the correct completion of it according to the RESPONSE IU.
+
+4.6.25 exec_test_tm_query_task_set
+ Test Suite: UASTests
+ Test Name: exec_test_tm_query_task_set
+ Test Description:
+ This function sends the QUERY TASK SET TASK MANAGEMENTcommand (Code = 0x81),
+ and verifies the correct completion of it according to the RESPONSE IU.
+
+4.6.26 exec_test_tm_overlapped_tag
+ Test Suite: UASTests
+ Test Name: exec_test_tm_overlapped_tag
+ Test Description:
+ This function verifies correct handling of tag overlapping. It issues 2
+ commands with the same tag id and verifies that both commands were handled
+ correctly, meaning aborted.
+ One of the commands issued is a COMMAND IU and the other is TM IU.
+
+4.6.27 exec_test_cmd_overlapped_tag
+ Test Suite: UASTests
+ Test Name: exec_test_cmd_overlapped_tag
+ Test Description:
+ This function verifies correct handling of tag overlapping. It issues 2
+ commands with the same tag id and verifies that both commands were handled
+ correctly, meaning aborted.
+ Both of the command issued are COMMAND IUs.
+
+--
+Created by a consultant of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
\ No newline at end of file
diff --git a/tools/usb/unittests/Documentation/unittests-setup b/tools/usb/unittests/Documentation/unittests-setup
new file mode 100644
index 0000000..f336e3b
--- /dev/null
+++ b/tools/usb/unittests/Documentation/unittests-setup
@@ -0,0 +1,127 @@
+
+Questions can be refereed to tlinder@codeaurora.org.
+Copyright (C) 2011 Code Aurora Forum. All rights reserved
+
+USB device Unit test framework
+==============================
+
+Introduction
+-------------
+
+This document describes the SuperSpeed USB Unit tests including setup,
+environment and test cases.
+
+
+1: SETUP
+---------
+
+The Unit tests code consists of 4 parts:
+
+1. The usb-tests code that is part of the kernel usb code.
+2. Googletest code. Downloaded from the web.
+3. The user-space test code in this distribution
+4. libusb code that is part of the libusb git repository
+
+The Unit tests can be ran on any Linux machine with a device that has g_zero
+and dummy_hcd module loaded on it. If you wish to run the Unit tests on another
+device (one that doesn't support g_zero and dumm_hcd_ it's possible but not all
+of the bellow tests will pass. This is due to the fact that several proprietary
+control requests handling were implemented in the above modules in order to
+support some of the tests. For example: new control request handling was
+added to the dummy_hcd module to perform a connect/disconnect sequence.
+
+
+1.1: GETTING USB-TEST CODE FROM THE KERNEL REPOSITORY
+
+Get the kernel code from
+ git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+The unit test kernel patches are released as part of kernel2.6.?? so you should
+work with this version of the kernel or later.
+
+Compiling the Kernel code:
+Export $KERNEL to point to the location of your kernel.
+mkdir out-32
+cd out-32
+make -C $KERNEL O=`pwd` ARCH=x86 defconfig
+
+Run the autoconfig.sh script to configure the kernel. Please refer to
+autoconfig_readme for details.
+
+Compilation:
+make -C $KERNEL O=`pwd` ARCH=x8
+
+
+1.2: LIBUSB CODE
+
+Get the libusb code from git://git.libusb.org/libusb.git
+The libusb related patches are merged into the libusb tree. (NOT YET!!!)
+
+1.2.1 Libusb Setup and compilation
+
+Install the following packages (from synaptic):
+a. autoconfig
+b.automake
+c. libtool
+
+Run: ./autogen.sh. –prefix=<output_folder>
+This script will generate the .config file and the Makefile
+
+Open the auto-generated Makefiles (there is one under libusb, one under
+libusb/libusb and another one under libusb/examples) and update the following:
+a)To CPPFLAGS add -m32 (CPPFLAGS = -m32)
+b)To CFLAGS add -m32 (CFLAGS = -g -O2 -m32)
+c)Change every x86_64 to i386
+
+run: make install
+The library and include files will be placed in . --prefix=<output_folder>
+
+
+1.3: GOOGLETEST CODE
+
+Download from
+http://code.google.com/p/googletest/downloads/list (gtest-1.5.0.tar.bz2) .
+Open the Makefile and add “-lpthread” to CXXFLAGS:
+CXXFLAGS += -g -Wall -Wextra -m32 -L/usr/lib32 -lstdc++ -L/usr/local/lib -lusb-1.0 -lpthread
+
+
+1.4 COMPILING USER SPACE TEST CODE (IN THIS PACKAGE)
+
+cd ../tools/usb/unittests/make/ (from your working area)
+
+Set the $KERNEL to your kernel source code, $GTEST to your Googletest directory
+and $LIBUSB to your libusb compilation output directory.
+
+make
+The make creates an executable called usb_tests
+
+
+1.5: VIRTUAL MACHINE
+
+If you wish to use the dummy_hcd module then it's best to run the Unit tests on
+a Virtual machine (VM).
+Debugging of the VM kernel is performed with insight.
+So you'll be required to install the following packages:
+1. qemu
+2. fuseext2
+3. insight
+
+Create gadjet.img. Refer to create-gadget-img for details.
+
+1.5.1 Initial setup of the VM:
+
+Copy usb_tests to the VM.
+Copy the libusb library files to the VM (from <output_folder>/lib)
+
+
+2: RUNNING THE UNIT TEST
+-----------------------
+
+On the VM (or other Linux host) do:
+export LD_LIBRARY_PATH=<libusb library files path on the VM>
+run the tests script: ./usb_tests with relevant input parameters. (Refer to
+unittests-info for additional information)
+
+--
+Created by a consultant of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
+
diff --git a/tools/usb/unittests/libusb_patches/0001-Add-support-to-USB3-descriptors.patch b/tools/usb/unittests/libusb_patches/0001-Add-support-to-USB3-descriptors.patch
new file mode 100644
index 0000000..8c8aaf0
--- /dev/null
+++ b/tools/usb/unittests/libusb_patches/0001-Add-support-to-USB3-descriptors.patch
@@ -0,0 +1,420 @@
+From fcc8bb8ea6a326a2c84e92b29004e8e3896925b7 Mon Sep 17 00:00:00 2001
+From: Maya Erez <merez@codeaurora.org>
+Date: Sun, 13 Mar 2011 22:01:07 +0200
+Subject: [PATCH 1/4] Add support to USB3 descriptors
+
+Add definitions for Endpoint Companion and BOS descriptors.
+Add APIs for parsing the Endpoint Companion and BOS descriptors.
+
+Signed-off-by: Maya Erez <merez@codeaurora.org>
+
+---
+ libusb/descriptor.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++---
+ libusb/libusb.h | 115 ++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 264 insertions(+), 11 deletions(-)
+
+diff --git a/libusb/descriptor.c b/libusb/descriptor.c
+index 11480e8..0ce6975 100644
+--- a/libusb/descriptor.c
++++ b/libusb/descriptor.c
+@@ -22,6 +22,7 @@
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <stdio.h>
+
+ #include "libusbi.h"
+
+@@ -45,6 +46,7 @@ int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
+ unsigned char *sp = source, *dp = dest;
+ uint16_t w;
+ const char *cp;
++ uint32_t d;
+
+ for (cp = descriptor; *cp; cp++) {
+ switch (*cp) {
+@@ -63,6 +65,21 @@ int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
+ sp += 2;
+ dp += 2;
+ break;
++ /* 32-bit word, convert from little endian to CPU */
++ case 'd':
++ /* Align to word boundary */
++ dp += ((unsigned long)dp & 1);
++
++ 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;
+ }
+ }
+
+@@ -75,6 +92,39 @@ static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
+ free((unsigned char *) endpoint->extra);
+ }
+
++static int parse_endpoint_comp(struct libusb_context *ctx,
++ struct libusb_ss_ep_comp_descriptor *ep_comp,
++ unsigned char *buffer, int size)
++{
++ struct usb_descriptor_header header;
++ int parsed = 0;
++
++ usbi_parse_descriptor(buffer, "bb", &header, 0);
++
++ /* Everything should be fine being passed into here, but we sanity */
++ /* check JIC */
++ if (header.bLength > size) {
++ usbi_err(ctx, "ran out of descriptors parsing");
++ return LIBUSB_ERROR_NO_MEM;
++ }
++
++ if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMP) {
++ usbi_err(ctx, "unexpected descriptor %x (expected %x)",
++ header.bDescriptorType, LIBUSB_DT_SS_ENDPOINT_COMP);
++ return parsed;
++ }
++
++ if (header.bLength >= LIBUSB_DT_SS_EP_COMP_SIZE)
++ usbi_parse_descriptor(buffer, "bbbbw", ep_comp, 0);
++
++ buffer += header.bLength;
++ size -= header.bLength;
++ parsed += header.bLength;
++
++ return parsed;
++}
++
++
+ static int parse_endpoint(struct libusb_context *ctx,
+ struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer,
+ int size, int host_endian)
+@@ -83,7 +133,7 @@ static int parse_endpoint(struct libusb_context *ctx,
+ unsigned char *extra;
+ unsigned char *begin;
+ int parsed = 0;
+- int len;
++ int len, retval;
+
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+@@ -109,6 +159,28 @@ static int parse_endpoint(struct libusb_context *ctx,
+ size -= header.bLength;
+ parsed += header.bLength;
+
++ /* check if we have a Comapnion descriptor */
++ usbi_parse_descriptor(buffer, "bb", &header, 0);
++ if (header.bDescriptorType == LIBUSB_DT_SS_ENDPOINT_COMP) {
++ endpoint->ep_comp = (struct libusb_ss_ep_comp_descriptor *)
++ malloc(sizeof(struct libusb_ss_ep_comp_descriptor));
++ if (!endpoint->ep_comp) {
++ usbi_err(ctx, "couldn't allocate memory for ep_comp");
++ return LIBUSB_ERROR_NO_MEM;
++ }
++
++ memset(endpoint->ep_comp, 0,
++ sizeof(struct libusb_ss_ep_comp_descriptor));
++ retval = parse_endpoint_comp(ctx, endpoint->ep_comp,
++ buffer, size);
++ if (retval < 0)
++ return retval;
++
++ buffer += retval;
++ parsed += retval;
++ size -= retval;
++ }
++
+ /* Skip over the rest of the Class Specific or Vendor Specific */
+ /* descriptors */
+ begin = buffer;
+@@ -122,9 +194,10 @@ static int parse_endpoint(struct libusb_context *ctx,
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+- (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+- (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+- (header.bDescriptorType == LIBUSB_DT_DEVICE))
++ (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
++ (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
++ (header.bDescriptorType == LIBUSB_DT_DEVICE) ||
++ (header.bDescriptorType == LIBUSB_DT_SS_ENDPOINT_COMP))
+ break;
+
+ usbi_dbg("skipping descriptor %x", header.bDescriptorType);
+@@ -233,9 +306,11 @@ static int parse_interface(libusb_context *ctx,
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+- (header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+- (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+- (header.bDescriptorType == LIBUSB_DT_DEVICE))
++ (header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
++ (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
++ (header.bDescriptorType == LIBUSB_DT_DEVICE) ||
++ (header.bDescriptorType ==
++ LIBUSB_DT_SS_ENDPOINT_COMP))
+ break;
+
+ buffer += header.bLength;
+@@ -379,9 +454,11 @@ static int parse_configuration(struct libusb_context *ctx,
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+- (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+- (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+- (header.bDescriptorType == LIBUSB_DT_DEVICE))
++ (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
++ (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
++ (header.bDescriptorType == LIBUSB_DT_DEVICE) ||
++ (header.bDescriptorType ==
++ LIBUSB_DT_SS_ENDPOINT_COMP))
+ break;
+
+ usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType);
+@@ -726,3 +803,66 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
+ return di;
+ }
+
++
++/** \ingroup desc
++ * Get the USB bos descriptor for a given device.
++ *
++ * \param dev the device
++ * \param bos output bos descriptor
++ * \returns 0 on success
++ */
++API_EXPORTED int libusb_parse_bos_desc(struct libusb_device *dev,
++ struct libusb_bos_descriptor *bos,
++ unsigned char *buf)
++{
++ int i;
++ int desc_begin = 0;
++
++ usbi_parse_descriptor(buf, "bbwb", bos, 0);
++ desc_begin = LIBUSB_DT_BOS_SIZE;
++
++ /* Get the device capability descriptors */
++ for (i = 0; i < bos->bNumDeviceCaps; ++i) {
++ if (buf[desc_begin+2] == LIBUSB_USB_CAP_TYPE_EXT) {
++ if (!bos->usb_ext_cap) {
++ bos->usb_ext_cap =
++ (struct libusb_usb_ext_cap_descriptor *)
++ malloc(sizeof(struct
++ libusb_usb_ext_cap_descriptor));
++ usbi_parse_descriptor(buf+desc_begin, "bbbd",
++ bos->usb_ext_cap, 0);
++ } else
++ usbi_warn(dev->ctx,
++ "usb_ext_cap was already allocated");
++
++ /* move to the next device capability descriptor */
++ desc_begin += LIBUSB_DT_USB_CAP_TYPE_EXT_SIZE;
++ } else if (buf[desc_begin+2] == LIBUSB_SS_USB_CAP_TYPE) {
++ if (!bos->ss_usb_cap) {
++ bos->ss_usb_cap =
++ (struct libusb_ss_usb_cap_descriptor *)
++ malloc(sizeof(struct
++ libusb_ss_usb_cap_descriptor));
++
++ usbi_parse_descriptor(buf+desc_begin,
++ "bbbbwbbw",
++ bos->ss_usb_cap, 0);
++ } else
++ usbi_warn(dev->ctx,
++ "ss_usb_cap was already allocated");
++
++ /* move to the next device capability descriptor */
++ desc_begin += LIBUSB_DT_SS_USB_CAP_TYPE_SIZE;
++ } else {
++ usbi_info(dev->ctx,
++ "wireless/container_id capability "
++ "descriptor");
++
++ /* move to the next device capability descriptor */
++ desc_begin += buf[desc_begin];
++ }
++ }
++ return 0;
++}
++
++
+diff --git a/libusb/libusb.h b/libusb/libusb.h
+index 8dc3362..9f2243a 100644
+--- a/libusb/libusb.h
++++ b/libusb/libusb.h
+@@ -191,7 +191,16 @@ enum libusb_descriptor_type {
+ LIBUSB_DT_PHYSICAL = 0x23,
+
+ /** Hub descriptor */
+- LIBUSB_DT_HUB = 0x29
++ LIBUSB_DT_HUB = 0x29,
++
++ /** BOS descriptor */
++ LIBUSB_DT_BOS = 0x0f,
++
++ /** Device Capability descriptor */
++ LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
++
++ /** SuperSpeed Endpoint Companion descriptor */
++ LIBUSB_DT_SS_ENDPOINT_COMP = 0x30
+ };
+
+ /* Descriptor sizes per descriptor type */
+@@ -201,6 +210,13 @@ enum libusb_descriptor_type {
+ #define LIBUSB_DT_ENDPOINT_SIZE 7
+ #define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+ #define LIBUSB_DT_HUB_NONVAR_SIZE 7
++#define LIBUSB_DT_SS_EP_COMP_SIZE 6
++#define LIBUSB_DT_BOS_SIZE 5
++#define LIBUSB_DT_USB_CAP_TYPE_EXT_SIZE 7
++#define LIBUSB_DT_SS_USB_CAP_TYPE_SIZE 10
++#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) + \
++ (LIBUSB_DT_USB_CAP_TYPE_EXT_SIZE) + \
++ (LIBUSB_DT_SS_USB_CAP_TYPE_SIZE))
+
+ #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
+ #define LIBUSB_ENDPOINT_DIR_MASK 0x80
+@@ -407,6 +423,33 @@ struct libusb_device_descriptor {
+ uint8_t bNumConfigurations;
+ };
+
++/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
++struct libusb_ss_ep_comp_descriptor {
++
++ /** Size of this descriptor (in bytes) */
++ u_int8_t bLength;
++
++ /** Descriptor type. Will have value
++ * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMP in
++ * this context. */
++ u_int8_t bDescriptorType;
++
++
++ /** The maximum number of packets the endpoint can send or
++ * recieve as part of a burst. */
++ u_int8_t bMaxBurst;
++
++ /** In bulk EP: bits 4:0 represents the maximum number of
++ * streams the EP supports. In isochronous EP: bits 1:0
++ * represents the Mult - a zero based value that determines
++ * the maximum number of packets within a service interval */
++ u_int8_t bmAttributes;
++
++ /** The total number of bytes this EP will transfer every
++ * service interval. valid only for periodic EPs. */
++ u_int16_t wBytesPerInterval;
++};
++
+ /** \ingroup desc
+ * A structure representing the standard USB endpoint descriptor. This
+ * descriptor is documented in section 9.6.3 of the USB 2.0 specification.
+@@ -449,6 +492,9 @@ struct libusb_endpoint_descriptor {
+ /** For audio devices only: the address if the synch endpoint */
+ uint8_t bSynchAddress;
+
++ /** The EP companion descriptor */
++ struct libusb_ss_ep_comp_descriptor *ep_comp;
++
+ /** Extra descriptors. If libusb encounters unknown endpoint descriptors,
+ * it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+@@ -457,6 +503,7 @@ struct libusb_endpoint_descriptor {
+ int extra_length;
+ };
+
++
+ /** \ingroup desc
+ * A structure representing the standard USB interface descriptor. This
+ * descriptor is documented in section 9.6.5 of the USB 2.0 specification.
+@@ -565,6 +612,60 @@ struct libusb_config_descriptor {
+ int extra_length;
+ };
+
++/** \ingroup desc
++ * A structure representing the BOS descriptor. This
++ * descriptor is documented in section 9.6.2 of the USB 3.0
++ * specification. All multiple-byte fields are represented in
++ * host-endian format.
++ */
++struct libusb_bos_descriptor {
++ u_int8_t bLength;
++ u_int8_t bDescriptorType;
++ u_int16_t wTotalLength;
++ u_int8_t bNumDeviceCaps;
++
++ struct libusb_usb_ext_cap_descriptor *usb_ext_cap;
++ struct libusb_ss_usb_cap_descriptor *ss_usb_cap;
++};
++
++
++struct libusb_dev_cap_header {
++ u_int8_t bLength;
++ u_int8_t bDescriptorType;
++ u_int8_t bDevCapabilityType;
++};
++
++
++#define LIBUSB_USB_CAP_TYPE_EXT 2
++
++struct libusb_usb_ext_cap_descriptor { /* Link Power Management */
++ u_int8_t bLength;
++ u_int8_t bDescriptorType;
++ u_int8_t bDevCapabilityType;
++ u_int32_t bmAttributes;
++#define LIBUSB_LPM_SUPPORT (1 << 1) /* supports LPM */
++};
++
++
++#define LIBUSB_SS_USB_CAP_TYPE 3
++
++struct libusb_ss_usb_cap_descriptor { /* Link Power Management */
++ u_int8_t bLength;
++ u_int8_t bDescriptorType;
++ u_int8_t bDevCapabilityType;
++ u_int8_t bmAttributes;
++#define LIBUSB_LPM_SUPPORT (1 << 1) /* supports LPM */
++ u_int16_t wSpeedSupported;
++#define LIBUSB_LOW_SPEED_OPERATION (1) /* Low speed operation */
++#define LIBUSB_FULL_SPEED_OPERATION (1 << 1)/* Full speed operation */
++#define LIBUSB_HIGH_SPEED_OPERATION (1 << 2)/* High speed operation */
++#define LIBUSB_5GBPS_OPERATION (1 << 3)/* Operation at 5Gbps */
++ u_int8_t bFunctionalitySupport;
++ u_int8_t bU1devExitLat;
++ u_int16_t bU2DevExitLat;
++};
++
++
+ /** \ingroup asyncio
+ * Setup packet for control transfers. */
+ struct libusb_control_setup {
+@@ -1315,6 +1416,18 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
+ libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+ void *user_data);
+
++
++/** \ingroup desc
++ * Get the USB bos descriptor for a given device.
++ *
++ * \param dev the device
++ * \param bos output bos descriptor
++ * \returns 0 on success
++ */
++int libusb_parse_bos_desc(struct libusb_device *dev,
++ struct libusb_bos_descriptor *bos,
++ unsigned char *buf);
++
+ #ifdef __cplusplus
+ }
+ #endif
+--
+1.7.3.3
+
+--
+Sent by an employee of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
\ No newline at end of file
diff --git a/tools/usb/unittests/libusb_patches/0002-Add-support-for-libusb_get_device_speed.patch b/tools/usb/unittests/libusb_patches/0002-Add-support-for-libusb_get_device_speed.patch
new file mode 100644
index 0000000..ca612bb
--- /dev/null
+++ b/tools/usb/unittests/libusb_patches/0002-Add-support-for-libusb_get_device_speed.patch
@@ -0,0 +1,172 @@
+From c5df8c1d47367d214c40bf932244f8b44f1f4caf Mon Sep 17 00:00:00 2001
+From: Tatyana Brokhman <tlinder@codeaurora.org>
+Date: Mon, 14 Mar 2011 16:18:26 +0200
+Subject: [PATCH 2/4] Add support for libusb_get_device_speed()
+
+This patch adds a new libusb function used to determine the connected USB
+device speed.
+
+Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
+
+---
+ libusb/core.c | 17 ++++++++++++++
+ libusb/libusb.h | 11 +++++++++
+ libusb/libusbi.h | 7 ++++++
+ libusb/os/linux_usbfs.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 91 insertions(+), 0 deletions(-)
+
+diff --git a/libusb/core.c b/libusb/core.c
+index 64445ab..6d49fb3 100644
+--- a/libusb/core.c
++++ b/libusb/core.c
+@@ -745,6 +745,23 @@ int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev,
+ }
+
+ /** \ingroup dev
++ * Convenience function to retrieve the speed of the connected
++ * device
++ *
++ * \param dev a device
++ * \returns the connected device speed
++ * \returns LIBUSB_ERROR_NOT_SUPPORTED if get_device_speed() cb
++ * was not defined for the usbi_backend
++ * \returns LIBUSB_ERROR_OTHER on other failure
++ */
++API_EXPORTED int libusb_get_dev_speed(libusb_device *dev)
++{
++ if (usbi_backend->get_device_speed)
++ return usbi_backend->get_device_speed(dev);
++ return LIBUSB_ERROR_NOT_SUPPORTED;
++}
++
++/** \ingroup dev
+ * Calculate the maximum packet size which a specific endpoint is capable is
+ * sending or receiving in the duration of 1 microframe
+ *
+diff --git a/libusb/libusb.h b/libusb/libusb.h
+index 9f2243a..346f85f 100644
+--- a/libusb/libusb.h
++++ b/libusb/libusb.h
+@@ -89,6 +89,16 @@
+ extern "C" {
+ #endif
+
++/* USB 2.0 defines three speeds, here's how Linux identifies them */
++enum libusb_device_speed {
++ LIBUSB_SPEED_UNKNOWN = 0, /* enumerating */
++ LIBUSB_SPEED_LOW, LIBUSB_SPEED_FULL, /* usb 1.1 */
++ LIBUSB_SPEED_HIGH, /* usb 2.0 */
++ LIBUSB_SPEED_VARIABLE, /* wireless (usb 2.5) */
++ LIBUSB_SPEED_SUPER, /* usb 3.0 */
++};
++
++
+ /** \def libusb_cpu_to_le16
+ * \ingroup misc
+ * Convert a 16-bit value from host-endian to little-endian format. On
+@@ -965,6 +975,7 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
+ unsigned char endpoint);
+ int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
+ unsigned char endpoint);
++int LIBUSB_CALL libusb_get_dev_speed(libusb_device *dev);
+
+ int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle);
+ void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
+diff --git a/libusb/libusbi.h b/libusb/libusbi.h
+index 974b108..87cd770 100644
+--- a/libusb/libusbi.h
++++ b/libusb/libusbi.h
+@@ -591,6 +591,13 @@ struct usbi_os_backend {
+ uint8_t config_index, unsigned char *buffer, size_t len,
+ int *host_endian);
+
++
++ /* Get the connected device speed
++ *
++ * Return 0 on success or a LIBUSB_ERROR_OTHER code on failure.
++ */
++ int (*get_device_speed)(struct libusb_device *device);
++
+ /* Get the bConfigurationValue for the active configuration for a device.
+ * Optional. This should only be implemented if you can retrieve it from
+ * cache (don't generate I/O).
+diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
+index 867893c..430d773 100644
+--- a/libusb/os/linux_usbfs.c
++++ b/libusb/os/linux_usbfs.c
+@@ -333,6 +333,61 @@ static int sysfs_get_device_descriptor(struct libusb_device *dev,
+ return 0;
+ }
+
++static int sysfs_get_device_speed(struct libusb_device *dev)
++{
++ int fd;
++ ssize_t r;
++ unsigned char buffer[32];
++ char *tmp;
++
++ fd = __open_sysfs_attr(dev, "speed");
++ if (fd < 0)
++ return fd;
++
++ r = read(fd, &buffer, 32);
++ close(fd);
++ if (r < 0) {
++ usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", fd, errno);
++ return LIBUSB_ERROR_OTHER;
++ }
++
++ /*
++ * The read string from sysfs terminates with a "new line" char
++ * (A in ascii code) which we want to trim
++ */
++ tmp = strchr(buffer, 10);
++ *tmp=0;
++
++ /*
++ * The spped is dumped in sysfs.c as follows:
++ * case USB_SPEED_LOW: speed = "1.5";
++ * case USB_SPEED_UNKNOWN/USB_SPEED_FULL: speed = "12";
++ * case USB_SPEED_HIGH/USB_SPEED_WIRELESS: speed = "480";
++ * case USB_SPEED_SUPER: speed = "5000";
++ */
++
++ if (!strcmp("1.5",buffer))
++ return LIBUSB_SPEED_LOW;
++
++ if (!strcmp("12",buffer))
++ return LIBUSB_SPEED_FULL;
++
++ if (!strcmp("480",buffer))
++ return LIBUSB_SPEED_HIGH;
++
++ if (!strcmp("5000",buffer))
++ return LIBUSB_SPEED_SUPER;
++
++ return LIBUSB_SPEED_UNKNOWN;
++}
++
++static int op_get_dev_speed(struct libusb_device *dev)
++{
++ if (sysfs_has_descriptors)
++ return sysfs_get_device_speed(dev);
++ return LIBUSB_SPEED_UNKNOWN;
++}
++
+ static int op_get_device_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, int *host_endian)
+ {
+@@ -2210,6 +2265,7 @@ const struct usbi_os_backend linux_usbfs_backend = {
+ .get_device_descriptor = op_get_device_descriptor,
+ .get_active_config_descriptor = op_get_active_config_descriptor,
+ .get_config_descriptor = op_get_config_descriptor,
++ .get_device_speed = op_get_dev_speed,
+
+ .open = op_open,
+ .close = op_close,
+--
+1.7.3.3
+
+--
+Sent by an employee of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
\ No newline at end of file
diff --git a/tools/usb/unittests/libusb_patches/0003-Add-UAS-defines.patch b/tools/usb/unittests/libusb_patches/0003-Add-UAS-defines.patch
new file mode 100644
index 0000000..a1abfd2
--- /dev/null
+++ b/tools/usb/unittests/libusb_patches/0003-Add-UAS-defines.patch
@@ -0,0 +1,56 @@
+From 45864135c176df8bf03bff05733acd8c8ec0579e Mon Sep 17 00:00:00 2001
+From: Tatyana Brokhman <tlinder@codeaurora.org>
+Date: Tue, 14 Jun 2011 13:25:37 +0300
+Subject: [PATCH 3/4] Add UAS defines
+
+This patch adds necessary definitions as defined by the UAS spec
+
+Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
+
+---
+ libusb/libusb.h | 19 ++++++++++++++++++-
+ 1 files changed, 18 insertions(+), 1 deletions(-)
+
+diff --git a/libusb/libusb.h b/libusb/libusb.h
+index 346f85f..c5e2fbb 100644
+--- a/libusb/libusb.h
++++ b/libusb/libusb.h
+@@ -210,7 +210,12 @@ enum libusb_descriptor_type {
+ LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
+
+ /** SuperSpeed Endpoint Companion descriptor */
+- LIBUSB_DT_SS_ENDPOINT_COMP = 0x30
++ LIBUSB_DT_SS_ENDPOINT_COMP = 0x30,
++
++ /** UASP descriptors: */
++ /** Pipe usage descriptor */
++ LIBUSB_DT_PIPE_USAGE = 0x24
++
+ };
+
+ /* Descriptor sizes per descriptor type */
+@@ -675,6 +680,18 @@ struct libusb_ss_usb_cap_descriptor { /* Link Power Management */
+ u_int16_t bU2DevExitLat;
+ };
+
++/* LIBUSB_DT_PIPE_USAGE descriptor */
++struct libusb_uasp_pipe_usage_desc {
++ u_int8_t bLength;
++ u_int8_t bDescriptorType;
++#define PIPE_ID_UNDEF 0x00
++#define PIPE_ID_CMD 0x01
++#define PIPE_ID_STS 0x02
++#define PIPE_ID_DATA_IN 0x03
++#define PIPE_ID_DATA_OUT 0x04
++ u_int8_t bPipeID;
++ u_int8_t reserved;
++};
+
+ /** \ingroup asyncio
+ * Setup packet for control transfers. */
+--
+1.7.3.3
+
+--
+Sent by an employee of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
\ No newline at end of file
diff --git a/tools/usb/unittests/libusb_patches/0004-libusb-Add-stream-support-to-LIBUSB.patch b/tools/usb/unittests/libusb_patches/0004-libusb-Add-stream-support-to-LIBUSB.patch
new file mode 100644
index 0000000..a7059be
--- /dev/null
+++ b/tools/usb/unittests/libusb_patches/0004-libusb-Add-stream-support-to-LIBUSB.patch
@@ -0,0 +1,314 @@
+From 436bfafeefaa7f71252578b66394735f5d2da0c6 Mon Sep 17 00:00:00 2001
+From: Tatyana Brokhman <tlinder@codeaurora.org>
+Date: Sun, 12 Jun 2011 15:05:32 +0300
+Subject: [PATCH 4/4] libusb: Add stream support to LIBUSB
+
+1. Add stream ID to bulk transfer API
+2. Add stream alloc/free APIs
+
+Signed-off-by: Amit Blay <ablay@qualcomm.com>
+
+---
+ libusb/core.c | 38 ++++++++++++++++++++++++++++++++++++++
+ libusb/libusb.h | 13 +++++++++++++
+ libusb/libusbi.h | 30 +++++++++++++++++++++++++++++-
+ libusb/os/linux_usbfs.c | 43 +++++++++++++++++++++++++++++++++++++++++++
+ libusb/os/linux_usbfs.h | 3 +++
+ libusb/sync.c | 42 +++++++++++++++++++++++++++++++++++++++---
+ 6 files changed, 165 insertions(+), 4 deletions(-)
+
+diff --git a/libusb/core.c b/libusb/core.c
+index 6d49fb3..b8bd11c 100644
+--- a/libusb/core.c
++++ b/libusb/core.c
+@@ -1298,6 +1298,44 @@ out:
+ }
+
+ /** \ingroup dev
++ * Allocate streams for an EP.
++ *
++ * This is a blocking function.
++ *
++ * \param dev a device handle
++ * \param ep_map the endpoints to allocate streams for
++ * \returns 0 on success
++ * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
++ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
++ * \returns another LIBUSB_ERROR code on other failure
++ */
++API_EXPORTED int libusb_alloc_streams(libusb_device_handle *dev,
++ unsigned int ep_map)
++{
++ usbi_dbg("endpoint %x", ep_map);
++ return usbi_backend->alloc_streams(dev, ep_map);
++}
++
++/** \ingroup dev
++ * Free streams for an EP.
++ *
++ * This is a blocking function.
++ *
++ * \param dev a device handle
++ * \param endpoint the endpoint to free streams for
++ * \returns 0 on success
++ * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
++ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
++ * \returns another LIBUSB_ERROR code on other failure
++ */
++API_EXPORTED int libusb_free_streams(libusb_device_handle *dev,
++ unsigned int ep_map)
++{
++ usbi_dbg("endpoint %x", ep_map);
++ return usbi_backend->free_streams(dev, ep_map);
++}
++
++/** \ingroup dev
+ * Activate an alternate setting for an interface. The interface must have
+ * been previously claimed with libusb_claim_interface().
+ *
+diff --git a/libusb/libusb.h b/libusb/libusb.h
+index c5e2fbb..1c70139 100644
+--- a/libusb/libusb.h
++++ b/libusb/libusb.h
+@@ -952,6 +952,10 @@ struct libusb_transfer {
+ * endpoints. */
+ int num_iso_packets;
+
++ /** Stream ID for the endpoint where the transfer will be
++ * sent. */
++ unsigned int stream_id;
++
+ /** Isochronous packet descriptors, for isochronous transfers only. */
+ struct libusb_iso_packet_descriptor iso_packet_desc
+ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+@@ -1004,6 +1008,11 @@ int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev,
+ int interface_number);
+ int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev,
+ int interface_number);
++int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev,
++ unsigned int ep_map);
++int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev,
++ unsigned int ep_map);
++
+
+ libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid(
+ libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);
+@@ -1331,6 +1340,10 @@ int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *actual_length, unsigned int timeout);
+
++int LIBUSB_CALL libusb_bulk_transfer_ex(libusb_device_handle *dev_handle,
++ unsigned char endpoint, unsigned char *data, int length,
++ int *actual_length, unsigned int timeout, unsigned int stream_id);
++
+ int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *actual_length, unsigned int timeout);
+diff --git a/libusb/libusbi.h b/libusb/libusbi.h
+index 87cd770..59c5e59 100644
+--- a/libusb/libusbi.h
++++ b/libusb/libusbi.h
+@@ -687,7 +687,35 @@ struct usbi_os_backend {
+ int (*set_interface_altsetting)(struct libusb_device_handle *handle,
+ int interface_number, int altsetting);
+
+- /* Clear a halt/stall condition on an endpoint.
++ /* Allcoate streams for en EP.
++ *
++ * It's OK for this function to block.
++ *
++ * Return:
++ * - 0 on success
++ * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
++ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
++ * was opened
++ * - another LIBUSB_ERROR code on other failure
++ */
++ int (*alloc_streams)(struct libusb_device_handle *handle,
++ unsigned int ep_map);
++
++ /* Free allocated streams for en EP.
++ *
++ * It's OK for this function to block.
++ *
++ * Return:
++ * - 0 on success
++ * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
++ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
++ * was opened
++ * - another LIBUSB_ERROR code on other failure
++ */
++ int (*free_streams)(struct libusb_device_handle *handle,
++ unsigned int ep_map);
++
++ /* Clear a halt/stall condition on an endpoint.
+ *
+ * It's OK for this function to block.
+ *
+diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
+index 430d773..ce62220 100644
+--- a/libusb/os/linux_usbfs.c
++++ b/libusb/os/linux_usbfs.c
+@@ -1215,6 +1215,46 @@ static int op_claim_interface(struct libusb_device_handle *handle, int iface)
+ return 0;
+ }
+
++static int op_alloc_streams(struct libusb_device_handle *handle,
++ unsigned int ep_map)
++{
++ int fd = __device_handle_priv(handle)->fd;
++ unsigned int _ep_map = ep_map;
++ int r = ioctl(fd, IOCTL_USBFS_ALLOC_STREAMS, &_ep_map);
++ if (r) {
++ if (errno == ENOENT)
++ return LIBUSB_ERROR_NOT_FOUND;
++ else if (errno == ENODEV)
++ return LIBUSB_ERROR_NO_DEVICE;
++
++ usbi_err(HANDLE_CTX(handle),
++ "alloc_streams failed error %d errno %d", r, errno);
++ return LIBUSB_ERROR_OTHER;
++ }
++
++ return 0;
++}
++
++static int op_free_streams(struct libusb_device_handle *handle,
++ unsigned int ep_map)
++{
++ int fd = __device_handle_priv(handle)->fd;
++ unsigned int _ep_map = ep_map;
++ int r = ioctl(fd, IOCTL_USBFS_FREE_STREAMS, &_ep_map);
++ if (r) {
++ if (errno == ENOENT)
++ return LIBUSB_ERROR_NOT_FOUND;
++ else if (errno == ENODEV)
++ return LIBUSB_ERROR_NO_DEVICE;
++
++ usbi_err(HANDLE_CTX(handle),
++ "free_streams failed error %d errno %d", r, errno);
++ return LIBUSB_ERROR_OTHER;
++ }
++
++ return 0;
++}
++
+ static int op_release_interface(struct libusb_device_handle *handle, int iface)
+ {
+ int fd = __device_handle_priv(handle)->fd;
+@@ -1450,6 +1490,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
+ urb->type = urb_type;
+ urb->endpoint = transfer->endpoint;
+ urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH);
++ urb->stream_id = transfer->stream_id;
+ if (supports_flag_bulk_continuation && !is_out)
+ urb->flags = USBFS_URB_SHORT_NOT_OK;
+ if (i == num_urbs - 1 && last_urb_partial)
+@@ -2273,6 +2314,8 @@ const struct usbi_os_backend linux_usbfs_backend = {
+ .set_configuration = op_set_configuration,
+ .claim_interface = op_claim_interface,
+ .release_interface = op_release_interface,
++ .alloc_streams = op_alloc_streams,
++ .free_streams = op_free_streams,
+
+ .set_interface_altsetting = op_set_interface,
+ .clear_halt = op_clear_halt,
+diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
+index bd02edc..9d5d4ca 100644
+--- a/libusb/os/linux_usbfs.h
++++ b/libusb/os/linux_usbfs.h
+@@ -96,6 +96,7 @@ struct usbfs_urb {
+ unsigned int signr;
+ void *usercontext;
+ struct usbfs_iso_packet_desc iso_frame_desc[0];
++ unsigned int stream_id;
+ };
+
+ struct usbfs_connectinfo {
+@@ -134,5 +135,7 @@ struct usbfs_hub_portinfo {
+ #define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int)
+ #define IOCTL_USBFS_DISCONNECT _IO('U', 22)
+ #define IOCTL_USBFS_CONNECT _IO('U', 23)
++#define IOCTL_USBFS_ALLOC_STREAMS _IOR('U', 26, unsigned int)
++#define IOCTL_USBFS_FREE_STREAMS _IOR('U', 27, unsigned int)
+
+ #endif
+diff --git a/libusb/sync.c b/libusb/sync.c
+index 3870f95..f4a6dc3 100644
+--- a/libusb/sync.c
++++ b/libusb/sync.c
+@@ -152,7 +152,8 @@ static void LIBUSB_CALL bulk_transfer_cb(struct libusb_transfer *transfer)
+
+ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *buffer, int length,
+- int *transferred, unsigned int timeout, unsigned char type)
++ int *transferred, unsigned int timeout, unsigned char type,
++ unsigned int stream_id)
+ {
+ struct libusb_transfer *transfer = libusb_alloc_transfer(0);
+ int completed = 0;
+@@ -164,6 +165,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
+ bulk_transfer_cb, &completed, timeout);
+ transfer->type = type;
++ transfer->stream_id = stream_id;
+
+ r = libusb_submit_transfer(transfer);
+ if (r < 0) {
+@@ -257,7 +259,41 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
+ unsigned int timeout)
+ {
+ return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
+- transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK);
++ transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK, 0);
++}
++
++/** \ingroup syncio
++ * Perform a USB bulk transfer with extended paramter list,
++ * which includes USB3 stream ID.
++ *
++ * \param dev_handle a handle for the device to communicate with
++ * \param endpoint the address of a valid endpoint to communicate with
++ * \param data a suitably-sized data buffer for either input or output
++ * (depending on endpoint)
++ * \param length for bulk writes, the number of bytes from data to be sent. for
++ * bulk reads, the maximum number of bytes to receive into the data buffer.
++ * \param transferred output location for the number of bytes actually
++ * transferred.
++ * \param timeout timeout (in millseconds) that this function should wait
++ * before giving up due to no response being received. For an unlimited
++ * timeout, use value 0.
++ *
++ * \returns 0 on success (and populates transferred )
++ * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates
++ * transferred )
++ * \returns LIBUSB_ERROR_PIPE if the endpoint halted
++ * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see
++ * \ref packetoverflow
++ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
++ * \returns another LIBUSB_ERROR code on other failures
++ */
++API_EXPORTED int libusb_bulk_transfer_ex(
++ struct libusb_device_handle *dev_handle, unsigned char endpoint,
++ unsigned char *data, int length, int *transferred, unsigned int timeout,
++ unsigned int stream_id)
++{
++ return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
++ transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK, stream_id);
+ }
+
+ /** \ingroup syncio
+@@ -306,6 +342,6 @@ int API_EXPORTED libusb_interrupt_transfer(
+ unsigned char *data, int length, int *transferred, unsigned int timeout)
+ {
+ return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
+- transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
++ transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT, 0);
+ }
+
+--
+1.7.3.3
+
+--
+Sent by an employee of the Qualcomm Innovation Center, Inc.
+The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
\ No newline at end of file
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..599416b
--- /dev/null
+++ b/tools/usb/unittests/usb/composite_tests.cc
@@ -0,0 +1,1645 @@
+/*
+ * 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 or dummy_hcd).
+ * @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
+ * 0x52 - start connect/disconnect sequence
+ * @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) and dummy_hcd modules
+ */
+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;
+ }
+
+ wValue = 0;
+ ret = soursesink_test_setup(udev, dev, CONN_DISCONN_TEST, wValue);
+
+ /*
+ * 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..550e0cb
--- /dev/null
+++ b/tools/usb/unittests/usb/composite_tests.h
@@ -0,0 +1,293 @@
+/*
+ * 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"
+
+
+/**
+ * soursesink_test_setup() - Send a control request to setup/begin a spesific
+ * test (to be handled by f_soursesink or dummy_hcd).
+ * @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
+ * 0x52 - start connect/disconnect sequence
+ * @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) and dummy_hcd modules
+ */
+int soursesink_test_setup(struct libusb_device_handle *udev,
+ libusb_device *dev,
+ uint8_t request,
+ uint16_t wValue);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * test_hs_set_feature_suspend_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 hs interface in default
+ * state, to set the suspend capability
+ */
+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.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.