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:
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* USB Gadget HID driver for Tegra X1
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -80,6 +80,8 @@ enum {
|
|||||||
static jc_cal_t jc_cal_ctx;
|
static jc_cal_t jc_cal_ctx;
|
||||||
static usb_ops_t usb_ops;
|
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)
|
static bool _jc_calibration(const jc_gamepad_rpt_t *jc_pad)
|
||||||
{
|
{
|
||||||
// Calibrate left stick.
|
// 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)
|
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)
|
if (status == USB_ERROR_XFER_ERROR)
|
||||||
{
|
{
|
||||||
usbs->set_text(usbs->label, "#FFDD00 Error:# EP IN transfer!");
|
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)
|
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)
|
if (res == INPUT_POLL_EXIT)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Send HID report.
|
// 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)))
|
if (_hid_transfer_start(usbs, sizeof(gamepad_report_t)))
|
||||||
return true; // EP Error.
|
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)
|
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.
|
// Send HID report.
|
||||||
if (_hid_transfer_start(usbs, sizeof(touchpad_report_t)))
|
if (_hid_transfer_start(usbs, sizeof(touchpad_report_t)))
|
||||||
@@ -399,6 +401,10 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
|
|||||||
else
|
else
|
||||||
xusb_device_get_ops(&usb_ops);
|
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)
|
if (usbs->type == USB_HID_GAMEPAD)
|
||||||
{
|
{
|
||||||
polling_time = 15000;
|
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");
|
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;
|
goto error;
|
||||||
|
|
||||||
usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation");
|
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();
|
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.
|
// Parse input device.
|
||||||
if (usbs->type == USB_HID_GAMEPAD)
|
if (usbs->type == USB_HID_GAMEPAD)
|
||||||
{
|
{
|
||||||
@@ -448,13 +462,6 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
|
|||||||
break;
|
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.
|
// Wait max gadget timing.
|
||||||
timer = get_tmr_us() - timer;
|
timer = get_tmr_us() - timer;
|
||||||
if (timer < polling_time)
|
if (timer < polling_time)
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ static void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state)
|
|||||||
|
|
||||||
static void _handle_ep0_ctrl(usbd_gadget_ums_t *ums)
|
static void _handle_ep0_ctrl(usbd_gadget_ums_t *ums)
|
||||||
{
|
{
|
||||||
if (usb_ops.usbd_handle_ep0_ctrl_setup())
|
if (usb_ops.usbd_handle_ep0_ctrl_setup(NULL))
|
||||||
raise_exception(ums, UMS_STATE_PROTOCOL_RESET);
|
raise_exception(ums, UMS_STATE_PROTOCOL_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,11 @@ typedef struct _usbd_controller_t
|
|||||||
bool configuration_set;
|
bool configuration_set;
|
||||||
bool max_lun_set;
|
bool max_lun_set;
|
||||||
bool bulk_reset_req;
|
bool bulk_reset_req;
|
||||||
|
u32 intr_idle_rate;
|
||||||
|
bool intr_idle_req;
|
||||||
bool hid_report_sent;
|
bool hid_report_sent;
|
||||||
|
void *hid_rpt_buffer;
|
||||||
|
u32 hid_rpt_size;
|
||||||
u32 charger_detect;
|
u32 charger_detect;
|
||||||
} usbd_controller_t;
|
} usbd_controller_t;
|
||||||
|
|
||||||
@@ -889,9 +893,9 @@ static void _usbd_handle_get_class_request(bool *transmit_data, u8 *desc, int *s
|
|||||||
u16 _wLength = usbd_otg->control_setup.wLength;
|
u16 _wLength = usbd_otg->control_setup.wLength;
|
||||||
|
|
||||||
bool valid_interface = _wIndex == usbd_otg->interface_num;
|
bool valid_interface = _wIndex == usbd_otg->interface_num;
|
||||||
bool valid_len = (_bRequest == USB_REQUEST_BULK_GET_MAX_LUN) ? 1 : 0;
|
bool valid_val = (_bRequest >= USB_REQUEST_BULK_GET_MAX_LUN) ? (!_wValue) : true;
|
||||||
|
|
||||||
if (!valid_interface || _wValue != 0 || _wLength != valid_len)
|
if (!valid_interface || !valid_val)
|
||||||
{
|
{
|
||||||
*ep_stall = true;
|
*ep_stall = true;
|
||||||
return;
|
return;
|
||||||
@@ -899,20 +903,48 @@ static void _usbd_handle_get_class_request(bool *transmit_data, u8 *desc, int *s
|
|||||||
|
|
||||||
switch (_bRequest)
|
switch (_bRequest)
|
||||||
{
|
{
|
||||||
|
case USB_REQUEST_INTR_GET_REPORT:
|
||||||
|
if (usbd_otg->hid_rpt_size != _wLength)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// _wValue unused as there's only one report type and id.
|
||||||
|
*transmit_data = true;
|
||||||
|
*size = usbd_otg->hid_rpt_size;
|
||||||
|
memcpy(desc, usbd_otg->hid_rpt_buffer, usbd_otg->hid_rpt_size);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case USB_REQUEST_INTR_SET_IDLE:
|
||||||
|
if (_wLength)
|
||||||
|
break;
|
||||||
|
|
||||||
|
usbd_otg->intr_idle_rate = (_wValue & 0xFF) * 4 * 1000; // Only one interface so upper byte ignored.
|
||||||
|
usbd_otg->intr_idle_req = true;
|
||||||
|
_usbd_ep_ack(USB_EP_CTRL_IN);
|
||||||
|
return; // DELAYED_STATUS;
|
||||||
|
|
||||||
case USB_REQUEST_BULK_RESET:
|
case USB_REQUEST_BULK_RESET:
|
||||||
|
if (_wLength)
|
||||||
|
break;
|
||||||
|
|
||||||
_usbd_ep_ack(USB_EP_CTRL_IN);
|
_usbd_ep_ack(USB_EP_CTRL_IN);
|
||||||
usbd_otg->bulk_reset_req = true;
|
usbd_otg->bulk_reset_req = true;
|
||||||
break; // DELAYED_STATUS;
|
return; // DELAYED_STATUS;
|
||||||
|
|
||||||
case USB_REQUEST_BULK_GET_MAX_LUN:
|
case USB_REQUEST_BULK_GET_MAX_LUN:
|
||||||
|
if (_wLength != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
*transmit_data = true;
|
*transmit_data = true;
|
||||||
*size = 1;
|
*size = 1;
|
||||||
desc[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported.
|
desc[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported.
|
||||||
usbd_otg->max_lun_set = true;
|
usbd_otg->max_lun_set = true;
|
||||||
break;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
*ep_stall = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ep_stall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _usbd_handle_get_descriptor(bool *transmit_data, void **desc, int *size, bool *ep_stall)
|
static void _usbd_handle_get_descriptor(bool *transmit_data, void **desc, int *size, bool *ep_stall)
|
||||||
@@ -1395,7 +1427,7 @@ int usb_device_enumerate(usb_gadget_type gadget)
|
|||||||
return _usbd_ep0_initialize();
|
return _usbd_ep0_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int usbd_handle_ep0_ctrl_setup()
|
int usbd_handle_ep0_ctrl_setup(u32 *data)
|
||||||
{
|
{
|
||||||
// Acknowledge setup request for EP0 and copy its configuration.
|
// Acknowledge setup request for EP0 and copy its configuration.
|
||||||
u32 ep0_setup_req = usbd_otg->regs->endptsetupstat;
|
u32 ep0_setup_req = usbd_otg->regs->endptsetupstat;
|
||||||
@@ -1407,6 +1439,15 @@ int usbd_handle_ep0_ctrl_setup()
|
|||||||
memset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE);
|
memset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usbd_otg->intr_idle_req)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
*data = usbd_otg->intr_idle_rate;
|
||||||
|
|
||||||
|
usbd_otg->intr_idle_req = false;
|
||||||
|
return USB_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Only return error if bulk reset was requested.
|
// Only return error if bulk reset was requested.
|
||||||
if (usbd_otg->bulk_reset_req)
|
if (usbd_otg->bulk_reset_req)
|
||||||
{
|
{
|
||||||
@@ -1489,7 +1530,7 @@ int usb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_timeout)
|
|||||||
if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED))
|
if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
usbd_handle_ep0_ctrl_setup();
|
usbd_handle_ep0_ctrl_setup(NULL);
|
||||||
}
|
}
|
||||||
while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED));
|
while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED));
|
||||||
|
|
||||||
@@ -1538,7 +1579,7 @@ int usb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_timeout)
|
|||||||
if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED))
|
if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
usbd_handle_ep0_ctrl_setup();
|
usbd_handle_ep0_ctrl_setup(NULL);
|
||||||
}
|
}
|
||||||
while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED));
|
while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED));
|
||||||
|
|
||||||
@@ -1574,7 +1615,7 @@ int usb_device_class_send_max_lun(u8 max_lun)
|
|||||||
|
|
||||||
while (!usbd_otg->max_lun_set)
|
while (!usbd_otg->max_lun_set)
|
||||||
{
|
{
|
||||||
usbd_handle_ep0_ctrl_setup();
|
usbd_handle_ep0_ctrl_setup(NULL);
|
||||||
if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
|
if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
|
||||||
return USB_ERROR_USER_ABORT;
|
return USB_ERROR_USER_ABORT;
|
||||||
}
|
}
|
||||||
@@ -1582,15 +1623,19 @@ int usb_device_class_send_max_lun(u8 max_lun)
|
|||||||
return USB_RES_OK;
|
return USB_RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_device_class_send_hid_report()
|
int usb_device_class_send_hid_report(void *rpt_buffer, u32 rpt_size)
|
||||||
{
|
{
|
||||||
|
// Set buffers.
|
||||||
|
usbd_otg->hid_rpt_buffer = rpt_buffer;
|
||||||
|
usbd_otg->hid_rpt_size = rpt_size;
|
||||||
|
|
||||||
// Timeout if get GET_HID_REPORT request doesn't happen in 10s.
|
// Timeout if get GET_HID_REPORT request doesn't happen in 10s.
|
||||||
u32 timer = get_tmr_ms() + 10000;
|
u32 timer = get_tmr_ms() + 10000;
|
||||||
|
|
||||||
// Wait for request and transfer start.
|
// Wait for request and transfer start.
|
||||||
while (!usbd_otg->hid_report_sent)
|
while (!usbd_otg->hid_report_sent)
|
||||||
{
|
{
|
||||||
usbd_handle_ep0_ctrl_setup();
|
usbd_handle_ep0_ctrl_setup(NULL);
|
||||||
if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
|
if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
|
||||||
return USB_ERROR_USER_ABORT;
|
return USB_ERROR_USER_ABORT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Enhanced & eXtensible USB Device (EDCI & XDCI) driver for Tegra X1
|
* Enhanced & eXtensible USB Device (EDCI & XDCI) driver for Tegra X1
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 CTCaer
|
* Copyright (c) 2019-2025 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -31,11 +31,11 @@
|
|||||||
#define USB_EP_BUFFER_ALIGN (USB_TD_BUFFER_PAGE_SIZE)
|
#define USB_EP_BUFFER_ALIGN (USB_TD_BUFFER_PAGE_SIZE)
|
||||||
|
|
||||||
#define USB_XFER_START 0
|
#define USB_XFER_START 0
|
||||||
#define USB_XFER_SYNCED_ENUM 1000000
|
#define USB_XFER_SYNCED_ENUM 1000000 // ~2s.
|
||||||
#define USB_XFER_SYNCED_CMD 1000000
|
#define USB_XFER_SYNCED_CMD 1000000 // ~2s.
|
||||||
#define USB_XFER_SYNCED_DATA 2000000
|
#define USB_XFER_SYNCED_DATA 2000000 // ~4s.
|
||||||
#define USB_XFER_SYNCED_CLASS 5000000
|
#define USB_XFER_SYNCED_CLASS 5000000 // ~10s.
|
||||||
#define USB_XFER_SYNCED -1
|
#define USB_XFER_SYNCED -1 // Max.
|
||||||
|
|
||||||
typedef enum _usb_hid_type
|
typedef enum _usb_hid_type
|
||||||
{
|
{
|
||||||
@@ -122,6 +122,9 @@ typedef enum {
|
|||||||
|
|
||||||
USB_REQUEST_GET_MS_DESCRIPTOR = 0x99,
|
USB_REQUEST_GET_MS_DESCRIPTOR = 0x99,
|
||||||
|
|
||||||
|
USB_REQUEST_INTR_GET_REPORT = 1,
|
||||||
|
USB_REQUEST_INTR_SET_IDLE = 10,
|
||||||
|
|
||||||
USB_REQUEST_BULK_GET_MAX_LUN = 0xFE,
|
USB_REQUEST_BULK_GET_MAX_LUN = 0xFE,
|
||||||
USB_REQUEST_BULK_RESET = 0xFF
|
USB_REQUEST_BULK_RESET = 0xFF
|
||||||
} usb_standard_req_t;
|
} usb_standard_req_t;
|
||||||
@@ -167,12 +170,13 @@ typedef struct _usb_ops_t
|
|||||||
{
|
{
|
||||||
int (*usbd_flush_endpoint)(u32);
|
int (*usbd_flush_endpoint)(u32);
|
||||||
int (*usbd_set_ep_stall)(u32, int);
|
int (*usbd_set_ep_stall)(u32, int);
|
||||||
int (*usbd_handle_ep0_ctrl_setup)();
|
int (*usbd_handle_ep0_ctrl_setup)(u32 *);
|
||||||
void (*usbd_end)(bool, bool);
|
void (*usbd_end)(bool, bool);
|
||||||
int (*usb_device_init)();
|
int (*usb_device_init)();
|
||||||
int (*usb_device_enumerate)(usb_gadget_type gadget);
|
int (*usb_device_enumerate)(usb_gadget_type);
|
||||||
|
|
||||||
int (*usb_device_class_send_max_lun)(u8);
|
int (*usb_device_class_send_max_lun)(u8);
|
||||||
int (*usb_device_class_send_hid_report)();
|
int (*usb_device_class_send_hid_report)(void *, u32);
|
||||||
|
|
||||||
int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, u32);
|
int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, u32);
|
||||||
int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *);
|
int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *);
|
||||||
@@ -186,10 +190,17 @@ typedef struct _usb_ops_t
|
|||||||
typedef struct _usb_ctxt_t
|
typedef struct _usb_ctxt_t
|
||||||
{
|
{
|
||||||
u32 type;
|
u32 type;
|
||||||
|
|
||||||
|
// UMS.
|
||||||
u32 partition;
|
u32 partition;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u32 sectors;
|
u32 sectors;
|
||||||
u32 ro;
|
u32 ro;
|
||||||
|
|
||||||
|
// HID.
|
||||||
|
u32 idle;
|
||||||
|
|
||||||
|
// System.
|
||||||
void (*system_maintenance)(bool);
|
void (*system_maintenance)(bool);
|
||||||
void *label;
|
void *label;
|
||||||
void (*set_text)(void *, const char *);
|
void (*set_text)(void *, const char *);
|
||||||
@@ -201,4 +212,4 @@ void xusb_device_get_ops(usb_ops_t *ops);
|
|||||||
int usb_device_gadget_ums(usb_ctxt_t *usbs);
|
int usb_device_gadget_ums(usb_ctxt_t *usbs);
|
||||||
int usb_device_gadget_hid(usb_ctxt_t *usbs);
|
int usb_device_gadget_hid(usb_ctxt_t *usbs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -381,6 +381,10 @@ typedef struct _xusbd_controller_t
|
|||||||
|
|
||||||
u8 max_lun;
|
u8 max_lun;
|
||||||
bool max_lun_set;
|
bool max_lun_set;
|
||||||
|
void *hid_rpt_buffer;
|
||||||
|
u32 hid_rpt_size;
|
||||||
|
u32 intr_idle_rate;
|
||||||
|
bool intr_idle_req;
|
||||||
bool bulk_reset_req;
|
bool bulk_reset_req;
|
||||||
} xusbd_controller_t;
|
} xusbd_controller_t;
|
||||||
|
|
||||||
@@ -1469,20 +1473,39 @@ static int _xusb_handle_get_class_request(const usb_ctrl_setup_t *ctrl_setup)
|
|||||||
u16 _wLength = ctrl_setup->wLength;
|
u16 _wLength = ctrl_setup->wLength;
|
||||||
|
|
||||||
bool valid_interface = _wIndex == usbd_xotg->interface_num;
|
bool valid_interface = _wIndex == usbd_xotg->interface_num;
|
||||||
bool valid_len = (_bRequest == USB_REQUEST_BULK_GET_MAX_LUN) ? 1 : 0;
|
bool valid_val = (_bRequest >= USB_REQUEST_BULK_GET_MAX_LUN) ? (!_wValue) : true;
|
||||||
|
|
||||||
if (!valid_interface || _wValue != 0 || _wLength != valid_len)
|
if (!valid_interface || !valid_val)
|
||||||
goto stall;
|
goto stall;
|
||||||
|
|
||||||
switch (_bRequest)
|
switch (_bRequest)
|
||||||
{
|
{
|
||||||
|
case USB_REQUEST_INTR_GET_REPORT:
|
||||||
|
if (usbd_xotg->hid_rpt_size != _wLength)
|
||||||
|
goto stall;
|
||||||
|
|
||||||
|
// _wValue unused as there's only one report type and id.
|
||||||
|
return _xusb_issue_data_trb(usbd_xotg->hid_rpt_buffer, usbd_xotg->hid_rpt_size, USB_DIR_IN);
|
||||||
|
|
||||||
|
case USB_REQUEST_INTR_SET_IDLE:
|
||||||
|
if (_wLength)
|
||||||
|
goto stall;
|
||||||
|
|
||||||
|
usbd_xotg->intr_idle_rate = (_wValue & 0xFF) * 4 * 1000; // Only one interface so upper byte ignored.
|
||||||
|
usbd_xotg->intr_idle_req = true;
|
||||||
|
return _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS;
|
||||||
|
|
||||||
case USB_REQUEST_BULK_RESET:
|
case USB_REQUEST_BULK_RESET:
|
||||||
|
if (_wLength)
|
||||||
|
goto stall;
|
||||||
|
|
||||||
usbd_xotg->bulk_reset_req = true;
|
usbd_xotg->bulk_reset_req = true;
|
||||||
return _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS;
|
return _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS;
|
||||||
|
|
||||||
case USB_REQUEST_BULK_GET_MAX_LUN:
|
case USB_REQUEST_BULK_GET_MAX_LUN:
|
||||||
if (!usbd_xotg->max_lun_set)
|
if (_wLength != 1 || !usbd_xotg->max_lun_set)
|
||||||
goto stall;
|
goto stall;
|
||||||
|
|
||||||
usbd_xotg->device_state = XUSB_LUN_CONFIGURED_STS_WAIT;
|
usbd_xotg->device_state = XUSB_LUN_CONFIGURED_STS_WAIT;
|
||||||
return _xusb_issue_data_trb(&usbd_xotg->max_lun, 1, USB_DIR_IN);
|
return _xusb_issue_data_trb(&usbd_xotg->max_lun, 1, USB_DIR_IN);
|
||||||
}
|
}
|
||||||
@@ -2019,12 +2042,24 @@ void xusb_end(bool reset_ep, bool only_controller)
|
|||||||
_xusb_device_power_down();
|
_xusb_device_power_down();
|
||||||
}
|
}
|
||||||
|
|
||||||
int xusb_handle_ep0_ctrl_setup()
|
int xusb_handle_ep0_ctrl_setup(u32 *data)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* EP0 Control handling is done by normal ep operation in XUSB.
|
* EP0 Control handling is done by normal ep operation in XUSB.
|
||||||
* Here we handle the bulk reset only.
|
* Here we handle the interface only, except if HID.
|
||||||
*/
|
*/
|
||||||
|
if (usbd_xotg->gadget >= USB_GADGET_HID_GAMEPAD)
|
||||||
|
_xusb_ep_operation(1);
|
||||||
|
|
||||||
|
if (usbd_xotg->intr_idle_req)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
*data = usbd_xotg->intr_idle_rate;
|
||||||
|
|
||||||
|
usbd_xotg->intr_idle_req = false;
|
||||||
|
return USB_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (usbd_xotg->bulk_reset_req)
|
if (usbd_xotg->bulk_reset_req)
|
||||||
{
|
{
|
||||||
usbd_xotg->bulk_reset_req = false;
|
usbd_xotg->bulk_reset_req = false;
|
||||||
@@ -2178,8 +2213,12 @@ bool xusb_device_class_send_max_lun(u8 max_lun)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xusb_device_class_send_hid_report()
|
bool xusb_device_class_send_hid_report(void *rpt_buffer, u32 rpt_size)
|
||||||
{
|
{
|
||||||
|
// Set buffers.
|
||||||
|
usbd_xotg->hid_rpt_buffer = rpt_buffer;
|
||||||
|
usbd_xotg->hid_rpt_size = rpt_size;
|
||||||
|
|
||||||
// Timeout if get GET_HID_REPORT request doesn't happen in 10s.
|
// Timeout if get GET_HID_REPORT request doesn't happen in 10s.
|
||||||
u32 timer = get_tmr_ms() + 10000;
|
u32 timer = get_tmr_ms() + 10000;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user