-
Notifications
You must be signed in to change notification settings - Fork 40
Add test script to validate USB UVC #520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| ``` | ||
| Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. | ||
| SPDX-License-Identifier: BSD-3-Clause | ||
| ``` | ||
|
|
||
| # USB Video Class Validation | ||
|
|
||
| ## Overview | ||
|
|
||
| This shell script executes on the DUT (Device-Under-Test) and validates USB Video Class (UVC) devices. | ||
| The test validation scope includes: | ||
| - Successful enumeration of UVC devices and display following details for each device: | ||
| - DEVICE (USB device address), VID:PID, and PRODUCT string. | ||
| - Validation of video device nodes creation: | ||
| - For each UVC interface of each detected device, verify /dev/video* nodes exist. | ||
| - Print a table of enumerated devices: | ||
|
|
||
| ``` | ||
| DEVICE VID:PID DRIVER PRODUCT | ||
| ------------------------------------------------------------------------------- | ||
| <dev> <vid:pid> <uvcvideo> <product> | ||
| ``` | ||
| The test PASS requires all detected UVC devices to have associated /dev/video* nodes. | ||
|
|
||
| Running this test on a DUT without a connected USB Video peripheral is expected to FAIL with the message: No 'USB Video Device' found. | ||
|
|
||
| --- | ||
|
|
||
| ## Setup | ||
|
|
||
| - Connect USB Video peripheral(s) to USB port(s) on DUT. | ||
| - Only applicable for USB ports that support Host Mode functionality. | ||
| - USB Video peripherals examples: USB webcam, video capture cards, etc. | ||
|
|
||
| --- | ||
|
|
||
| ## Usage | ||
| ### Instructions: | ||
| 1. **Copy the test suite to the target device** using `scp` or any preferred method. | ||
| 2. **Navigate to the test directory** on the target device. | ||
| 3. **Run the test script** using the test runner or directly. | ||
|
|
||
| --- | ||
|
|
||
| ### Quick Example | ||
| ``` | ||
| cd Runner | ||
| ./run-test.sh usb_uvc | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| #!/bin/sh | ||
|
|
||
| # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
| # Validate USB Video Class (UVC) device detection and creation of /dev/video* nodes | ||
| # Requires at least one USB Video peripheral (e.g., USB webcam) connected to a USB Host port. | ||
|
|
||
| TESTNAME="usb_uvc" | ||
|
|
||
| # Robustly find and source init_env | ||
| SCRIPT_DIR="$( | ||
| cd "$(dirname "$0")" || exit 1 | ||
| pwd | ||
| )" | ||
|
|
||
| # Default result file (works even before functestlib is available) | ||
| # shellcheck disable=SC2034 | ||
| RES_FILE="$SCRIPT_DIR/${TESTNAME}.res" | ||
|
|
||
| INIT_ENV="" | ||
| SEARCH="$SCRIPT_DIR" | ||
| while [ "$SEARCH" != "/" ]; do | ||
| if [ -f "$SEARCH/init_env" ]; then | ||
| INIT_ENV="$SEARCH/init_env" | ||
| break | ||
| fi | ||
| SEARCH=$(dirname "$SEARCH") | ||
| done | ||
|
|
||
| if [ -z "$INIT_ENV" ]; then | ||
| echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 | ||
| echo "$TESTNAME SKIP" >"$RES_FILE" 2>/dev/null || true | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Only source if not already loaded (idempotent) | ||
| if [ -z "${__INIT_ENV_LOADED:-}" ]; then | ||
| # shellcheck disable=SC1090 | ||
| . "$INIT_ENV" | ||
| __INIT_ENV_LOADED=1 | ||
| fi | ||
| # Always source functestlib.sh, using $TOOLS exported by init_env | ||
| # shellcheck disable=SC1090,SC1091 | ||
| . "$TOOLS/functestlib.sh" | ||
|
|
||
| # Resolve test path and cd (single SKIP/exit path) | ||
| SKIP_REASON="" | ||
| test_path=$(find_test_case_by_name "$TESTNAME") | ||
| if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then | ||
| SKIP_REASON="$TESTNAME SKIP - test path not found" | ||
| elif ! cd "$test_path"; then | ||
| SKIP_REASON="$TESTNAME SKIP - cannot cd into $test_path" | ||
| else | ||
| RES_FILE="$test_path/${TESTNAME}.res" | ||
| fi | ||
|
|
||
| if [ -n "$SKIP_REASON" ]; then | ||
| log_skip "$SKIP_REASON" | ||
| echo "$TESTNAME SKIP" >"$RES_FILE" 2>/dev/null || true | ||
| exit 0 | ||
| fi | ||
|
|
||
| log_info "-----------------------------------------------------------------------------------------" | ||
| log_info "-------------------Starting $TESTNAME Testcase----------------------------" | ||
| log_info "=== Test Initialization ===" | ||
|
|
||
| # Check if dependencies are installed, else skip test | ||
| # Include all external utilities used by this script | ||
| deps_list="grep sed sort wc tr readlink head awk" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The dependency declaration includes unused head and awk, while the script invokes external basename at line 127 without declaring it. Remove unused dependencies and either declare basename or replace it with shell parameter expansion. |
||
| check_dependencies "$deps_list" | ||
|
|
||
| # Detect unique devices with bInterfaceClass = 0e (UVC) under /sys/bus/usb/devices | ||
| # Accept common encodings: '0e', '0E', or decimal '14' | ||
| log_info "=== USB Video device Detection ===" | ||
| video_device_list="$( | ||
| for f in /sys/bus/usb/devices/*/bInterfaceClass; do | ||
| [ -r "$f" ] || continue | ||
| if grep -qx '0e' "$f" || grep -qx '0E' "$f" || grep -qx '14' "$f"; then | ||
| d=${f%/bInterfaceClass} | ||
| d=${d%:*} | ||
| printf '%s\n' "${d##*/}" | ||
| fi | ||
| done 2>/dev/null | sort -u | ||
| )" | ||
|
|
||
| video_device_count="$(printf "%s\n" "$video_device_list" | sed '/^$/d' | wc -l | tr -d '[:space:]')" | ||
| log_info "Number of USB video devices found: $video_device_count" | ||
|
|
||
| if [ "$video_device_count" -gt 0 ] 2>/dev/null; then | ||
| log_info "=== Enumerated USB Video Devices ===" | ||
| printf '\n%-9s %-9s %-18s %-s\n' "DEVICE" "VID:PID" "DRIVER" "PRODUCT" | ||
| printf '%s\n' "--------------------------------------------------------" | ||
| dev_info_db="" | ||
| associated_nodes="" | ||
| for dev in $(printf "%s\n" "$video_device_list" | sed '/^$/d'); do | ||
| sys="/sys/bus/usb/devices/$dev" | ||
| vid=$([ -r "$sys/idVendor" ] && tr -d '[:space:]' < "$sys/idVendor" || echo -) | ||
| pid=$([ -r "$sys/idProduct" ] && tr -d '[:space:]' < "$sys/idProduct" || echo -) | ||
| if [ -r "$sys/product" ]; then | ||
| product=$(tr -d '\000' < "$sys/product") | ||
| else | ||
| product="-" | ||
| fi | ||
| # Determine driver from the UVC interface driver symlink | ||
| driver="-" | ||
| for intf in "$sys":*; do | ||
| # Only consider UVC interfaces (bInterfaceClass == 0e/14) | ||
| if [ -r "$intf/bInterfaceClass" ] && { grep -qx '0e' "$intf/bInterfaceClass" || grep -qx '0E' "$intf/bInterfaceClass" || grep -qx '14' "$intf/bInterfaceClass"; }; then | ||
| # Resolve driver symlink and extract driver name | ||
| if [ -L "$intf/driver" ]; then | ||
| link="$(readlink "$intf/driver" 2>/dev/null)" | ||
| driver="$(printf "%s\n" "$link" | grep -o 'uvcvideo' || echo -)" | ||
| fi | ||
| break | ||
| fi | ||
| done | ||
| dev_info_db="${dev_info_db}\n${dev}|${vid}:${pid}|${driver}|${product}" | ||
| printf '%-9s %-9s %-18s %-s\n' "$dev" "$vid:$pid" "$driver" "$product" | ||
|
|
||
| # Print associated /dev/video* nodes for this UVC device | ||
| for intf in "$sys":*; do | ||
| # Only consider UVC interfaces (bInterfaceClass == 0e/14) | ||
| if [ -r "$intf/bInterfaceClass" ] && { grep -qx '0e' "$intf/bInterfaceClass" || grep -qx '0E' "$intf/bInterfaceClass" || grep -qx '14' "$intf/bInterfaceClass"; }; then | ||
| if [ -d "$intf/video4linux" ]; then | ||
| for v in "$intf"/video4linux/video*; do | ||
| [ -e "$v" ] || continue | ||
| node="/dev/$(basename "$v")" | ||
| if [ -e "$node" ]; then | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sysfs may expose video4linux/video* before udev creates the corresponding /dev/video* node. Checking the node only once makes the test race device enumeration and can produce intermittent false failures. Reuse wait_for_path from Runner/utils/functestlib.sh with a bounded timeout, such as wait_for_path "$node" 5, before declaring the node missing. |
||
| log_info "UVC device $dev (${vid}:${pid} '${product}', driver: ${driver}): ${node} exists" | ||
| associated_nodes="${associated_nodes}\n${node}" | ||
| fi | ||
| done | ||
| fi | ||
| fi | ||
| done | ||
| done | ||
| printf '\n' | ||
| fi | ||
|
|
||
| if [ "$video_device_count" -le 0 ] 2>/dev/null; then | ||
| log_fail "$TESTNAME : Test Failed - No 'USB Video Device' found" | ||
| echo "$TESTNAME FAIL" > "$RES_FILE" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Count only /dev/video* nodes associated with detected UVC devices | ||
| video_node_count="$(printf "%b\n" "$associated_nodes" | sed '/^$/d' | sort -u | wc -l | tr -d '[:space:]')" | ||
| log_info "Number of /dev/video* nodes found: ${video_node_count:-0}" | ||
|
|
||
| # Pass if the number of /dev/video* nodes is at least the number of detected UVC devices | ||
| if [ "${video_node_count:-0}" -ge "$video_device_count" ] 2>/dev/null; then | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The final result compares the total number of unique /dev/video* nodes with the total number of UVC devices. This does not prove that every UVC device has a node. For example, one device exposing two nodes and another exposing none produces 2 >= 2 and incorrectly passes. Track validation per USB device and fail when any detected device has no associated video node. The sibling usb_msd/run.sh test demonstrates the expected per-device tracking pattern. |
||
| log_pass "$TESTNAME : Test Passed - Found /dev/video* nodes for detected UVC device(s)" | ||
| echo "$TESTNAME PASS" > "$RES_FILE" | ||
| exit 0 | ||
| else | ||
| log_fail "$TESTNAME : Test Failed - /dev/video* nodes do not exist for detected UVC device(s)" | ||
| echo "$TESTNAME FAIL" > "$RES_FILE" | ||
| exit 0 | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| metadata: | ||
| name: usb_uvc | ||
| format: "Lava-Test Test Definition 1.0" | ||
| description: "This shell script executes on the DUT (Device-Under-Test) and verifies enumeration of connected USB Video Class (UVC) devices and creation of /dev/video* nodes." | ||
| os: | ||
| - linux | ||
| scope: | ||
| - functional | ||
|
|
||
| run: | ||
| steps: | ||
| - REPO_PATH=$PWD | ||
| - cd Runner/suites/Kernel/Baseport/USB/usb_uvc | ||
| - ./run.sh || true | ||
| - $REPO_PATH/Runner/utils/send-to-lava.sh usb_uvc.res |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove trailing whitespaces