Merge pull request #3114 from hathach/fix-sigma-mouse-multiple-attach
Fix sigma mouse multiple attach
This commit is contained in:
123
.github/workflows/build.yml
vendored
123
.github/workflows/build.yml
vendored
@@ -8,8 +8,8 @@ on:
|
|||||||
- 'examples/**'
|
- 'examples/**'
|
||||||
- 'lib/**'
|
- 'lib/**'
|
||||||
- 'hw/**'
|
- 'hw/**'
|
||||||
- 'tools/get_deps.py'
|
|
||||||
- 'tools/build.py'
|
- 'tools/build.py'
|
||||||
|
- 'tools/get_deps.py'
|
||||||
- '.github/actions/**'
|
- '.github/actions/**'
|
||||||
- '.github/workflows/build.yml'
|
- '.github/workflows/build.yml'
|
||||||
- '.github/workflows/build_util.yml'
|
- '.github/workflows/build_util.yml'
|
||||||
@@ -21,8 +21,9 @@ on:
|
|||||||
- 'examples/**'
|
- 'examples/**'
|
||||||
- 'lib/**'
|
- 'lib/**'
|
||||||
- 'hw/**'
|
- 'hw/**'
|
||||||
- 'tools/get_deps.py'
|
- 'test/hil/**'
|
||||||
- 'tools/build.py'
|
- 'tools/build.py'
|
||||||
|
- 'tools/get_deps.py'
|
||||||
- '.github/actions/**'
|
- '.github/actions/**'
|
||||||
- '.github/workflows/build.yml'
|
- '.github/workflows/build.yml'
|
||||||
- '.github/workflows/build_util.yml'
|
- '.github/workflows/build_util.yml'
|
||||||
@@ -31,11 +32,20 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
HIL_JSON: test/hil/tinyusb.json
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# ---------------------------------------
|
||||||
|
#
|
||||||
|
# Build
|
||||||
|
#
|
||||||
|
# ---------------------------------------
|
||||||
set-matrix:
|
set-matrix:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
json: ${{ steps.set-matrix-json.outputs.matrix }}
|
json: ${{ steps.set-matrix-json.outputs.matrix }}
|
||||||
|
hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout TinyUSB
|
- name: Checkout TinyUSB
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -43,9 +53,14 @@ jobs:
|
|||||||
- name: Generate matrix json
|
- name: Generate matrix json
|
||||||
id: set-matrix-json
|
id: set-matrix-json
|
||||||
run: |
|
run: |
|
||||||
|
# build matrix
|
||||||
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)
|
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)
|
||||||
echo "matrix=$MATRIX_JSON"
|
echo "matrix=$MATRIX_JSON"
|
||||||
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
|
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
|
||||||
|
# hil matrix
|
||||||
|
HIL_MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }})
|
||||||
|
echo "hil_matrix=$HIL_MATRIX_JSON"
|
||||||
|
echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Build CMake
|
# Build CMake
|
||||||
@@ -151,3 +166,107 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
west build -b pca10056 -d examples/device/cdc_msc/build examples/device/cdc_msc -- -DRTOS=zephyr
|
west build -b pca10056 -d examples/device/cdc_msc/build examples/device/cdc_msc -- -DRTOS=zephyr
|
||||||
west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr
|
west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
#
|
||||||
|
# Hardware in the loop (HIL)
|
||||||
|
# Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR
|
||||||
|
# ---------------------------------------
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Build arm-gcc
|
||||||
|
# ---------------------------------------
|
||||||
|
hil-build:
|
||||||
|
if: |
|
||||||
|
github.repository_owner == 'hathach' &&
|
||||||
|
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
|
||||||
|
needs: set-matrix
|
||||||
|
uses: ./.github/workflows/build_util.yml
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
toolchain:
|
||||||
|
- 'arm-gcc'
|
||||||
|
- 'esp-idf'
|
||||||
|
with:
|
||||||
|
build-system: 'cmake'
|
||||||
|
toolchain: ${{ matrix.toolchain }}
|
||||||
|
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.hil_json)[matrix.toolchain]) }}
|
||||||
|
one-per-family: true
|
||||||
|
upload-artifacts: true
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Hardware in the loop (HIL)
|
||||||
|
# self-hosted on local VM, for attached hardware checkout HIL_JSON
|
||||||
|
# ---------------------------------------
|
||||||
|
hil-tinyusb:
|
||||||
|
if: |
|
||||||
|
github.repository_owner == 'hathach' &&
|
||||||
|
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
|
||||||
|
needs: hil-build
|
||||||
|
runs-on: [self-hosted, X64, hathach, hardware-in-the-loop]
|
||||||
|
steps:
|
||||||
|
- name: Clean workspace
|
||||||
|
run: |
|
||||||
|
echo "Cleaning up previous run"
|
||||||
|
rm -rf "${{ github.workspace }}"
|
||||||
|
mkdir -p "${{ github.workspace }}"
|
||||||
|
|
||||||
|
- name: Checkout TinyUSB
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
sparse-checkout: test/hil
|
||||||
|
|
||||||
|
- name: Download Artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: cmake-build
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Test on actual hardware
|
||||||
|
run: |
|
||||||
|
ls cmake-build/
|
||||||
|
python3 test/hil/hil_test.py ${{ env.HIL_JSON }}
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Hardware in the loop (HIL)
|
||||||
|
# self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
|
||||||
|
# Since IAR Token secret is not passed to forked PR, only build non-forked PR
|
||||||
|
# ---------------------------------------
|
||||||
|
hil-hfp:
|
||||||
|
if: |
|
||||||
|
github.repository_owner == 'hathach' &&
|
||||||
|
github.event.pull_request.head.repo.fork == false &&
|
||||||
|
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
|
||||||
|
runs-on: [self-hosted, Linux, X64, hifiphile]
|
||||||
|
env:
|
||||||
|
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Clean workspace
|
||||||
|
run: |
|
||||||
|
echo "Cleaning up previous run"
|
||||||
|
rm -rf "${{ github.workspace }}"3
|
||||||
|
mkdir -p "${{ github.workspace }}"
|
||||||
|
|
||||||
|
- name: Toolchain version
|
||||||
|
run: |
|
||||||
|
iccarm --version
|
||||||
|
|
||||||
|
- name: Checkout TinyUSB
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get build boards
|
||||||
|
run: |
|
||||||
|
MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json)
|
||||||
|
BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")')
|
||||||
|
echo "BUILD_ARGS=$BUILD_ARGS"
|
||||||
|
echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get Dependencies
|
||||||
|
run: python3 tools/get_deps.py $BUILD_ARGS
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
|
||||||
|
|
||||||
|
- name: Test on actual hardware (hardware in the loop)
|
||||||
|
run: python3 test/hil/hil_test.py hfp.json
|
||||||
|
128
.github/workflows/hil_test.yml
vendored
128
.github/workflows/hil_test.yml
vendored
@@ -1,128 +0,0 @@
|
|||||||
name: Hardware Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
paths:
|
|
||||||
- 'src/**'
|
|
||||||
- 'examples/**'
|
|
||||||
- 'lib/**'
|
|
||||||
- 'hw/**'
|
|
||||||
- 'test/hil/**'
|
|
||||||
- 'tools/get_deps.py'
|
|
||||||
- '.github/actions/**'
|
|
||||||
- '.github/workflows/hil_test.yml'
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
HIL_JSON: test/hil/tinyusb.json
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
set-matrix:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
json: ${{ steps.set-matrix-json.outputs.matrix }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout TinyUSB
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Generate matrix json
|
|
||||||
id: set-matrix-json
|
|
||||||
run: |
|
|
||||||
MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }})
|
|
||||||
echo "matrix=$MATRIX_JSON"
|
|
||||||
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# ---------------------------------------
|
|
||||||
# Build arm-gcc
|
|
||||||
# ---------------------------------------
|
|
||||||
build:
|
|
||||||
if: github.repository_owner == 'hathach'
|
|
||||||
needs: set-matrix
|
|
||||||
uses: ./.github/workflows/build_util.yml
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
toolchain:
|
|
||||||
- 'arm-gcc'
|
|
||||||
- 'esp-idf'
|
|
||||||
with:
|
|
||||||
build-system: 'cmake'
|
|
||||||
toolchain: ${{ matrix.toolchain }}
|
|
||||||
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
|
|
||||||
one-per-family: true
|
|
||||||
upload-artifacts: true
|
|
||||||
|
|
||||||
# ---------------------------------------
|
|
||||||
# Hardware in the loop (HIL)
|
|
||||||
# self-hosted on local VM, for attached hardware checkout HIL_JSON
|
|
||||||
# ---------------------------------------
|
|
||||||
hil-tinyusb:
|
|
||||||
if: github.repository_owner == 'hathach'
|
|
||||||
needs: build
|
|
||||||
runs-on: [self-hosted, X64, hathach, hardware-in-the-loop]
|
|
||||||
steps:
|
|
||||||
- name: Clean workspace
|
|
||||||
run: |
|
|
||||||
echo "Cleaning up previous run"
|
|
||||||
rm -rf "${{ github.workspace }}"
|
|
||||||
mkdir -p "${{ github.workspace }}"
|
|
||||||
|
|
||||||
- name: Checkout TinyUSB
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
sparse-checkout: test/hil
|
|
||||||
|
|
||||||
- name: Download Artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: cmake-build
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Test on actual hardware
|
|
||||||
run: |
|
|
||||||
ls cmake-build/
|
|
||||||
python3 test/hil/hil_test.py ${{ env.HIL_JSON }}
|
|
||||||
|
|
||||||
# ---------------------------------------
|
|
||||||
# Hardware in the loop (HIL)
|
|
||||||
# self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
|
|
||||||
# Since IAR Token secret is not passed to forked PR, only build non-forked PR
|
|
||||||
# ---------------------------------------
|
|
||||||
hil-hfp:
|
|
||||||
if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false
|
|
||||||
runs-on: [self-hosted, Linux, X64, hifiphile]
|
|
||||||
env:
|
|
||||||
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
|
|
||||||
steps:
|
|
||||||
- name: Clean workspace
|
|
||||||
run: |
|
|
||||||
echo "Cleaning up previous run"
|
|
||||||
rm -rf "${{ github.workspace }}"
|
|
||||||
mkdir -p "${{ github.workspace }}"
|
|
||||||
|
|
||||||
- name: Toolchain version
|
|
||||||
run: |
|
|
||||||
iccarm --version
|
|
||||||
|
|
||||||
- name: Checkout TinyUSB
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Get build boards
|
|
||||||
run: |
|
|
||||||
MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json)
|
|
||||||
BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")')
|
|
||||||
echo "BUILD_ARGS=$BUILD_ARGS"
|
|
||||||
echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Get Dependencies
|
|
||||||
run: python3 tools/get_deps.py $BUILD_ARGS
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
|
|
||||||
|
|
||||||
- name: Test on actual hardware (hardware in the loop)
|
|
||||||
run: python3 test/hil/hil_test.py hfp.json
|
|
2
.idea/debugServers/rt1064.xml
generated
2
.idea/debugServers/rt1064.xml
generated
@@ -1,5 +1,5 @@
|
|||||||
<component name="DebugServers">
|
<component name="DebugServers">
|
||||||
<jlink-debug-target name="rt1064" uniqueID="9602472b-6ce8-4a2d-9636-1c03b5fcd6da" selected="true">
|
<jlink-debug-target name="rt1064" uniqueID="9602472b-6ce8-4a2d-9636-1c03b5fcd6da">
|
||||||
<debugger version="1">
|
<debugger version="1">
|
||||||
<debugger kind="GDB" isBundled="true" />
|
<debugger kind="GDB" isBundled="true" />
|
||||||
<env />
|
<env />
|
||||||
|
@@ -459,7 +459,8 @@ static void process_new_status(tuh_xfer_t* xfer) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
hcd_event_handler(&event, false);
|
hcd_event_handler(&event, false);
|
||||||
processed = true; // usbh queue status after handled this in (de)enumeration
|
// skip status for attach event, usbh will do it after handled this enumeration
|
||||||
|
processed = (event.event_id == HCD_EVENT_DEVICE_ATTACH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
254
src/host/usbh.c
254
src/host/usbh.c
@@ -34,7 +34,7 @@
|
|||||||
#include "hub.h"
|
#include "hub.h"
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// USBH Configuration
|
// Configuration
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
||||||
#define CFG_TUH_TASK_QUEUE_SZ 16
|
#define CFG_TUH_TASK_QUEUE_SZ 16
|
||||||
@@ -89,7 +89,7 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// USBH-HCD common data structure
|
// Data Structure
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
typedef struct {
|
typedef struct {
|
||||||
tuh_bus_info_t bus_info;
|
tuh_bus_info_t bus_info;
|
||||||
@@ -131,8 +131,60 @@ typedef struct {
|
|||||||
|
|
||||||
} usbh_device_t;
|
} usbh_device_t;
|
||||||
|
|
||||||
|
// sum of end device + hub
|
||||||
|
#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB)
|
||||||
|
|
||||||
|
// all devices excluding zero-address
|
||||||
|
// hub address start from CFG_TUH_DEVICE_MAX+1
|
||||||
|
// TODO: hub can has its own simpler struct to save memory
|
||||||
|
static usbh_device_t _usbh_devices[TOTAL_DEVICES];
|
||||||
|
|
||||||
|
// Mutex for claiming endpoint
|
||||||
|
#if OSAL_MUTEX_REQUIRED
|
||||||
|
static osal_mutex_def_t _usbh_mutexdef;
|
||||||
|
static osal_mutex_t _usbh_mutex;
|
||||||
|
#else
|
||||||
|
#define _usbh_mutex NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Event queue: usbh_int_set() is used as mutex in OS NONE config
|
||||||
|
OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
|
||||||
|
static osal_queue_t _usbh_q;
|
||||||
|
|
||||||
|
// Control transfers: since most controllers do not support multiple control transfers
|
||||||
|
// on multiple devices concurrently and control transfers are not used much except for
|
||||||
|
// enumeration, we will only execute control transfers one at a time.
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* buffer;
|
||||||
|
tuh_xfer_cb_t complete_cb;
|
||||||
|
uintptr_t user_data;
|
||||||
|
|
||||||
|
volatile uint8_t stage;
|
||||||
|
uint8_t daddr;
|
||||||
|
volatile uint16_t actual_len;
|
||||||
|
uint8_t failed_count;
|
||||||
|
} usbh_ctrl_xfer_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t controller_id; // controller ID
|
||||||
|
uint8_t enumerating_daddr; // device address of the device being enumerated
|
||||||
|
uint8_t attach_debouncing_bm; // bitmask for roothub port attach debouncing
|
||||||
|
tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration
|
||||||
|
usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer
|
||||||
|
} usbh_data_t;
|
||||||
|
|
||||||
|
static usbh_data_t _usbh_data = {
|
||||||
|
.controller_id = TUSB_INDEX_INVALID_8,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request);
|
||||||
|
TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE);
|
||||||
|
} usbh_epbuf_t;
|
||||||
|
CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf;
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MACRO CONSTANT TYPEDEF
|
// Class Driver
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
|
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
|
||||||
#define DRIVER_NAME(_name) _name
|
#define DRIVER_NAME(_name) _name
|
||||||
@@ -235,71 +287,21 @@ static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
// Function Inline and Prototypes
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
static bool enum_new_device(hcd_event_t* event);
|
||||||
|
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
||||||
|
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
||||||
|
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||||
|
|
||||||
// sum of end device + hub
|
|
||||||
#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB)
|
|
||||||
|
|
||||||
// all devices excluding zero-address
|
|
||||||
// hub address start from CFG_TUH_DEVICE_MAX+1
|
|
||||||
// TODO: hub can has its own simpler struct to save memory
|
|
||||||
static usbh_device_t _usbh_devices[TOTAL_DEVICES];
|
|
||||||
|
|
||||||
// Mutex for claiming endpoint
|
|
||||||
#if OSAL_MUTEX_REQUIRED
|
|
||||||
static osal_mutex_def_t _usbh_mutexdef;
|
|
||||||
static osal_mutex_t _usbh_mutex;
|
|
||||||
#else
|
|
||||||
#define _usbh_mutex NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Event queue: usbh_int_set() is used as mutex in OS NONE config
|
|
||||||
OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
|
|
||||||
static osal_queue_t _usbh_q;
|
|
||||||
|
|
||||||
// Control transfers: since most controllers do not support multiple control transfers
|
|
||||||
// on multiple devices concurrently and control transfers are not used much except for
|
|
||||||
// enumeration, we will only execute control transfers one at a time.
|
|
||||||
typedef struct {
|
|
||||||
uint8_t* buffer;
|
|
||||||
tuh_xfer_cb_t complete_cb;
|
|
||||||
uintptr_t user_data;
|
|
||||||
|
|
||||||
volatile uint8_t stage;
|
|
||||||
uint8_t daddr;
|
|
||||||
volatile uint16_t actual_len;
|
|
||||||
uint8_t failed_count;
|
|
||||||
} usbh_ctrl_xfer_info_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t controller_id; // controller ID
|
|
||||||
uint8_t enumerating_daddr; // device address of the device being enumerated
|
|
||||||
uint8_t attach_debouncing_bm; // bitmask for roothub port attach debouncing
|
|
||||||
tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration
|
|
||||||
usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer
|
|
||||||
} usbh_data_t;
|
|
||||||
|
|
||||||
static usbh_data_t _usbh_data = {
|
|
||||||
.controller_id = TUSB_INDEX_INVALID_8,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request);
|
|
||||||
TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE);
|
|
||||||
} usbh_epbuf_t;
|
|
||||||
CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf;
|
|
||||||
|
|
||||||
//------------- Helper Function -------------//
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) {
|
TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) {
|
||||||
TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
|
TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
|
||||||
return &_usbh_devices[dev_addr-1];
|
return &_usbh_devices[dev_addr-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool enum_new_device(hcd_event_t* event);
|
TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) {
|
||||||
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
|
||||||
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
}
|
||||||
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) {
|
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) {
|
||||||
TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr));
|
TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr));
|
||||||
@@ -307,10 +309,40 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) {
|
||||||
|
if (_usbh_data.ctrl_xfer_info.stage != stage) {
|
||||||
|
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||||
|
_usbh_data.ctrl_xfer_info.stage = stage;
|
||||||
|
(void) osal_mutex_unlock(_usbh_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) {
|
||||||
|
const uint8_t rhport = usbh_get_rhport(daddr);
|
||||||
|
const bool ret = hcd_setup_send(rhport, daddr, setup_packet);
|
||||||
|
if (!ret) {
|
||||||
|
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8_t daddr) {
|
||||||
|
hcd_device_close(rhport, daddr);
|
||||||
|
|
||||||
|
// abort any ongoing control transfer
|
||||||
|
if (daddr == _usbh_data.ctrl_xfer_info.daddr) {
|
||||||
|
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidate if enumerating
|
||||||
|
if (daddr == _usbh_data.enumerating_daddr) {
|
||||||
|
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Device API
|
// Device API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
bool tuh_mounted(uint8_t dev_addr) {
|
bool tuh_mounted(uint8_t dev_addr) {
|
||||||
usbh_device_t *dev = get_device(dev_addr);
|
usbh_device_t *dev = get_device(dev_addr);
|
||||||
TU_VERIFY(dev);
|
TU_VERIFY(dev);
|
||||||
@@ -530,16 +562,16 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HCD_EVENT_DEVICE_REMOVE:
|
case HCD_EVENT_DEVICE_REMOVE:
|
||||||
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
TU_LOG1("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||||
process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
if (_usbh_data.enumerating_daddr == 0 &&
|
||||||
|
event.rhport == _usbh_data.dev0_bus.rhport &&
|
||||||
#if CFG_TUH_HUB
|
event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
|
||||||
// TODO remove
|
event.connection.hub_port == _usbh_data.dev0_bus.hub_port) {
|
||||||
if (event.connection.hub_addr != 0 && event.connection.hub_port != 0) {
|
// dev0 is unplugged while enumerating (not yet assigned an address)
|
||||||
// done with hub, waiting for next data on status pipe
|
usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
|
||||||
(void) hub_edpt_status_xfer(event.connection.hub_addr);
|
} else {
|
||||||
|
process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCD_EVENT_XFER_COMPLETE: {
|
case HCD_EVENT_XFER_COMPLETE: {
|
||||||
@@ -623,23 +655,6 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) {
|
|||||||
*((xfer_result_t*) xfer->user_data) = xfer->result;
|
*((xfer_result_t*) xfer->user_data) = xfer->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) {
|
|
||||||
if (_usbh_data.ctrl_xfer_info.stage != stage) {
|
|
||||||
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
|
||||||
_usbh_data.ctrl_xfer_info.stage = stage;
|
|
||||||
(void) osal_mutex_unlock(_usbh_mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) {
|
|
||||||
const uint8_t rhport = usbh_get_rhport(daddr);
|
|
||||||
const bool ret = hcd_setup_send(rhport, daddr, setup_packet);
|
|
||||||
if (!ret) {
|
|
||||||
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO timeout_ms is not supported yet
|
// TODO timeout_ms is not supported yet
|
||||||
bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
||||||
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet
|
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet
|
||||||
@@ -1263,28 +1278,13 @@ uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_i
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Detaching
|
// Detaching
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) {
|
|
||||||
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
// a device unplugged from rhport:hub_addr:hub_port
|
// a device unplugged from rhport:hub_addr:hub_port
|
||||||
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
|
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
|
||||||
// if dev0 is unplugged while enumerating (not yet assigned an address)
|
// Find the all devices (star-network) under port that is unplugged
|
||||||
if (_usbh_data.enumerating_daddr == 0) {
|
#if CFG_TUH_HUB
|
||||||
const tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus;
|
uint8_t removing_hubs[CFG_TUH_HUB] = { 0 };
|
||||||
if ((rhport == dev0_bus->rhport) && (hub_addr == dev0_bus->hub_addr) && (hub_port == dev0_bus->hub_port)) {
|
#endif
|
||||||
hcd_device_close(dev0_bus->rhport, 0);
|
|
||||||
if (_usbh_data.ctrl_xfer_info.daddr == 0) {
|
|
||||||
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
|
|
||||||
}
|
|
||||||
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------- find the all devices (star-network) under port that is unplugged -------------//
|
|
||||||
uint32_t removing_hubs = 0;
|
|
||||||
do {
|
do {
|
||||||
for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
|
for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_id];
|
usbh_device_t* dev = &_usbh_devices[dev_id];
|
||||||
@@ -1296,10 +1296,13 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
|
|||||||
(hub_port == 0 || dev->bus_info.hub_port == hub_port)) {
|
(hub_port == 0 || dev->bus_info.hub_port == hub_port)) {
|
||||||
TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr);
|
TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr);
|
||||||
|
|
||||||
|
#if CFG_TUH_HUB
|
||||||
if (is_hub_addr(daddr)) {
|
if (is_hub_addr(daddr)) {
|
||||||
TU_LOG_USBH(" is a HUB device %u\r\n", daddr);
|
TU_LOG_USBH(" is a HUB device %u\r\n", daddr);
|
||||||
removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
|
removing_hubs[dev_id - CFG_TUH_DEVICE_MAX] = 1;
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
// Invoke callback before closing driver (maybe call it later ?)
|
// Invoke callback before closing driver (maybe call it later ?)
|
||||||
if (tuh_umount_cb) {
|
if (tuh_umount_cb) {
|
||||||
tuh_umount_cb(daddr);
|
tuh_umount_cb(daddr);
|
||||||
@@ -1314,30 +1317,21 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hcd_device_close(rhport, daddr);
|
usbh_device_close(rhport, daddr);
|
||||||
clear_device(dev);
|
clear_device(dev);
|
||||||
|
|
||||||
// abort ongoing control xfer on this device if any
|
|
||||||
if (daddr == _usbh_data.ctrl_xfer_info.daddr) {
|
|
||||||
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (daddr == _usbh_data.enumerating_daddr) {
|
|
||||||
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if removing a hub, we need to remove all of its downstream devices
|
#if CFG_TUH_HUB
|
||||||
#if CFG_TUH_HUB
|
// if a hub is removed, we need to remove all of its downstream devices
|
||||||
if (removing_hubs == 0) {
|
if (tu_mem_is_zero(removing_hubs, CFG_TUH_HUB)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find a marked hub to process
|
// find a marked hub to process
|
||||||
for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) {
|
for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) {
|
||||||
if (tu_bit_test(removing_hubs, h_id)) {
|
if (removing_hubs[h_id]) {
|
||||||
removing_hubs &= ~TU_BIT(h_id);
|
removing_hubs[h_id] = 0;
|
||||||
|
|
||||||
// update hub_addr and hub_port for next loop
|
// update hub_addr and hub_port for next loop
|
||||||
hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX;
|
hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX;
|
||||||
@@ -1345,10 +1339,10 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void) removing_hubs;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} while(1);
|
} while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1560,6 +1554,10 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ENUM_SET_ADDR: {
|
case ENUM_SET_ADDR: {
|
||||||
|
// Due to physical debouncing, some devices can cause multiple attaches (actually reset) without detach event
|
||||||
|
// Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
|
||||||
|
process_removed_device(dev0_bus->rhport, dev0_bus->hub_addr, dev0_bus->hub_port);
|
||||||
|
|
||||||
const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl;
|
const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl;
|
||||||
const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
|
const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
|
||||||
TU_ASSERT(new_addr != 0,);
|
TU_ASSERT(new_addr != 0,);
|
||||||
@@ -1582,7 +1580,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||||||
new_dev->addressed = 1;
|
new_dev->addressed = 1;
|
||||||
_usbh_data.enumerating_daddr = new_addr;
|
_usbh_data.enumerating_daddr = new_addr;
|
||||||
|
|
||||||
hcd_device_close(dev0_bus->rhport, 0); // close dev0
|
usbh_device_close(dev0_bus->rhport, 0); // close dev0
|
||||||
|
|
||||||
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint
|
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user