bdk: usb: revamp hid logic

- Add support for GET REPORT. Allows OS to get a single input report.
- Add support for SET_IDLE. Allows OS to control when to send input reports

The SET IDLE and the underlying logic change fixes several things:
- The old issue of congestion in some systems.
- The new bug that would not allow setup packets to be received because mode
 was set to only send when there are changes.
- Now this starts properly as the old code but allows to be changed by OS on
 demand, while continuing servicing setup packets.
This commit is contained in:
CTCaer
2025-06-22 13:24:47 +03:00
parent e1ea05d53a
commit 40b05ea5ea
5 changed files with 143 additions and 41 deletions

View File

@@ -1,7 +1,7 @@
/*
* USB Gadget HID driver for Tegra X1
*
* Copyright (c) 2019-2022 CTCaer
* Copyright (c) 2019-2025 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -80,6 +80,8 @@ enum {
static jc_cal_t jc_cal_ctx;
static usb_ops_t usb_ops;
static void *rpt_buffer = (u8 *)USB_EP_BULK_IN_BUF_ADDR;
static bool _jc_calibration(const jc_gamepad_rpt_t *jc_pad)
{
// Calibrate left stick.
@@ -347,7 +349,7 @@ static bool _fts_touch_read(touchpad_report_t *rpt)
static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len)
{
u8 status = usb_ops.usb_device_ep1_in_write((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, USB_XFER_SYNCED_CMD);
u8 status = usb_ops.usb_device_ep1_in_write(rpt_buffer, len, NULL, USB_XFER_SYNCED_CMD);
if (status == USB_ERROR_XFER_ERROR)
{
usbs->set_text(usbs->label, "#FFDD00 Error:# EP IN transfer!");
@@ -364,12 +366,12 @@ static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len)
static bool _hid_poll_jc(usb_ctxt_t *usbs)
{
int res = _jc_poll((gamepad_report_t *)USB_EP_BULK_IN_BUF_ADDR);
int res = _jc_poll(rpt_buffer);
if (res == INPUT_POLL_EXIT)
return true;
// Send HID report.
if (res == INPUT_POLL_HAS_PACKET)
if (res == INPUT_POLL_HAS_PACKET || usbs->idle)
if (_hid_transfer_start(usbs, sizeof(gamepad_report_t)))
return true; // EP Error.
@@ -378,7 +380,7 @@ static bool _hid_poll_jc(usb_ctxt_t *usbs)
static bool _hid_poll_touch(usb_ctxt_t *usbs)
{
_fts_touch_read((touchpad_report_t *)USB_EP_BULK_IN_BUF_ADDR);
_fts_touch_read(rpt_buffer);
// Send HID report.
if (_hid_transfer_start(usbs, sizeof(touchpad_report_t)))
@@ -399,6 +401,10 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
else
xusb_device_get_ops(&usb_ops);
// Always push packets by default.
//! TODO: For now only per polling rate or on change is supported.
usbs->idle = 1;
if (usbs->type == USB_HID_GAMEPAD)
{
polling_time = 15000;
@@ -426,7 +432,8 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for HID report request");
if (usb_ops.usb_device_class_send_hid_report())
u32 rpt_size = usbs->type == USB_HID_GAMEPAD ? sizeof(gamepad_report_t) : sizeof(touchpad_report_t);
if (usb_ops.usb_device_class_send_hid_report(rpt_buffer, rpt_size))
goto error;
usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation");
@@ -436,6 +443,13 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
{
u32 timer = get_tmr_us();
// Check for suspended USB in case the cable was pulled.
if (usb_ops.usb_device_get_suspended())
break; // Disconnected.
// Handle control endpoint.
usb_ops.usbd_handle_ep0_ctrl_setup(&usbs->idle);
// Parse input device.
if (usbs->type == USB_HID_GAMEPAD)
{
@@ -448,13 +462,6 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
break;
}
// Check for suspended USB in case the cable was pulled.
if (usb_ops.usb_device_get_suspended())
break; // Disconnected.
// Handle control endpoint.
usb_ops.usbd_handle_ep0_ctrl_setup();
// Wait max gadget timing.
timer = get_tmr_us() - timer;
if (timer < polling_time)