1
0
Fork 0
mirror of https://github.com/CTCaer/hekate.git synced 2024-11-26 19:52:11 +00:00

usb: Rfactor driver/gadgets in prep for XUSB

Allow gadgets using different USB controllers on demand.
This will allow plugging in XUSB for Mariko usage.
This commit is contained in:
CTCaer 2020-11-15 14:30:25 +02:00
parent a84f1e5ee5
commit c7fcea5f35
6 changed files with 313 additions and 260 deletions

View file

@ -19,7 +19,7 @@
#include <usb/usb_descriptor_types.h> #include <usb/usb_descriptor_types.h>
#include <utils/types.h> #include <utils/types.h>
usb_dev_descr_t usb_device_descriptor_ums = static usb_dev_descr_t usb_device_descriptor_ums =
{ {
.bLength = 18, .bLength = 18,
.bDescriptorType = USB_DESCRIPTOR_DEVICE, .bDescriptorType = USB_DESCRIPTOR_DEVICE,
@ -37,7 +37,7 @@ usb_dev_descr_t usb_device_descriptor_ums =
.bNumConfigs = 1 .bNumConfigs = 1
}; };
usb_dev_qual_descr_t usb_device_qualifier_descriptor = static usb_dev_qual_descr_t usb_device_qualifier_descriptor =
{ {
.bLength = 10, .bLength = 10,
.bDescriptorType = USB_DESCRIPTOR_DEVICE_QUALIFIER, .bDescriptorType = USB_DESCRIPTOR_DEVICE_QUALIFIER,
@ -50,7 +50,7 @@ usb_dev_qual_descr_t usb_device_qualifier_descriptor =
.bReserved = 0x00 .bReserved = 0x00
}; };
usb_cfg_simple_descr_t usb_configuration_descriptor_ums = static usb_cfg_simple_descr_t usb_configuration_descriptor_ums =
{ {
/* Configuration descriptor structure */ /* Configuration descriptor structure */
.config.bLength = 9, .config.bLength = 9,
@ -90,7 +90,7 @@ usb_cfg_simple_descr_t usb_configuration_descriptor_ums =
.endpoint[1].bInterval = 0x00 .endpoint[1].bInterval = 0x00
}; };
usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = static usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums =
{ {
/* Other Speed Configuration descriptor structure */ /* Other Speed Configuration descriptor structure */
.config.bLength = 9, .config.bLength = 9,
@ -130,7 +130,7 @@ usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums =
.endpoint[1].bInterval = 0 .endpoint[1].bInterval = 0
}; };
usb_dev_bot_t usb_device_binary_object_descriptor = static usb_dev_bot_t usb_device_binary_object_descriptor =
{ {
.bLength = 5, .bLength = 5,
.bDescriptorType = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT, .bDescriptorType = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT,
@ -155,33 +155,33 @@ usb_dev_bot_t usb_device_binary_object_descriptor =
.wU2DevExitLat = 0 .wU2DevExitLat = 0
}; };
u8 usb_lang_id_string_descriptor[4] = static u8 usb_lang_id_string_descriptor[4] =
{ {
4, 3, 4, 3,
0x09, 0x04 0x09, 0x04
}; };
u8 usb_serial_string_descriptor[26] = static u8 usb_serial_string_descriptor[26] =
{ {
26, 0x03, 26, 0x03,
'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00, 'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00,
'9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00 '9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00
}; };
u8 usb_vendor_string_descriptor_ums[32] = static u8 usb_vendor_string_descriptor_ums[32] =
{ {
26, 0x03, 26, 0x03,
'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0, 'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0,
'D', 0, 'i', 0, 's', 0, 'k', 0 'D', 0, 'i', 0, 's', 0, 'k', 0
}; };
u8 usb_product_string_descriptor_ums[22] = static u8 usb_product_string_descriptor_ums[22] =
{ {
8, 0x03, 8, 0x03,
'U', 0, 'M', 0, 'S', 0 'U', 0, 'M', 0, 'S', 0
}; };
usb_ms_os_descr_t usb_ms_os_descriptor = static usb_ms_os_descr_t usb_ms_os_descriptor =
{ {
.bLength = 0x28, .bLength = 0x28,
.bDescriptorType = 0x03, .bDescriptorType = 0x03,
@ -195,7 +195,7 @@ usb_ms_os_descr_t usb_ms_os_descriptor =
.bVendorCode = 0x99, .bVendorCode = 0x99,
}; };
usb_ms_cid_descr_t usb_ms_cid_descriptor = static usb_ms_cid_descr_t usb_ms_cid_descriptor =
{ {
.dLength = 0x28, .dLength = 0x28,
.wVersion = 0x100, .wVersion = 0x100,
@ -212,7 +212,7 @@ usb_ms_cid_descr_t usb_ms_cid_descriptor =
.bCompatibleId[5] = 'B', .bCompatibleId[5] = 'B',
}; };
usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = static usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums =
{ {
.dLength = 0x48, .dLength = 0x48,
.wVersion = 0x100, .wVersion = 0x100,
@ -251,7 +251,7 @@ usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums =
.wPropertyData[1] = 0x10, .wPropertyData[1] = 0x10,
}; };
usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = static usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid =
{ {
.dLength = 7, .dLength = 7,
.wVersion = 0x100, .wVersion = 0x100,
@ -259,7 +259,7 @@ usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid =
.wSections = 0, .wSections = 0,
}; };
usb_dev_descr_t usb_device_descriptor_hid_jc = static usb_dev_descr_t usb_device_descriptor_hid_jc =
{ {
.bLength = 18, .bLength = 18,
.bDescriptorType = USB_DESCRIPTOR_DEVICE, .bDescriptorType = USB_DESCRIPTOR_DEVICE,
@ -277,7 +277,7 @@ usb_dev_descr_t usb_device_descriptor_hid_jc =
.bNumConfigs = 1 .bNumConfigs = 1
}; };
usb_dev_descr_t usb_device_descriptor_hid_touch = static usb_dev_descr_t usb_device_descriptor_hid_touch =
{ {
.bLength = 18, .bLength = 18,
.bDescriptorType = USB_DESCRIPTOR_DEVICE, .bDescriptorType = USB_DESCRIPTOR_DEVICE,
@ -332,6 +332,8 @@ u8 hid_report_descriptor_jc[] =
0xc0 // END_COLLECTION(), 0xc0 // END_COLLECTION(),
}; };
u32 hid_report_descriptor_jc_size = sizeof(hid_report_descriptor_jc);
u8 hid_report_descriptor_touch[] = u8 hid_report_descriptor_touch[] =
{ {
0x05, 0x0d, // USAGE_PAGE (Digitizers) 0x05, 0x0d, // USAGE_PAGE (Digitizers)
@ -388,6 +390,7 @@ u8 hid_report_descriptor_touch[] =
0xc0, // END_COLLECTION 0xc0, // END_COLLECTION
0xc0, // END_COLLECTION 0xc0, // END_COLLECTION
}; };
u32 hid_report_descriptor_touch_size = sizeof(hid_report_descriptor_touch);
static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc = static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc =
{ {
@ -418,7 +421,7 @@ static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc =
.hid.bCountryCode = 0, .hid.bCountryCode = 0,
.hid.bNumDescriptors = 1, .hid.bNumDescriptors = 1,
.hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT,
.hid.bDescriptorLength = 0x43, .hid.bDescriptorLength = sizeof(hid_report_descriptor_jc),
/* Endpoint descriptor structure EP1 IN */ /* Endpoint descriptor structure EP1 IN */
.endpoint[0].bLength = 7, .endpoint[0].bLength = 7,
@ -437,28 +440,28 @@ static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc =
.endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS.
}; };
u8 usb_vendor_string_descriptor_hid[22] = static u8 usb_vendor_string_descriptor_hid[22] =
{ {
16, 0x03, 16, 0x03,
'N', 0, 'y', 0, 'x', 0, ' ', 0, 'N', 0, 'y', 0, 'x', 0, ' ', 0,
'U', 0, 'S', 0, 'B', 0 'U', 0, 'S', 0, 'B', 0
}; };
u8 usb_product_string_descriptor_hid_jc[24] = static u8 usb_product_string_descriptor_hid_jc[24] =
{ {
24, 0x03, 24, 0x03,
'N', 0, 'y', 0, 'x', 0, ' ', 0, 'N', 0, 'y', 0, 'x', 0, ' ', 0,
'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0 'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0
}; };
u8 usb_product_string_descriptor_hid_touch[26] = static u8 usb_product_string_descriptor_hid_touch[26] =
{ {
26, 0x03, 26, 0x03,
'N', 0, 'y', 0, 'x', 0, ' ', 0, 'N', 0, 'y', 0, 'x', 0, ' ', 0,
'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0 'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0
}; };
usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = static usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch =
{ {
/* Configuration descriptor structure */ /* Configuration descriptor structure */
.config.bLength = 9, .config.bLength = 9,

View file

@ -67,6 +67,7 @@ typedef struct _jc_cal_t
} jc_cal_t; } jc_cal_t;
static jc_cal_t jc_cal_ctx; static jc_cal_t jc_cal_ctx;
static usb_ops_t usb_ops;
static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad) static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad)
{ {
@ -306,12 +307,12 @@ 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_device_write_ep1_in((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, true); u8 status = usb_ops.usb_device_ep1_in_write((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, USB_XFER_SYNCED);
if (status == 26) if (status == 26)
{ {
usbs->set_text(usbs->label, "#C7EA46 Status:# Error EP IN"); usbs->set_text(usbs->label, "#C7EA46 Status:# Error EP IN");
usbd_flush_endpoint(3); if (usb_ops.usbd_flush_endpoint)
usb_ops.usbd_flush_endpoint(USB_EP_BULK_IN);
} }
// Linux mitigation: If timed out, clear status. // Linux mitigation: If timed out, clear status.
@ -350,6 +351,8 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
u32 gadget_type; u32 gadget_type;
u32 polling_time; u32 polling_time;
// Get USB Controller ops.
usb_device_get_ops(&usb_ops);
if (usbs->type == USB_HID_GAMEPAD) if (usbs->type == USB_HID_GAMEPAD)
{ {
polling_time = 8000; polling_time = 8000;
@ -363,21 +366,21 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB");
if (usb_device_init()) if (usb_ops.usb_device_init())
{ {
usbd_end(false, true); usb_ops.usbd_end(false, true);
return 1; return 1;
} }
usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for connection"); usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for connection");
// Initialize Control Endpoint. // Initialize Control Endpoint.
if (usb_device_ep0_initialize(gadget_type)) if (usb_ops.usb_device_enumerate(gadget_type))
goto error; goto error;
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_device_get_hid_report()) if (usb_ops.usb_device_class_send_hid_report())
goto error; goto error;
usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation"); usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation");
@ -400,11 +403,11 @@ int usb_device_gadget_hid(usb_ctxt_t *usbs)
} }
// Check for suspended USB in case the cable was pulled. // Check for suspended USB in case the cable was pulled.
if (usb_device_get_suspended()) if (usb_ops.usb_device_get_suspended())
break; // Disconnected. break; // Disconnected.
// Handle control endpoint. // Handle control endpoint.
usbd_handle_ep0_pending_control_transfer(); 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;
@ -426,7 +429,7 @@ error:
res = 1; res = 1;
exit: exit:
usbd_end(true, false); usb_ops.usbd_end(true, false);
return res; return res;
} }

View file

@ -221,6 +221,8 @@ typedef struct _usbd_gadget_ums_t {
void (*set_text)(void *, const char *); void (*set_text)(void *, const char *);
} usbd_gadget_ums_t; } usbd_gadget_ums_t;
static usb_ops_t usb_ops;
static inline void put_array_le_to_be16(u16 val, void *p) static inline void put_array_le_to_be16(u16 val, void *p)
{ {
u8 *_p = p; u8 *_p = p;
@ -271,7 +273,7 @@ static void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state)
static void ums_handle_ep0_ctrl(usbd_gadget_ums_t *ums) static void ums_handle_ep0_ctrl(usbd_gadget_ums_t *ums)
{ {
if (usbd_handle_ep0_pending_control_transfer()) if (usb_ops.usbd_handle_ep0_ctrl_setup())
raise_exception(ums, UMS_STATE_PROTOCOL_RESET); raise_exception(ums, UMS_STATE_PROTOCOL_RESET);
} }
@ -284,30 +286,36 @@ static int ums_wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums)
static int ums_set_stall(u32 ep) static int ums_set_stall(u32 ep)
{ {
usbd_set_ep_stall(ep, 1); usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_STALL);
return 0; return 0;
} }
static int ums_clear_stall(u32 ep) static int ums_clear_stall(u32 ep)
{ {
usbd_set_ep_stall(ep, 0); usb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_CLEAR);
return 0; return 0;
} }
static void ums_flush_endpoint(u32 ep)
{
if (usb_ops.usbd_flush_endpoint)
usb_ops.usbd_flush_endpoint(ep);
}
static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, bool sync) static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, bool sync)
{ {
if (ep == bulk_ctxt->bulk_in) if (ep == bulk_ctxt->bulk_in)
{ {
bulk_ctxt->bulk_in_status = usb_device_write_ep1_in( bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_write(
bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length, bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length,
&bulk_ctxt->bulk_in_length_actual, sync); &bulk_ctxt->bulk_in_length_actual, sync);
if (bulk_ctxt->bulk_in_status == 26) if (bulk_ctxt->bulk_in_status == 26)
{ {
ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN");
usbd_flush_endpoint(bulk_ctxt->bulk_in); ums_flush_endpoint(bulk_ctxt->bulk_in);
} }
if (sync) if (sync)
@ -315,14 +323,14 @@ static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt,
} }
else else
{ {
bulk_ctxt->bulk_out_status = usb_device_read_ep1_out( bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read(
bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length,
&bulk_ctxt->bulk_out_length_actual, sync); &bulk_ctxt->bulk_out_length_actual, sync);
if (bulk_ctxt->bulk_out_status == 26) if (bulk_ctxt->bulk_out_status == 26)
{ {
ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT");
usbd_flush_endpoint(bulk_ctxt->bulk_out); ums_flush_endpoint(bulk_ctxt->bulk_out);
} }
if (sync) if (sync)
@ -332,14 +340,14 @@ static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt,
static void _ums_transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) static void _ums_transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
{ {
bulk_ctxt->bulk_out_status = usb_device_read_ep1_out_big_reads( bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read_big(
bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length,
&bulk_ctxt->bulk_out_length_actual); &bulk_ctxt->bulk_out_length_actual);
if (bulk_ctxt->bulk_out_status == 26) if (bulk_ctxt->bulk_out_status == 26)
{ {
ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT");
usbd_flush_endpoint(bulk_ctxt->bulk_out); ums_flush_endpoint(bulk_ctxt->bulk_out);
} }
bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL;
@ -349,24 +357,26 @@ static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt,
{ {
if (ep == bulk_ctxt->bulk_in) if (ep == bulk_ctxt->bulk_in)
{ {
bulk_ctxt->bulk_in_status = usb_device_ep1_in_writing_finish(&bulk_ctxt->bulk_in_length_actual); bulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_writing_finish(
&bulk_ctxt->bulk_in_length_actual);
if (bulk_ctxt->bulk_in_status == 26) if (bulk_ctxt->bulk_in_status == 26)
{ {
ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN");
usbd_flush_endpoint(bulk_ctxt->bulk_in); ums_flush_endpoint(bulk_ctxt->bulk_in);
} }
bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY;
} }
else else
{ {
bulk_ctxt->bulk_out_status = usb_device_ep1_out_reading_finish(&bulk_ctxt->bulk_out_length_actual); bulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_reading_finish(
&bulk_ctxt->bulk_out_length_actual, 1000000);
if (bulk_ctxt->bulk_out_status == 26) if (bulk_ctxt->bulk_out_status == 26)
{ {
ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT");
usbd_flush_endpoint(bulk_ctxt->bulk_out); ums_flush_endpoint(bulk_ctxt->bulk_out);
} }
bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL;
@ -497,7 +507,7 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
break; break;
// Start the USB transfer. // Start the USB transfer.
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, false); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_START);
first_read = false; first_read = false;
// Increment our buffer to read new data. // Increment our buffer to read new data.
@ -1382,7 +1392,7 @@ static int pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE);
memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep); memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep);
bulk_ctxt->bulk_in_length = nsend; bulk_ctxt->bulk_in_length = nsend;
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED);
ums->usb_amount_left -= nsend; ums->usb_amount_left -= nsend;
current_len_to_keep = 0; current_len_to_keep = 0;
} }
@ -1400,7 +1410,7 @@ static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE);
bulk_ctxt->bulk_out_length = amount; bulk_ctxt->bulk_out_length = amount;
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED);
ums->usb_amount_left -= amount; ums->usb_amount_left -= amount;
return 0; return 0;
@ -1447,7 +1457,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
// If there's no residue, simply send the last buffer. // If there's no residue, simply send the last buffer.
if (!ums->residue) if (!ums->residue)
{ {
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED);
/* For Bulk-only, if we're allowed to stall then send the /* For Bulk-only, if we're allowed to stall then send the
* short packet and halt the bulk-in endpoint. If we can't * short packet and halt the bulk-in endpoint. If we can't
@ -1455,7 +1465,7 @@ static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
} }
else if (ums->can_stall) else if (ums->can_stall)
{ {
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED);
rc = ums_set_stall(bulk_ctxt->bulk_in); rc = ums_set_stall(bulk_ctxt->bulk_in);
ums->set_text(ums->label, "#C7EA46 Status:# Residue. Stalled EP IN"); ums->set_text(ums->label, "#C7EA46 Status:# Residue. Stalled EP IN");
} }
@ -1528,7 +1538,7 @@ static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
{ {
if (bulk_ctxt->bulk_out_status == 3) if (bulk_ctxt->bulk_out_status == 3)
{ {
if (usb_device_get_port_status() == 0x885) if (usb_ops.usb_device_get_port_in_sleep())
{ {
ums->set_text(ums->label, "#C7EA46 Status:# EP in sleep"); ums->set_text(ums->label, "#C7EA46 Status:# EP in sleep");
ums->timeouts += 10; ums->timeouts += 10;
@ -1634,7 +1644,7 @@ static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN;
/* Queue a request to read a Bulk-only CBW */ /* Queue a request to read a Bulk-only CBW */
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED);
/* We will drain the buffer in software, which means we /* We will drain the buffer in software, which means we
* can reuse it for the next filling. No need to advance * can reuse it for the next filling. No need to advance
@ -1680,7 +1690,7 @@ static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
csw->Status = status; csw->Status = status;
bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN; bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN;
_ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED);
} }
static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
@ -1688,8 +1698,8 @@ static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
enum ums_state old_state; enum ums_state old_state;
/* Clear out the controller's fifos */ /* Clear out the controller's fifos */
usbd_flush_endpoint(bulk_ctxt->bulk_in); ums_flush_endpoint(bulk_ctxt->bulk_in);
usbd_flush_endpoint(bulk_ctxt->bulk_out); ums_flush_endpoint(bulk_ctxt->bulk_out);
/* Reset the I/O buffer states and pointers, the SCSI /* Reset the I/O buffer states and pointers, the SCSI
* state, and the exception. Then invoke the handler. */ * state, and the exception. Then invoke the handler. */
@ -1764,26 +1774,25 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
int res = 0; int res = 0;
sdmmc_t sdmmc; sdmmc_t sdmmc;
sdmmc_storage_t storage; sdmmc_storage_t storage;
usbd_gadget_ums_t ums = {0};
// Get USB Controller ops.
usb_device_get_ops(&usb_ops);
usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB");
if (usb_device_init()) if (usb_ops.usb_device_init())
{ {
usbd_end(false, true); usb_ops.usbd_end(false, true);
return 1; return 1;
} }
usbd_gadget_ums_t ums;
memset(&ums, 0, sizeof(usbd_gadget_ums_t));
ums.bulk_out_maxpacket = usbd_get_max_pkt_length(USB_EP_BULK_IN);
ums.state = UMS_STATE_NORMAL; ums.state = UMS_STATE_NORMAL;
ums.can_stall = 0; ums.can_stall = 0;
ums.bulk_ctxt.bulk_in = 3; ums.bulk_ctxt.bulk_in = USB_EP_BULK_IN;
ums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; ums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR;
ums.bulk_ctxt.bulk_out = 2; ums.bulk_ctxt.bulk_out = USB_EP_BULK_OUT;
ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR;
// Set LUN parameters. // Set LUN parameters.
@ -1820,12 +1829,12 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
ums.set_text(ums.label, "#C7EA46 Status:# Waiting for connection"); ums.set_text(ums.label, "#C7EA46 Status:# Waiting for connection");
// Initialize Control Endpoint. // Initialize Control Endpoint.
if (usb_device_ep0_initialize(USB_GADGET_UMS)) if (usb_ops.usb_device_enumerate(USB_GADGET_UMS))
goto error; goto error;
ums.set_text(ums.label, "#C7EA46 Status:# Waiting for LUN"); ums.set_text(ums.label, "#C7EA46 Status:# Waiting for LUN");
if (usb_device_get_max_lun(0)) // One device for now. if (usb_ops.usb_device_class_send_max_lun(0)) // One device for now.
goto error; goto error;
ums.set_text(ums.label, "#C7EA46 Status:# Started UMS"); ums.set_text(ums.label, "#C7EA46 Status:# Started UMS");
@ -1885,7 +1894,7 @@ exit:
if (ums.lun.type == MMC_EMMC) if (ums.lun.type == MMC_EMMC)
sdmmc_storage_end(ums.lun.storage); sdmmc_storage_end(ums.lun.storage);
usbd_end(true, false); usb_ops.usbd_end(true, false);
return res; return res;
} }

View file

@ -1,7 +1,7 @@
/* /*
* Enhanced USB (EHCI) device driver for Tegra X1 * Enhanced USB (EHCI) device driver for Tegra X1
* *
* Copyright (c) 2019 CTCaer * Copyright (c) 2019-2020 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,

View file

@ -1,7 +1,7 @@
/* /*
* Enhanced USB (EHCI) Device driver for Tegra X1 * Enhanced USB (EHCI) Device driver for Tegra X1
* *
* Copyright (c) 2019 CTCaer * Copyright (c) 2019-2020 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,
@ -20,7 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <usb/usbd.h> #include <usb/usbd.h>
#include <usb/usb_descriptors.h> #include <usb/usb_descriptor_types.h>
#include <usb/usb_t210.h> #include <usb/usb_t210.h>
#include <gfx_utils.h> #include <gfx_utils.h>
@ -42,20 +42,6 @@ typedef enum
USB_HW_EP1 = 1 USB_HW_EP1 = 1
} usb_hw_ep_t; } usb_hw_ep_t;
typedef enum
{
USB_EP_ADDR_CTRL_OUT = 0x00,
USB_EP_ADDR_CTRL_IN = 0x80,
USB_EP_ADDR_BULK_OUT = 0x01,
USB_EP_ADDR_BULK_IN = 0x81,
} usb_ep_addr_t;
typedef enum
{
USB_EP_CFG_RESET = 0,
USB_EP_CFG_STALL = 1
} usb_ep_cfg_t;
typedef enum typedef enum
{ {
USB_EP_STATUS_IDLE = 0, USB_EP_STATUS_IDLE = 0,
@ -67,72 +53,12 @@ typedef enum
} usb_ep_status_t; } usb_ep_status_t;
typedef enum { typedef enum {
USB_SETUP_RECIPIENT_DEVICE = 0, USB_LOW_SPEED = 0,
USB_SETUP_RECIPIENT_INTERFACE = 1, USB_FULL_SPEED = 1,
USB_SETUP_RECIPIENT_ENDPOINT = 2, USB_HIGH_SPEED = 2,
USB_SETUP_RECIPIENT_OTHER = 3, USB_SUPER_SPEED = 3,
USB_SETUP_TYPE_STANDARD = 0x00,
USB_SETUP_TYPE_CLASS = 0x20,
USB_SETUP_TYPE_VENDOR = 0x40,
USB_SETUP_TYPE_RESERVED = 0x60,
USB_SETUP_HOST_TO_DEVICE = 0x00,
USB_SETUP_DEVICE_TO_HOST = 0x80,
} usb_setup_req_type_t;
typedef enum {
USB_REQUEST_GET_STATUS = 0,
USB_REQUEST_CLEAR_FEATURE = 1,
USB_REQUEST_SET_FEATURE = 3,
USB_REQUEST_SET_ADDRESS = 5,
USB_REQUEST_GET_DESCRIPTOR = 6,
USB_REQUEST_SET_DESCRIPTOR = 7,
USB_REQUEST_GET_CONFIGURATION = 8,
USB_REQUEST_SET_CONFIGURATION = 9,
USB_REQUEST_GET_INTERFACE = 10,
USB_REQUEST_SET_INTERFACE = 11,
USB_REQUEST_SYNCH_FRAME = 12,
USB_REQUEST_GET_MS_DESCRIPTOR = 0x99,
USB_REQUEST_BULK_GET_MAX_LUN = 0xFE,
USB_REQUEST_BULK_RESET = 0xFF
} usb_standard_req_t;
typedef enum {
USB_FEATURE_ENDPOINT_HALT = 0,
USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1,
USB_FEATURE_TEST_MODE = 2,
} usb_get_status_req_t;
typedef enum {
USB_STATUS_EP_OK = 0,
USB_STATUS_EP_HALTED = 1,
USB_STATUS_DEV_SELF_POWERED = 1,
USB_STATUS_DEV_REMOTE_WAKE = 2,
} usb_set_clear_feature_req_t;
typedef enum {
USB_XFER_DIR_OUT = 0,
USB_XFER_DIR_IN = 1,
} usb_xfer_dir_t;
typedef enum {
USB_SPEED_LOW = 0,
USB_SPEED_FULL = 1,
USB_SPEED_HIGH = 2,
USB_SPEED_SUPER = 3,
} usb_speed_t; } usb_speed_t;
typedef enum {
USB_XFER_TYPE_CONTROL = 0,
USB_XFER_TYPE_ISOCHRONOUS = 1,
USB_XFER_TYPE_BULK = 2,
USB_XFER_TYPE_INTERRUPT = 3,
} usb_xfer_type_t;
typedef struct _dTD_t typedef struct _dTD_t
{ {
vu32 next_dTD; vu32 next_dTD;
@ -161,15 +87,6 @@ typedef struct _usbd_t
int ep_bytes_requested[4]; int ep_bytes_requested[4];
} usbd_t; } usbd_t;
typedef struct _usb_ctrl_setup_t
{
u8 bmRequestType;
u8 bRequest;
u16 wValue;
u16 wIndex;
u16 wLength;
} usb_ctrl_setup_t;
typedef struct _usbd_controller_t typedef struct _usbd_controller_t
{ {
u32 port_speed; u32 port_speed;
@ -188,6 +105,15 @@ typedef struct _usbd_controller_t
bool charger_detect; bool charger_detect;
} usbd_controller_t; } usbd_controller_t;
extern u8 hid_report_descriptor_jc[];
extern u8 hid_report_descriptor_touch[];
extern u32 hid_report_descriptor_jc_size;
extern u32 hid_report_descriptor_touch_size;
extern usb_desc_t usb_gadget_hid_jc_descriptors;
extern usb_desc_t usb_gadget_hid_touch_descriptors;
extern usb_desc_t usb_gadget_ums_descriptors;
usbd_t *usbdaemon; usbd_t *usbdaemon;
usbd_controller_t *usbd_otg; usbd_controller_t *usbd_otg;
@ -535,10 +461,10 @@ static void _usb_device_power_down()
usb_init_done = false; usb_init_done = false;
} }
static void _usbd_stall_reset_ep1(usb_xfer_dir_t direction, usb_ep_cfg_t stall) static void _usbd_stall_reset_ep1(usb_dir_t direction, usb_ep_cfg_t stall)
{ {
stall &= 1; stall &= 1;
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
{ {
usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16); usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16);
if (!stall) if (!stall)
@ -552,39 +478,14 @@ static void _usbd_stall_reset_ep1(usb_xfer_dir_t direction, usb_ep_cfg_t stall)
} }
} }
void usbd_end(bool reset_ep, bool only_controller)
{
if (reset_ep)
{
usbd_flush_endpoint(USB_EP_ALL);
_usbd_stall_reset_ep1(0, USB_EP_CFG_RESET); // EP1 Bulk IN.
_usbd_stall_reset_ep1(1, USB_EP_CFG_RESET); // EP1 Bulk OUT.
//TODO: what about EP0 simultaneous in/out reset.
usbd_otg->configuration = 0;
usbd_otg->interface = 0;
usbd_otg->configuration_set = 0;
usbd_otg->max_lun_set = 0;
}
// Stop device controller.
usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN;
// Enable PHY auto low power suspend.
usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS;
if (!only_controller)
_usb_device_power_down();
}
void usb_device_stall_ep1_bulk_out() void usb_device_stall_ep1_bulk_out()
{ {
_usbd_stall_reset_ep1(USB_XFER_DIR_OUT, USB_EP_CFG_STALL); _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_STALL);
} }
void usb_device_stall_ep1_bulk_in() void usb_device_stall_ep1_bulk_in()
{ {
_usbd_stall_reset_ep1(USB_XFER_DIR_IN, USB_EP_CFG_STALL); _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_STALL);
} }
int usbd_get_max_pkt_length(int endpoint) int usbd_get_max_pkt_length(int endpoint)
@ -608,7 +509,7 @@ int usbd_get_max_pkt_length(int endpoint)
static void _usbd_initialize_ep_ctrl(u32 endpoint) static void _usbd_initialize_ep_ctrl(u32 endpoint)
{ {
usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1;
usb_xfer_dir_t direction = endpoint & 1; usb_dir_t direction = endpoint & 1;
memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t));
@ -620,7 +521,7 @@ static void _usbd_initialize_ep_ctrl(u32 endpoint)
u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK;
usbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16; usbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16;
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
{ {
u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK; u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK;
if (actual_ep) if (actual_ep)
@ -700,13 +601,13 @@ int usbd_flush_endpoint(u32 endpoint)
{ {
usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1;
usb_xfer_dir_t direction = endpoint & 1; usb_dir_t direction = endpoint & 1;
u32 reg_mask = endpoint; u32 reg_mask = endpoint;
// Flash all endpoints or 1. // Flash all endpoints or 1.
if (endpoint != USB_EP_ALL) if (endpoint != USB_EP_ALL)
{ {
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;
else else
reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;
@ -745,11 +646,36 @@ int usbd_flush_endpoint(u32 endpoint)
return 0; return 0;
} }
void usbd_end(bool reset_ep, bool only_controller)
{
if (reset_ep)
{
usbd_flush_endpoint(USB_EP_ALL);
_usbd_stall_reset_ep1(0, USB_EP_CFG_RESET); // EP1 Bulk IN.
_usbd_stall_reset_ep1(1, USB_EP_CFG_RESET); // EP1 Bulk OUT.
//TODO: what about EP0 simultaneous in/out reset.
usbd_otg->configuration = 0;
usbd_otg->interface = 0;
usbd_otg->configuration_set = false;
usbd_otg->max_lun_set = false;
}
// Stop device controller.
usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN;
// Enable PHY auto low power suspend.
usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS;
if (!only_controller)
_usb_device_power_down();
}
static void _usbd_mark_ep_complete(u32 endpoint) static void _usbd_mark_ep_complete(u32 endpoint)
{ {
u32 complete_bit; u32 complete_bit;
usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1;
usb_xfer_dir_t direction = endpoint & 1; usb_dir_t direction = endpoint & 1;
usbd_flush_endpoint(endpoint); usbd_flush_endpoint(endpoint);
memset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4); memset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4);
@ -757,7 +683,7 @@ static void _usbd_mark_ep_complete(u32 endpoint)
usbdaemon->ep_configured[endpoint] = 0; usbdaemon->ep_configured[endpoint] = 0;
usbdaemon->ep_bytes_requested[endpoint] = 0; usbdaemon->ep_bytes_requested[endpoint] = 0;
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
complete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; complete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;
else else
complete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; complete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;
@ -771,9 +697,9 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint)
u32 reg_val; u32 reg_val;
u32 reg_mask; u32 reg_mask;
u32 actual_ep = (endpoint & 2) >> 1; u32 actual_ep = (endpoint & 2) >> 1;
usb_xfer_dir_t direction = endpoint & 1; usb_dir_t direction = endpoint & 1;
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;
else else
reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;
@ -784,7 +710,7 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint)
reg_val = usbd_otg->regs->endptctrl[0]; reg_val = usbd_otg->regs->endptctrl[0];
// Check stalled status. // Check stalled status.
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
status = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL; status = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL;
else else
status = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL; status = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL;
@ -793,7 +719,7 @@ static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint)
return USB_EP_STATUS_STALLED; return USB_EP_STATUS_STALLED;
// Check enabled status. // Check enabled status.
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
status = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE; status = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE;
else else
status = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE; status = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE;
@ -824,7 +750,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync)
u32 prime_bit; u32 prime_bit;
usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1;
usb_xfer_dir_t direction = endpoint & 1; usb_dir_t direction = endpoint & 1;
u32 length_left = len; u32 length_left = len;
u32 dtd_ep_idx = endpoint * 4; u32 dtd_ep_idx = endpoint * 4;
@ -877,7 +803,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync)
AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE; AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE;
AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |= MEM_PREFETCH_ENABLE; AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |= MEM_PREFETCH_ENABLE;
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
{ {
prime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; prime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
@ -918,7 +844,7 @@ out:
else if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE) else if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE)
res = 26; res = 26;
if (direction == USB_XFER_DIR_OUT) if (direction == USB_DIR_OUT)
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
} }
@ -938,25 +864,27 @@ static void _usbd_set_ep0_stall()
USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL; USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL;
} }
void usbd_set_ep_stall(u32 endpoint, int ep_stall) int usbd_set_ep_stall(u32 endpoint, int ep_stall)
{ {
usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; usb_hw_ep_t actual_ep = (endpoint & 2) >> 1;
usb_xfer_dir_t direction = endpoint & 1; usb_dir_t direction = endpoint & 1;
if (ep_stall) if (ep_stall)
{ {
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN. usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN.
else else
usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT. usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT.
} }
else else
{ {
if (direction == USB_XFER_DIR_IN) if (direction == USB_DIR_IN)
usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN. usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN.
else else
usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT. usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT.
} }
return 0;
} }
static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, int *ep_stall) static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, int *ep_stall)
@ -1256,12 +1184,12 @@ static int _usbd_handle_ep0_control_transfer()
if (usbd_otg->type == USB_GADGET_HID_GAMEPAD) if (usbd_otg->type == USB_GADGET_HID_GAMEPAD)
{ {
descriptor = (u8 *)&hid_report_descriptor_jc; descriptor = (u8 *)&hid_report_descriptor_jc;
_wLength = sizeof(hid_report_descriptor_jc); _wLength = hid_report_descriptor_jc_size;
} }
else // USB_GADGET_HID_TOUCHPAD else // USB_GADGET_HID_TOUCHPAD
{ {
descriptor = (u8 *)&hid_report_descriptor_touch; descriptor = (u8 *)&hid_report_descriptor_touch;
_wLength = sizeof(hid_report_descriptor_touch); _wLength = hid_report_descriptor_touch_size;
} }
usbd_otg->hid_report_sent = 1; usbd_otg->hid_report_sent = 1;
@ -1432,7 +1360,7 @@ static int _usbd_ep0_initialize()
return 3; return 3;
} }
int usb_device_ep0_initialize(usb_gadget_type type) int usb_device_enumerate(usb_gadget_type type)
{ {
switch (type) switch (type)
{ {
@ -1455,7 +1383,7 @@ int usb_device_ep0_initialize(usb_gadget_type type)
return result; return result;
} }
int usbd_handle_ep0_pending_control_transfer() int usbd_handle_ep0_ctrl_setup()
{ {
// 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;
@ -1476,17 +1404,17 @@ int usbd_handle_ep0_pending_control_transfer()
return 0; return 0;
} }
static usb_ep_status_t _usbd_get_ep1_status(usb_xfer_dir_t dir) static usb_ep_status_t _usbd_get_ep1_status(usb_dir_t dir)
{ {
usb_ep_t ep; usb_ep_t ep;
if (dir == USB_XFER_DIR_OUT) if (dir == USB_DIR_OUT)
ep = USB_EP_BULK_OUT; ep = USB_EP_BULK_OUT;
else else
ep = USB_EP_BULK_IN; ep = USB_EP_BULK_IN;
return _usbd_get_ep_status(ep); return _usbd_get_ep_status(ep);
} }
int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync) int usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, bool sync)
{ {
if (len > USB_EP_BUFFER_MAX_SIZE) if (len > USB_EP_BUFFER_MAX_SIZE)
len = USB_EP_BUFFER_MAX_SIZE; len = USB_EP_BUFFER_MAX_SIZE;
@ -1504,7 +1432,7 @@ int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync)
return result; return result;
} }
int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read) int usb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read)
{ {
if (len > USB_EP_BULK_OUT_MAX_XFER) if (len > USB_EP_BULK_OUT_MAX_XFER)
len = USB_EP_BULK_OUT_MAX_XFER; len = USB_EP_BULK_OUT_MAX_XFER;
@ -1518,7 +1446,7 @@ int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read)
{ {
u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE);
result = usb_device_read_ep1_out(buf_curr, len_ep, &bytes, true); result = usb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED);
if (!result) if (!result)
{ {
len -= len_ep; len -= len_ep;
@ -1540,16 +1468,16 @@ static int _usbd_get_ep1_out_bytes_read()
return (usbdaemon->ep_bytes_requested[2] - (usbdaemon->qhs[2].token >> 16)); return (usbdaemon->ep_bytes_requested[2] - (usbdaemon->qhs[2].token >> 16));
} }
int usb_device_ep1_out_reading_finish(u32 *pending_bytes) int usb_device_ep1_out_reading_finish(u32 *pending_bytes, int tries)
{ {
usb_ep_status_t ep_status; usb_ep_status_t ep_status;
do do
{ {
ep_status = _usbd_get_ep1_status(USB_XFER_DIR_OUT); ep_status = _usbd_get_ep1_status(USB_DIR_OUT);
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_pending_control_transfer(); usbd_handle_ep0_ctrl_setup();
} }
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));
@ -1565,7 +1493,7 @@ int usb_device_ep1_out_reading_finish(u32 *pending_bytes)
return 26; return 26;
} }
int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync) int usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, bool sync)
{ {
if (len > USB_EP_BUFFER_MAX_SIZE) if (len > USB_EP_BUFFER_MAX_SIZE)
len = USB_EP_BUFFER_MAX_SIZE; len = USB_EP_BUFFER_MAX_SIZE;
@ -1596,11 +1524,11 @@ int usb_device_ep1_in_writing_finish(u32 *pending_bytes)
usb_ep_status_t ep_status; usb_ep_status_t ep_status;
do do
{ {
ep_status = _usbd_get_ep1_status(USB_XFER_DIR_IN); ep_status = _usbd_get_ep1_status(USB_DIR_IN);
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_pending_control_transfer(); usbd_handle_ep0_ctrl_setup();
} }
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));
@ -1621,12 +1549,13 @@ bool usb_device_get_suspended()
return (suspended ? true : false); return (suspended ? true : false);
} }
u32 usb_device_get_port_status() bool usb_device_get_port_in_sleep()
{ {
return (usbd_otg->regs->portsc1); // Windows heuristic: Forces port into suspend, sleep and J-State.
return (usbd_otg->regs->portsc1) == 0x885;
} }
bool usb_device_get_max_lun(u8 max_lun) bool usb_device_class_send_max_lun(u8 max_lun)
{ {
// Timeout if get MAX_LUN request doesn't happen in 10s. // Timeout if get MAX_LUN request doesn't happen in 10s.
u32 timer = get_tmr_ms() + 10000; u32 timer = get_tmr_ms() + 10000;
@ -1635,7 +1564,7 @@ bool usb_device_get_max_lun(u8 max_lun)
while (!usbd_otg->max_lun_set) while (!usbd_otg->max_lun_set)
{ {
usbd_handle_ep0_pending_control_transfer(); usbd_handle_ep0_ctrl_setup();
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 true; return true;
} }
@ -1643,17 +1572,39 @@ bool usb_device_get_max_lun(u8 max_lun)
return false; return false;
} }
bool usb_device_get_hid_report() bool usb_device_class_send_hid_report()
{ {
// 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.
while (!usbd_otg->hid_report_sent) while (!usbd_otg->hid_report_sent)
{ {
usbd_handle_ep0_pending_control_transfer(); usbd_handle_ep0_ctrl_setup();
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 true; return true;
} }
return false; return false;
} }
void usb_device_get_ops(usb_ops_t *ops)
{
ops->usbd_flush_endpoint = usbd_flush_endpoint;
ops->usbd_set_ep_stall = usbd_set_ep_stall;
ops->usbd_handle_ep0_ctrl_setup = usbd_handle_ep0_ctrl_setup;
ops->usbd_end = usbd_end;
ops->usb_device_init = usb_device_init;
ops->usb_device_enumerate = usb_device_enumerate;
ops->usb_device_class_send_max_lun = usb_device_class_send_max_lun;
ops->usb_device_class_send_hid_report = usb_device_class_send_hid_report;
ops->usb_device_get_suspended = usb_device_get_suspended;
ops->usb_device_get_port_in_sleep = usb_device_get_port_in_sleep;
ops->usb_device_ep1_out_read = usb_device_ep1_out_read;
ops->usb_device_ep1_out_read_big = usb_device_ep1_out_read_big;
ops->usb_device_ep1_out_reading_finish = usb_device_ep1_out_reading_finish;
ops->usb_device_ep1_in_write = usb_device_ep1_in_write;
ops->usb_device_ep1_in_writing_finish = usb_device_ep1_in_writing_finish;
}

View file

@ -29,6 +29,129 @@
#define USB_EP_BUFFER_4_TD (USB_TD_BUFFER_MAX_SIZE * 4) #define USB_EP_BUFFER_4_TD (USB_TD_BUFFER_MAX_SIZE * 4)
#define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD) #define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD)
#define USB_XFER_START false
#define USB_XFER_SYNCED true
typedef enum _usb_hid_type
{
USB_HID_GAMEPAD,
USB_HID_TOUCHPAD
} usb_hid_type;
typedef enum _usb_gadget_type
{
USB_GADGET_UMS = 0,
USB_GADGET_HID_GAMEPAD = 1,
USB_GADGET_HID_TOUCHPAD = 2,
} usb_gadget_type;
typedef enum {
USB_DIR_OUT = 0,
USB_DIR_IN = 1,
} usb_dir_t;
typedef enum
{
USB_EP_CTRL_OUT = 0, // EP0.
USB_EP_CTRL_IN = 1, // EP0.
USB_EP_BULK_OUT = 2, // EP1.
USB_EP_BULK_IN = 3, // EP1.
USB_EP_ALL = 0xFFFFFFFF
} usb_ep_t;
typedef enum
{
USB_EP_ADDR_CTRL_OUT = 0x00,
USB_EP_ADDR_CTRL_IN = 0x80,
USB_EP_ADDR_BULK_OUT = 0x01,
USB_EP_ADDR_BULK_IN = 0x81,
} usb_ep_addr_t;
typedef enum
{
USB_EP_CFG_CLEAR = 0,
USB_EP_CFG_RESET = 0,
USB_EP_CFG_STALL = 1
} usb_ep_cfg_t;
typedef enum {
USB_STATUS_EP_OK = 0,
USB_STATUS_EP_HALTED = 1,
USB_STATUS_DEV_SELF_POWERED = 1,
USB_STATUS_DEV_REMOTE_WAKE = 2,
} usb_set_clear_feature_req_t;
typedef enum {
USB_SETUP_RECIPIENT_DEVICE = 0,
USB_SETUP_RECIPIENT_INTERFACE = 1,
USB_SETUP_RECIPIENT_ENDPOINT = 2,
USB_SETUP_RECIPIENT_OTHER = 3,
USB_SETUP_TYPE_STANDARD = 0x00,
USB_SETUP_TYPE_CLASS = 0x20,
USB_SETUP_TYPE_VENDOR = 0x40,
USB_SETUP_TYPE_RESERVED = 0x60,
USB_SETUP_HOST_TO_DEVICE = 0x00,
USB_SETUP_DEVICE_TO_HOST = 0x80,
} usb_setup_req_type_t;
typedef enum {
USB_REQUEST_GET_STATUS = 0,
USB_REQUEST_CLEAR_FEATURE = 1,
USB_REQUEST_SET_FEATURE = 3,
USB_REQUEST_SET_ADDRESS = 5,
USB_REQUEST_GET_DESCRIPTOR = 6,
USB_REQUEST_SET_DESCRIPTOR = 7,
USB_REQUEST_GET_CONFIGURATION = 8,
USB_REQUEST_SET_CONFIGURATION = 9,
USB_REQUEST_GET_INTERFACE = 10,
USB_REQUEST_SET_INTERFACE = 11,
USB_REQUEST_SYNCH_FRAME = 12,
USB_REQUEST_SET_SEL = 13,
USB_REQUEST_GET_MS_DESCRIPTOR = 0x99,
USB_REQUEST_BULK_GET_MAX_LUN = 0xFE,
USB_REQUEST_BULK_RESET = 0xFF
} usb_standard_req_t;
typedef enum {
USB_FEATURE_ENDPOINT_HALT = 0,
USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1,
USB_FEATURE_TEST_MODE = 2,
} usb_get_status_req_t;
typedef struct _usb_ctrl_setup_t
{
u8 bmRequestType;
u8 bRequest;
u16 wValue;
u16 wIndex;
u16 wLength;
} usb_ctrl_setup_t;
typedef struct _usb_ops_t
{
int (*usbd_flush_endpoint)(u32);
int (*usbd_set_ep_stall)(u32, int);
int (*usbd_handle_ep0_ctrl_setup)();
void (*usbd_end)(bool, bool);
int (*usb_device_init)();
int (*usb_device_enumerate)(usb_gadget_type gadget);
bool (*usb_device_class_send_max_lun)(u8);
bool (*usb_device_class_send_hid_report)();
int (*usb_device_ep1_out_read)(u8 *, u32, u32 *, bool);
int (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *);
int (*usb_device_ep1_out_reading_finish)(u32 *, int);
int (*usb_device_ep1_in_write)(u8 *, u32, u32 *, bool);
int (*usb_device_ep1_in_writing_finish)(u32 *);
bool (*usb_device_get_suspended)();
bool (*usb_device_get_port_in_sleep)();
} usb_ops_t;
typedef struct _usb_ctxt_t typedef struct _usb_ctxt_t
{ {
u32 type; u32 type;
@ -41,46 +164,10 @@ typedef struct _usb_ctxt_t
void (*set_text)(void *, const char *); void (*set_text)(void *, const char *);
} usb_ctxt_t; } usb_ctxt_t;
typedef enum _usb_hid_type void usb_device_get_ops(usb_ops_t *ops);
{ void xusb_device_get_ops(usb_ops_t *ops);
USB_HID_GAMEPAD,
USB_HID_TOUCHPAD
} usb_hid_type;
typedef enum _usb_gadget_type
{
USB_GADGET_UMS,
USB_GADGET_HID_GAMEPAD,
USB_GADGET_HID_TOUCHPAD
} usb_gadget_type;
typedef enum
{
USB_EP_CTRL_OUT = 0, // EP0.
USB_EP_CTRL_IN = 1, // EP0.
USB_EP_BULK_OUT = 2, // EP1.
USB_EP_BULK_IN = 3, // EP1.
USB_EP_ALL = 0xFFFFFFFF
} usb_ep_t;
int usbd_flush_endpoint(u32 ep);
void usbd_set_ep_stall(u32 endpoint, int ep_stall);
int usbd_get_max_pkt_length(int endpoint);
int usbd_handle_ep0_pending_control_transfer();
void usbd_end(bool reset_ep, bool only_controller);
int usb_device_init();
int usb_device_ep0_initialize(usb_gadget_type type);
int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync);
int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read);
int usb_device_ep1_out_reading_finish(u32 *pending_bytes);
int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync);
int usb_device_ep1_in_writing_finish(u32 *pending_bytes);
bool usb_device_get_suspended();
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);
bool usb_device_get_max_lun(u8 max_lun);
bool usb_device_get_hid_report();
u32 usb_device_get_port_status();
#endif #endif