CMSIS DAP/DAP Link Debugger (#1897)
* Apps: DAP Link * API: furi_hal_console_init Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
994
applications/plugins/dap_link/usb/dap_v2_usb.c
Normal file
994
applications/plugins/dap_link/usb/dap_v2_usb.c
Normal file
@@ -0,0 +1,994 @@
|
||||
#include <furi.h>
|
||||
#include <usb.h>
|
||||
#include <usb_std.h>
|
||||
#include <usb_hid.h>
|
||||
#include <usb_cdc.h>
|
||||
#include <furi_hal_console.h>
|
||||
|
||||
#include "dap_v2_usb.h"
|
||||
|
||||
// #define DAP_USB_LOG
|
||||
|
||||
#define HID_EP_IN 0x80
|
||||
#define HID_EP_OUT 0x00
|
||||
|
||||
#define DAP_HID_EP_SEND 1
|
||||
#define DAP_HID_EP_RECV 2
|
||||
#define DAP_HID_EP_BULK_RECV 3
|
||||
#define DAP_HID_EP_BULK_SEND 4
|
||||
#define DAP_CDC_EP_COMM 5
|
||||
#define DAP_CDC_EP_SEND 6
|
||||
#define DAP_CDC_EP_RECV 7
|
||||
|
||||
#define DAP_HID_EP_IN (HID_EP_IN | DAP_HID_EP_SEND)
|
||||
#define DAP_HID_EP_OUT (HID_EP_OUT | DAP_HID_EP_RECV)
|
||||
#define DAP_HID_EP_BULK_IN (HID_EP_IN | DAP_HID_EP_BULK_SEND)
|
||||
#define DAP_HID_EP_BULK_OUT (HID_EP_OUT | DAP_HID_EP_BULK_RECV)
|
||||
|
||||
#define DAP_HID_EP_SIZE 64
|
||||
#define DAP_CDC_COMM_EP_SIZE 8
|
||||
#define DAP_CDC_EP_SIZE 64
|
||||
|
||||
#define DAP_BULK_INTERVAL 0
|
||||
#define DAP_HID_INTERVAL 1
|
||||
#define DAP_CDC_INTERVAL 0
|
||||
#define DAP_CDC_COMM_INTERVAL 1
|
||||
|
||||
#define DAP_HID_VID 0x0483
|
||||
#define DAP_HID_PID 0x5740
|
||||
|
||||
#define DAP_USB_EP0_SIZE 8
|
||||
|
||||
#define EP_CFG_DECONFIGURE 0
|
||||
#define EP_CFG_CONFIGURE 1
|
||||
|
||||
enum {
|
||||
USB_INTF_HID,
|
||||
USB_INTF_BULK,
|
||||
USB_INTF_CDC_COMM,
|
||||
USB_INTF_CDC_DATA,
|
||||
USB_INTF_COUNT,
|
||||
};
|
||||
|
||||
enum {
|
||||
USB_STR_ZERO,
|
||||
USB_STR_MANUFACTURER,
|
||||
USB_STR_PRODUCT,
|
||||
USB_STR_SERIAL_NUMBER,
|
||||
USB_STR_CMSIS_DAP_V1,
|
||||
USB_STR_CMSIS_DAP_V2,
|
||||
USB_STR_COM_PORT,
|
||||
USB_STR_COUNT,
|
||||
};
|
||||
|
||||
// static const char* usb_str[] = {
|
||||
// [USB_STR_MANUFACTURER] = "Flipper Devices Inc.",
|
||||
// [USB_STR_PRODUCT] = "Combined VCP and CMSIS-DAP Adapter",
|
||||
// [USB_STR_COM_PORT] = "Virtual COM-Port",
|
||||
// [USB_STR_CMSIS_DAP_V1] = "CMSIS-DAP v1 Adapter",
|
||||
// [USB_STR_CMSIS_DAP_V2] = "CMSIS-DAP v2 Adapter",
|
||||
// [USB_STR_SERIAL_NUMBER] = "01234567890ABCDEF",
|
||||
// };
|
||||
|
||||
static const struct usb_string_descriptor dev_manuf_descr =
|
||||
USB_STRING_DESC("Flipper Devices Inc.");
|
||||
|
||||
static const struct usb_string_descriptor dev_prod_descr =
|
||||
USB_STRING_DESC("Combined VCP and CMSIS-DAP Adapter");
|
||||
|
||||
static struct usb_string_descriptor* dev_serial_descr = NULL;
|
||||
|
||||
static const struct usb_string_descriptor dev_dap_v1_descr =
|
||||
USB_STRING_DESC("CMSIS-DAP v1 Adapter");
|
||||
|
||||
static const struct usb_string_descriptor dev_dap_v2_descr =
|
||||
USB_STRING_DESC("CMSIS-DAP v2 Adapter");
|
||||
|
||||
static const struct usb_string_descriptor dev_com_descr = USB_STRING_DESC("Virtual COM-Port");
|
||||
|
||||
struct HidConfigDescriptor {
|
||||
struct usb_config_descriptor configuration;
|
||||
|
||||
// CMSIS-DAP v1
|
||||
struct usb_interface_descriptor hid_interface;
|
||||
struct usb_hid_descriptor hid;
|
||||
struct usb_endpoint_descriptor hid_ep_in;
|
||||
struct usb_endpoint_descriptor hid_ep_out;
|
||||
|
||||
// CMSIS-DAP v2
|
||||
struct usb_interface_descriptor bulk_interface;
|
||||
struct usb_endpoint_descriptor bulk_ep_out;
|
||||
struct usb_endpoint_descriptor bulk_ep_in;
|
||||
|
||||
// CDC
|
||||
struct usb_iad_descriptor iad;
|
||||
struct usb_interface_descriptor interface_comm;
|
||||
struct usb_cdc_header_desc cdc_header;
|
||||
struct usb_cdc_call_mgmt_desc cdc_acm;
|
||||
struct usb_cdc_acm_desc cdc_call_mgmt;
|
||||
struct usb_cdc_union_desc cdc_union;
|
||||
struct usb_endpoint_descriptor ep_comm;
|
||||
struct usb_interface_descriptor interface_data;
|
||||
struct usb_endpoint_descriptor ep_in;
|
||||
struct usb_endpoint_descriptor ep_out;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
static const struct usb_device_descriptor hid_device_desc = {
|
||||
.bLength = sizeof(struct usb_device_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_DEVICE,
|
||||
.bcdUSB = VERSION_BCD(2, 1, 0),
|
||||
.bDeviceClass = USB_CLASS_MISC,
|
||||
.bDeviceSubClass = USB_SUBCLASS_IAD,
|
||||
.bDeviceProtocol = USB_PROTO_IAD,
|
||||
.bMaxPacketSize0 = DAP_USB_EP0_SIZE,
|
||||
.idVendor = DAP_HID_VID,
|
||||
.idProduct = DAP_HID_PID,
|
||||
.bcdDevice = VERSION_BCD(1, 0, 0),
|
||||
.iManufacturer = USB_STR_MANUFACTURER,
|
||||
.iProduct = USB_STR_PRODUCT,
|
||||
.iSerialNumber = USB_STR_SERIAL_NUMBER,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
static const uint8_t hid_report_desc[] = {
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x00, // Usage (Undefined)
|
||||
0xa1, 0x01, // Collection (Application)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xff, 0x00, // Logical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x40, // Report Count (64)
|
||||
0x09, 0x00, // Usage (Undefined)
|
||||
0x81, 0x82, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x40, // Report Count (64)
|
||||
0x09, 0x00, // Usage (Undefined)
|
||||
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
|
||||
0xc0, // End Collection
|
||||
};
|
||||
|
||||
static const struct HidConfigDescriptor hid_cfg_desc = {
|
||||
.configuration =
|
||||
{
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_CONFIGURATION,
|
||||
.wTotalLength = sizeof(struct HidConfigDescriptor),
|
||||
.bNumInterfaces = USB_INTF_COUNT,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = NO_DESCRIPTOR,
|
||||
.bmAttributes = USB_CFG_ATTR_RESERVED,
|
||||
.bMaxPower = USB_CFG_POWER_MA(500),
|
||||
},
|
||||
|
||||
// CMSIS-DAP v1
|
||||
.hid_interface =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = USB_INTF_HID,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
.bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT,
|
||||
.bInterfaceProtocol = USB_HID_PROTO_NONBOOT,
|
||||
.iInterface = USB_STR_CMSIS_DAP_V1,
|
||||
},
|
||||
|
||||
.hid =
|
||||
{
|
||||
.bLength = sizeof(struct usb_hid_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_HID,
|
||||
.bcdHID = VERSION_BCD(1, 1, 1),
|
||||
.bCountryCode = USB_HID_COUNTRY_NONE,
|
||||
.bNumDescriptors = 1,
|
||||
.bDescriptorType0 = USB_DTYPE_HID_REPORT,
|
||||
.wDescriptorLength0 = sizeof(hid_report_desc),
|
||||
},
|
||||
|
||||
.hid_ep_in =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = DAP_HID_EP_IN,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
||||
.bInterval = DAP_HID_INTERVAL,
|
||||
},
|
||||
|
||||
.hid_ep_out =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = DAP_HID_EP_OUT,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
||||
.bInterval = DAP_HID_INTERVAL,
|
||||
},
|
||||
|
||||
// CMSIS-DAP v2
|
||||
.bulk_interface =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = USB_INTF_BULK,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = USB_STR_CMSIS_DAP_V2,
|
||||
},
|
||||
|
||||
.bulk_ep_out =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = DAP_HID_EP_BULK_OUT,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
||||
.bInterval = DAP_BULK_INTERVAL,
|
||||
},
|
||||
|
||||
.bulk_ep_in =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = DAP_HID_EP_BULK_IN,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
||||
.bInterval = DAP_BULK_INTERVAL,
|
||||
},
|
||||
|
||||
// CDC
|
||||
.iad =
|
||||
{
|
||||
.bLength = sizeof(struct usb_iad_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFASEASSOC,
|
||||
.bFirstInterface = USB_INTF_CDC_COMM,
|
||||
.bInterfaceCount = 2,
|
||||
.bFunctionClass = USB_CLASS_CDC,
|
||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bFunctionProtocol = USB_PROTO_NONE,
|
||||
.iFunction = USB_STR_COM_PORT,
|
||||
},
|
||||
.interface_comm =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = USB_INTF_CDC_COMM,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_CDC,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = 0,
|
||||
},
|
||||
|
||||
.cdc_header =
|
||||
{
|
||||
.bFunctionLength = sizeof(struct usb_cdc_header_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_HEADER,
|
||||
.bcdCDC = VERSION_BCD(1, 1, 0),
|
||||
},
|
||||
|
||||
.cdc_acm =
|
||||
{
|
||||
.bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT,
|
||||
// .bmCapabilities = USB_CDC_CAP_LINE | USB_CDC_CAP_BRK,
|
||||
.bmCapabilities = 0,
|
||||
},
|
||||
|
||||
.cdc_call_mgmt =
|
||||
{
|
||||
.bFunctionLength = sizeof(struct usb_cdc_acm_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_ACM,
|
||||
.bmCapabilities = USB_CDC_CALL_MGMT_CAP_DATA_INTF,
|
||||
// .bDataInterface = USB_INTF_CDC_DATA,
|
||||
},
|
||||
|
||||
.cdc_union =
|
||||
{
|
||||
.bFunctionLength = sizeof(struct usb_cdc_union_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_UNION,
|
||||
.bMasterInterface0 = USB_INTF_CDC_COMM,
|
||||
.bSlaveInterface0 = USB_INTF_CDC_DATA,
|
||||
},
|
||||
|
||||
.ep_comm =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = HID_EP_IN | DAP_CDC_EP_COMM,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = DAP_CDC_COMM_EP_SIZE,
|
||||
.bInterval = DAP_CDC_COMM_INTERVAL,
|
||||
},
|
||||
|
||||
.interface_data =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = USB_INTF_CDC_DATA,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_NONE,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
|
||||
.ep_in =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = HID_EP_IN | DAP_CDC_EP_SEND,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = DAP_CDC_EP_SIZE,
|
||||
.bInterval = DAP_CDC_INTERVAL,
|
||||
},
|
||||
|
||||
.ep_out =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = HID_EP_OUT | DAP_CDC_EP_RECV,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = DAP_CDC_EP_SIZE,
|
||||
.bInterval = DAP_CDC_INTERVAL,
|
||||
},
|
||||
};
|
||||
|
||||
// WinUSB
|
||||
#include "usb_winusb.h"
|
||||
|
||||
typedef struct USB_PACK {
|
||||
usb_binary_object_store_descriptor_t bos;
|
||||
usb_winusb_capability_descriptor_t winusb;
|
||||
} usb_bos_hierarchy_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
usb_winusb_subset_header_function_t header;
|
||||
usb_winusb_feature_compatble_id_t comp_id;
|
||||
usb_winusb_feature_reg_property_guids_t property;
|
||||
} usb_msos_descriptor_subset_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
usb_winusb_set_header_descriptor_t header;
|
||||
usb_msos_descriptor_subset_t subset;
|
||||
} usb_msos_descriptor_set_t;
|
||||
|
||||
#define USB_DTYPE_BINARY_OBJECT_STORE 15
|
||||
#define USB_DTYPE_DEVICE_CAPABILITY_DESCRIPTOR 16
|
||||
#define USB_DC_TYPE_PLATFORM 5
|
||||
|
||||
const usb_bos_hierarchy_t usb_bos_hierarchy = {
|
||||
.bos =
|
||||
{
|
||||
.bLength = sizeof(usb_binary_object_store_descriptor_t),
|
||||
.bDescriptorType = USB_DTYPE_BINARY_OBJECT_STORE,
|
||||
.wTotalLength = sizeof(usb_bos_hierarchy_t),
|
||||
.bNumDeviceCaps = 1,
|
||||
},
|
||||
.winusb =
|
||||
{
|
||||
.bLength = sizeof(usb_winusb_capability_descriptor_t),
|
||||
.bDescriptorType = USB_DTYPE_DEVICE_CAPABILITY_DESCRIPTOR,
|
||||
.bDevCapabilityType = USB_DC_TYPE_PLATFORM,
|
||||
.bReserved = 0,
|
||||
.PlatformCapabilityUUID = USB_WINUSB_PLATFORM_CAPABILITY_ID,
|
||||
.dwWindowsVersion = USB_WINUSB_WINDOWS_VERSION,
|
||||
.wMSOSDescriptorSetTotalLength = sizeof(usb_msos_descriptor_set_t),
|
||||
.bMS_VendorCode = USB_WINUSB_VENDOR_CODE,
|
||||
.bAltEnumCode = 0,
|
||||
},
|
||||
};
|
||||
|
||||
const usb_msos_descriptor_set_t usb_msos_descriptor_set = {
|
||||
.header =
|
||||
{
|
||||
.wLength = sizeof(usb_winusb_set_header_descriptor_t),
|
||||
.wDescriptorType = USB_WINUSB_SET_HEADER_DESCRIPTOR,
|
||||
.dwWindowsVersion = USB_WINUSB_WINDOWS_VERSION,
|
||||
.wDescriptorSetTotalLength = sizeof(usb_msos_descriptor_set_t),
|
||||
},
|
||||
|
||||
.subset =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.wLength = sizeof(usb_winusb_subset_header_function_t),
|
||||
.wDescriptorType = USB_WINUSB_SUBSET_HEADER_FUNCTION,
|
||||
.bFirstInterface = USB_INTF_BULK,
|
||||
.bReserved = 0,
|
||||
.wSubsetLength = sizeof(usb_msos_descriptor_subset_t),
|
||||
},
|
||||
|
||||
.comp_id =
|
||||
{
|
||||
.wLength = sizeof(usb_winusb_feature_compatble_id_t),
|
||||
.wDescriptorType = USB_WINUSB_FEATURE_COMPATBLE_ID,
|
||||
.CompatibleID = "WINUSB\0\0",
|
||||
.SubCompatibleID = {0},
|
||||
},
|
||||
|
||||
.property =
|
||||
{
|
||||
.wLength = sizeof(usb_winusb_feature_reg_property_guids_t),
|
||||
.wDescriptorType = USB_WINUSB_FEATURE_REG_PROPERTY,
|
||||
.wPropertyDataType = USB_WINUSB_PROPERTY_DATA_TYPE_MULTI_SZ,
|
||||
.wPropertyNameLength =
|
||||
sizeof(usb_msos_descriptor_set.subset.property.PropertyName),
|
||||
.PropertyName = {'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0,
|
||||
'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0,
|
||||
'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0},
|
||||
.wPropertyDataLength =
|
||||
sizeof(usb_msos_descriptor_set.subset.property.PropertyData),
|
||||
.PropertyData = {'{', 0, 'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0,
|
||||
'A', 0, 'D', 0, '-', 0, '2', 0, '9', 0, '3', 0, 'B', 0,
|
||||
'-', 0, '4', 0, '6', 0, '6', 0, '3', 0, '-', 0, 'A', 0,
|
||||
'A', 0, '3', 0, '6', 0, '-', 0, '1', 0, 'A', 0, 'A', 0,
|
||||
'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0,
|
||||
'7', 0, '6', 0, '}', 0, 0, 0, 0, 0},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FuriSemaphore* semaphore_v1;
|
||||
FuriSemaphore* semaphore_v2;
|
||||
FuriSemaphore* semaphore_cdc;
|
||||
bool connected;
|
||||
usbd_device* usb_dev;
|
||||
DapStateCallback state_callback;
|
||||
DapRxCallback rx_callback_v1;
|
||||
DapRxCallback rx_callback_v2;
|
||||
DapRxCallback rx_callback_cdc;
|
||||
DapCDCControlLineCallback control_line_callback_cdc;
|
||||
DapCDCConfigCallback config_callback_cdc;
|
||||
void* context;
|
||||
void* context_cdc;
|
||||
} DAPState;
|
||||
|
||||
static DAPState dap_state = {
|
||||
.semaphore_v1 = NULL,
|
||||
.semaphore_v2 = NULL,
|
||||
.semaphore_cdc = NULL,
|
||||
.connected = false,
|
||||
.usb_dev = NULL,
|
||||
.state_callback = NULL,
|
||||
.rx_callback_v1 = NULL,
|
||||
.rx_callback_v2 = NULL,
|
||||
.rx_callback_cdc = NULL,
|
||||
.control_line_callback_cdc = NULL,
|
||||
.config_callback_cdc = NULL,
|
||||
.context = NULL,
|
||||
.context_cdc = NULL,
|
||||
};
|
||||
|
||||
static struct usb_cdc_line_coding cdc_config = {0};
|
||||
static uint8_t cdc_ctrl_line_state = 0;
|
||||
|
||||
#ifdef DAP_USB_LOG
|
||||
void furi_console_log_printf(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
|
||||
|
||||
void furi_console_log_printf(const char* format, ...) {
|
||||
char buffer[256];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
furi_hal_console_puts(buffer);
|
||||
furi_hal_console_puts("\r\n");
|
||||
UNUSED(format);
|
||||
}
|
||||
#else
|
||||
#define furi_console_log_printf(...)
|
||||
#endif
|
||||
|
||||
int32_t dap_v1_usb_tx(uint8_t* buffer, uint8_t size) {
|
||||
if((dap_state.semaphore_v1 == NULL) || (dap_state.connected == false)) return 0;
|
||||
|
||||
furi_check(furi_semaphore_acquire(dap_state.semaphore_v1, FuriWaitForever) == FuriStatusOk);
|
||||
|
||||
if(dap_state.connected) {
|
||||
int32_t len = usbd_ep_write(dap_state.usb_dev, DAP_HID_EP_IN, buffer, size);
|
||||
furi_console_log_printf("v1 tx %ld", len);
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size) {
|
||||
if((dap_state.semaphore_v2 == NULL) || (dap_state.connected == false)) return 0;
|
||||
|
||||
furi_check(furi_semaphore_acquire(dap_state.semaphore_v2, FuriWaitForever) == FuriStatusOk);
|
||||
|
||||
if(dap_state.connected) {
|
||||
int32_t len = usbd_ep_write(dap_state.usb_dev, DAP_HID_EP_BULK_IN, buffer, size);
|
||||
furi_console_log_printf("v2 tx %ld", len);
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size) {
|
||||
if((dap_state.semaphore_cdc == NULL) || (dap_state.connected == false)) return 0;
|
||||
|
||||
furi_check(furi_semaphore_acquire(dap_state.semaphore_cdc, FuriWaitForever) == FuriStatusOk);
|
||||
|
||||
if(dap_state.connected) {
|
||||
int32_t len = usbd_ep_write(dap_state.usb_dev, HID_EP_IN | DAP_CDC_EP_SEND, buffer, size);
|
||||
furi_console_log_printf("cdc tx %ld", len);
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void dap_v1_usb_set_rx_callback(DapRxCallback callback) {
|
||||
dap_state.rx_callback_v1 = callback;
|
||||
}
|
||||
|
||||
void dap_v2_usb_set_rx_callback(DapRxCallback callback) {
|
||||
dap_state.rx_callback_v2 = callback;
|
||||
}
|
||||
|
||||
void dap_cdc_usb_set_rx_callback(DapRxCallback callback) {
|
||||
dap_state.rx_callback_cdc = callback;
|
||||
}
|
||||
|
||||
void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback) {
|
||||
dap_state.control_line_callback_cdc = callback;
|
||||
}
|
||||
|
||||
void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback) {
|
||||
dap_state.config_callback_cdc = callback;
|
||||
}
|
||||
|
||||
void dap_cdc_usb_set_context(void* context) {
|
||||
dap_state.context_cdc = context;
|
||||
}
|
||||
|
||||
void dap_common_usb_set_context(void* context) {
|
||||
dap_state.context = context;
|
||||
}
|
||||
|
||||
void dap_common_usb_set_state_callback(DapStateCallback callback) {
|
||||
dap_state.state_callback = callback;
|
||||
}
|
||||
|
||||
static void* dap_usb_alloc_string_descr(const char* str) {
|
||||
furi_assert(str);
|
||||
|
||||
uint8_t len = strlen(str);
|
||||
uint8_t wlen = (len + 1) * sizeof(uint16_t);
|
||||
struct usb_string_descriptor* dev_str_desc = malloc(wlen);
|
||||
dev_str_desc->bLength = wlen;
|
||||
dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
dev_str_desc->wString[i] = str[i];
|
||||
}
|
||||
|
||||
return dev_str_desc;
|
||||
}
|
||||
|
||||
void dap_common_usb_alloc_name(const char* name) {
|
||||
dev_serial_descr = dap_usb_alloc_string_descr(name);
|
||||
}
|
||||
|
||||
void dap_common_usb_free_name() {
|
||||
free(dev_serial_descr);
|
||||
}
|
||||
|
||||
static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
|
||||
static void hid_deinit(usbd_device* dev);
|
||||
static void hid_on_wakeup(usbd_device* dev);
|
||||
static void hid_on_suspend(usbd_device* dev);
|
||||
|
||||
static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg);
|
||||
static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
|
||||
|
||||
FuriHalUsbInterface dap_v2_usb_hid = {
|
||||
.init = hid_init,
|
||||
.deinit = hid_deinit,
|
||||
.wakeup = hid_on_wakeup,
|
||||
.suspend = hid_on_suspend,
|
||||
.dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
|
||||
.cfg_descr = (void*)&hid_cfg_desc,
|
||||
};
|
||||
|
||||
static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
|
||||
UNUSED(intf);
|
||||
UNUSED(ctx);
|
||||
|
||||
dap_v2_usb_hid.str_manuf_descr = (void*)&dev_manuf_descr;
|
||||
dap_v2_usb_hid.str_prod_descr = (void*)&dev_prod_descr;
|
||||
dap_v2_usb_hid.str_serial_descr = (void*)dev_serial_descr;
|
||||
|
||||
dap_state.usb_dev = dev;
|
||||
if(dap_state.semaphore_v1 == NULL) dap_state.semaphore_v1 = furi_semaphore_alloc(1, 1);
|
||||
if(dap_state.semaphore_v2 == NULL) dap_state.semaphore_v2 = furi_semaphore_alloc(1, 1);
|
||||
if(dap_state.semaphore_cdc == NULL) dap_state.semaphore_cdc = furi_semaphore_alloc(1, 1);
|
||||
|
||||
usb_hid.dev_descr->idVendor = DAP_HID_VID;
|
||||
usb_hid.dev_descr->idProduct = DAP_HID_PID;
|
||||
|
||||
usbd_reg_config(dev, hid_ep_config);
|
||||
usbd_reg_control(dev, hid_control);
|
||||
|
||||
usbd_connect(dev, true);
|
||||
}
|
||||
|
||||
static bool deinit_flag = false;
|
||||
|
||||
void dap_common_wait_for_deinit() {
|
||||
while(!deinit_flag) {
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_deinit(usbd_device* dev) {
|
||||
dap_state.usb_dev = NULL;
|
||||
|
||||
furi_semaphore_free(dap_state.semaphore_v1);
|
||||
furi_semaphore_free(dap_state.semaphore_v2);
|
||||
furi_semaphore_free(dap_state.semaphore_cdc);
|
||||
dap_state.semaphore_v1 = NULL;
|
||||
dap_state.semaphore_v2 = NULL;
|
||||
dap_state.semaphore_cdc = NULL;
|
||||
|
||||
usbd_reg_config(dev, NULL);
|
||||
usbd_reg_control(dev, NULL);
|
||||
|
||||
free(usb_hid.str_manuf_descr);
|
||||
free(usb_hid.str_prod_descr);
|
||||
|
||||
FURI_SW_MEMBARRIER();
|
||||
deinit_flag = true;
|
||||
}
|
||||
|
||||
static void hid_on_wakeup(usbd_device* dev) {
|
||||
UNUSED(dev);
|
||||
if(!dap_state.connected) {
|
||||
dap_state.connected = true;
|
||||
if(dap_state.state_callback != NULL) {
|
||||
dap_state.state_callback(dap_state.connected, dap_state.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_on_suspend(usbd_device* dev) {
|
||||
UNUSED(dev);
|
||||
if(dap_state.connected) {
|
||||
dap_state.connected = false;
|
||||
if(dap_state.state_callback != NULL) {
|
||||
dap_state.state_callback(dap_state.connected, dap_state.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t dap_v1_usb_rx(uint8_t* buffer, size_t size) {
|
||||
size_t len = 0;
|
||||
|
||||
if(dap_state.connected) {
|
||||
len = usbd_ep_read(dap_state.usb_dev, DAP_HID_EP_OUT, buffer, size);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t dap_v2_usb_rx(uint8_t* buffer, size_t size) {
|
||||
size_t len = 0;
|
||||
|
||||
if(dap_state.connected) {
|
||||
len = usbd_ep_read(dap_state.usb_dev, DAP_HID_EP_BULK_OUT, buffer, size);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size) {
|
||||
size_t len = 0;
|
||||
|
||||
if(dap_state.connected) {
|
||||
len = usbd_ep_read(dap_state.usb_dev, HID_EP_OUT | DAP_CDC_EP_RECV, buffer, size);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void hid_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
||||
UNUSED(dev);
|
||||
UNUSED(ep);
|
||||
|
||||
switch(event) {
|
||||
case usbd_evt_eptx:
|
||||
furi_semaphore_release(dap_state.semaphore_v1);
|
||||
furi_console_log_printf("hid tx complete");
|
||||
break;
|
||||
case usbd_evt_eprx:
|
||||
if(dap_state.rx_callback_v1 != NULL) {
|
||||
dap_state.rx_callback_v1(dap_state.context);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
furi_console_log_printf("hid %d, %d", event, ep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_txrx_ep_bulk_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
||||
UNUSED(dev);
|
||||
UNUSED(ep);
|
||||
|
||||
switch(event) {
|
||||
case usbd_evt_eptx:
|
||||
furi_semaphore_release(dap_state.semaphore_v2);
|
||||
furi_console_log_printf("bulk tx complete");
|
||||
break;
|
||||
case usbd_evt_eprx:
|
||||
if(dap_state.rx_callback_v2 != NULL) {
|
||||
dap_state.rx_callback_v2(dap_state.context);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
furi_console_log_printf("bulk %d, %d", event, ep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
||||
UNUSED(dev);
|
||||
UNUSED(ep);
|
||||
|
||||
switch(event) {
|
||||
case usbd_evt_eptx:
|
||||
furi_semaphore_release(dap_state.semaphore_cdc);
|
||||
furi_console_log_printf("cdc tx complete");
|
||||
break;
|
||||
case usbd_evt_eprx:
|
||||
if(dap_state.rx_callback_cdc != NULL) {
|
||||
dap_state.rx_callback_cdc(dap_state.context_cdc);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
furi_console_log_printf("cdc %d, %d", event, ep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg) {
|
||||
switch(cfg) {
|
||||
case EP_CFG_DECONFIGURE:
|
||||
usbd_ep_deconfig(dev, DAP_HID_EP_OUT);
|
||||
usbd_ep_deconfig(dev, DAP_HID_EP_IN);
|
||||
usbd_ep_deconfig(dev, DAP_HID_EP_BULK_IN);
|
||||
usbd_ep_deconfig(dev, DAP_HID_EP_BULK_OUT);
|
||||
usbd_ep_deconfig(dev, HID_EP_IN | DAP_CDC_EP_COMM);
|
||||
usbd_ep_deconfig(dev, HID_EP_IN | DAP_CDC_EP_SEND);
|
||||
usbd_ep_deconfig(dev, HID_EP_OUT | DAP_CDC_EP_RECV);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_OUT, NULL);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_IN, NULL);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_IN, NULL);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_OUT, NULL);
|
||||
usbd_reg_endpoint(dev, HID_EP_IN | DAP_CDC_EP_SEND, 0);
|
||||
usbd_reg_endpoint(dev, HID_EP_OUT | DAP_CDC_EP_RECV, 0);
|
||||
return usbd_ack;
|
||||
case EP_CFG_CONFIGURE:
|
||||
usbd_ep_config(dev, DAP_HID_EP_IN, USB_EPTYPE_INTERRUPT, DAP_HID_EP_SIZE);
|
||||
usbd_ep_config(dev, DAP_HID_EP_OUT, USB_EPTYPE_INTERRUPT, DAP_HID_EP_SIZE);
|
||||
usbd_ep_config(dev, DAP_HID_EP_BULK_OUT, USB_EPTYPE_BULK, DAP_HID_EP_SIZE);
|
||||
usbd_ep_config(dev, DAP_HID_EP_BULK_IN, USB_EPTYPE_BULK, DAP_HID_EP_SIZE);
|
||||
usbd_ep_config(dev, HID_EP_OUT | DAP_CDC_EP_RECV, USB_EPTYPE_BULK, DAP_CDC_EP_SIZE);
|
||||
usbd_ep_config(dev, HID_EP_IN | DAP_CDC_EP_SEND, USB_EPTYPE_BULK, DAP_CDC_EP_SIZE);
|
||||
usbd_ep_config(dev, HID_EP_IN | DAP_CDC_EP_COMM, USB_EPTYPE_INTERRUPT, DAP_CDC_EP_SIZE);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_IN, hid_txrx_ep_callback);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_OUT, hid_txrx_ep_callback);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_OUT, hid_txrx_ep_bulk_callback);
|
||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_IN, hid_txrx_ep_bulk_callback);
|
||||
usbd_reg_endpoint(dev, HID_EP_OUT | DAP_CDC_EP_RECV, cdc_txrx_ep_callback);
|
||||
usbd_reg_endpoint(dev, HID_EP_IN | DAP_CDC_EP_SEND, cdc_txrx_ep_callback);
|
||||
// usbd_ep_write(dev, DAP_HID_EP_IN, NULL, 0);
|
||||
// usbd_ep_write(dev, DAP_HID_EP_BULK_IN, NULL, 0);
|
||||
// usbd_ep_write(dev, HID_EP_IN | DAP_CDC_EP_SEND, NULL, 0);
|
||||
return usbd_ack;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DAP_USB_LOG
|
||||
static void dump_request_type(uint8_t type) {
|
||||
switch(type & USB_REQ_DIRECTION) {
|
||||
case USB_REQ_HOSTTODEV:
|
||||
furi_hal_console_puts("host to dev, ");
|
||||
break;
|
||||
case USB_REQ_DEVTOHOST:
|
||||
furi_hal_console_puts("dev to host, ");
|
||||
break;
|
||||
}
|
||||
|
||||
switch(type & USB_REQ_TYPE) {
|
||||
case USB_REQ_STANDARD:
|
||||
furi_hal_console_puts("standard, ");
|
||||
break;
|
||||
case USB_REQ_CLASS:
|
||||
furi_hal_console_puts("class, ");
|
||||
break;
|
||||
case USB_REQ_VENDOR:
|
||||
furi_hal_console_puts("vendor, ");
|
||||
break;
|
||||
}
|
||||
|
||||
switch(type & USB_REQ_RECIPIENT) {
|
||||
case USB_REQ_DEVICE:
|
||||
furi_hal_console_puts("device");
|
||||
break;
|
||||
case USB_REQ_INTERFACE:
|
||||
furi_hal_console_puts("interface");
|
||||
break;
|
||||
case USB_REQ_ENDPOINT:
|
||||
furi_hal_console_puts("endpoint");
|
||||
break;
|
||||
case USB_REQ_OTHER:
|
||||
furi_hal_console_puts("other");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_hal_console_puts("\r\n");
|
||||
}
|
||||
#else
|
||||
#define dump_request_type(...)
|
||||
#endif
|
||||
|
||||
static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
|
||||
UNUSED(callback);
|
||||
|
||||
dump_request_type(req->bmRequestType);
|
||||
furi_console_log_printf(
|
||||
"control: RT %02x, R %02x, V %04x, I %04x, L %04x",
|
||||
req->bmRequestType,
|
||||
req->bRequest,
|
||||
req->wValue,
|
||||
req->wIndex,
|
||||
req->wLength);
|
||||
|
||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE | USB_REQ_DIRECTION) & req->bmRequestType) ==
|
||||
(USB_REQ_STANDARD | USB_REQ_VENDOR | USB_REQ_DEVTOHOST)) {
|
||||
// vendor request, device to host
|
||||
furi_console_log_printf("vendor request");
|
||||
if(USB_WINUSB_VENDOR_CODE == req->bRequest) {
|
||||
// WINUSB request
|
||||
if(USB_WINUSB_DESCRIPTOR_INDEX == req->wIndex) {
|
||||
furi_console_log_printf("WINUSB descriptor");
|
||||
uint16_t length = req->wLength;
|
||||
if(length > sizeof(usb_msos_descriptor_set_t)) {
|
||||
length = sizeof(usb_msos_descriptor_set_t);
|
||||
}
|
||||
|
||||
dev->status.data_ptr = (uint8_t*)&usb_msos_descriptor_set;
|
||||
dev->status.data_count = length;
|
||||
return usbd_ack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
||||
(USB_REQ_STANDARD | USB_REQ_DEVICE)) {
|
||||
// device request
|
||||
if(req->bRequest == USB_STD_GET_DESCRIPTOR) {
|
||||
const uint8_t dtype = req->wValue >> 8;
|
||||
const uint8_t dnumber = req->wValue & 0xFF;
|
||||
// get string descriptor
|
||||
if(USB_DTYPE_STRING == dtype) {
|
||||
if(dnumber == USB_STR_CMSIS_DAP_V1) {
|
||||
furi_console_log_printf("str CMSIS-DAP v1");
|
||||
dev->status.data_ptr = (uint8_t*)&dev_dap_v1_descr;
|
||||
dev->status.data_count = dev_dap_v1_descr.bLength;
|
||||
return usbd_ack;
|
||||
} else if(dnumber == USB_STR_CMSIS_DAP_V2) {
|
||||
furi_console_log_printf("str CMSIS-DAP v2");
|
||||
dev->status.data_ptr = (uint8_t*)&dev_dap_v2_descr;
|
||||
dev->status.data_count = dev_dap_v2_descr.bLength;
|
||||
return usbd_ack;
|
||||
} else if(dnumber == USB_STR_COM_PORT) {
|
||||
furi_console_log_printf("str COM port");
|
||||
dev->status.data_ptr = (uint8_t*)&dev_com_descr;
|
||||
dev->status.data_count = dev_com_descr.bLength;
|
||||
return usbd_ack;
|
||||
}
|
||||
} else if(USB_DTYPE_BINARY_OBJECT_STORE == dtype) {
|
||||
furi_console_log_printf("BOS descriptor");
|
||||
uint16_t length = req->wLength;
|
||||
if(length > sizeof(usb_bos_hierarchy_t)) {
|
||||
length = sizeof(usb_bos_hierarchy_t);
|
||||
}
|
||||
dev->status.data_ptr = (uint8_t*)&usb_bos_hierarchy;
|
||||
dev->status.data_count = length;
|
||||
return usbd_ack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
||||
(USB_REQ_INTERFACE | USB_REQ_CLASS) &&
|
||||
req->wIndex == 0) {
|
||||
// class request
|
||||
switch(req->bRequest) {
|
||||
// get hid descriptor
|
||||
case USB_HID_GETREPORT:
|
||||
furi_console_log_printf("get report");
|
||||
return usbd_fail;
|
||||
// set hid idle
|
||||
case USB_HID_SETIDLE:
|
||||
furi_console_log_printf("set idle");
|
||||
return usbd_ack;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
||||
(USB_REQ_INTERFACE | USB_REQ_CLASS) &&
|
||||
req->wIndex == 2) {
|
||||
// class request
|
||||
switch(req->bRequest) {
|
||||
// control line state
|
||||
case USB_CDC_SET_CONTROL_LINE_STATE:
|
||||
furi_console_log_printf("set control line state");
|
||||
cdc_ctrl_line_state = req->wValue;
|
||||
if(dap_state.control_line_callback_cdc != NULL) {
|
||||
dap_state.control_line_callback_cdc(cdc_ctrl_line_state, dap_state.context_cdc);
|
||||
}
|
||||
return usbd_ack;
|
||||
// set cdc line coding
|
||||
case USB_CDC_SET_LINE_CODING:
|
||||
furi_console_log_printf("set line coding");
|
||||
memcpy(&cdc_config, req->data, sizeof(cdc_config));
|
||||
if(dap_state.config_callback_cdc != NULL) {
|
||||
dap_state.config_callback_cdc(&cdc_config, dap_state.context_cdc);
|
||||
}
|
||||
return usbd_ack;
|
||||
// get cdc line coding
|
||||
case USB_CDC_GET_LINE_CODING:
|
||||
furi_console_log_printf("get line coding");
|
||||
dev->status.data_ptr = &cdc_config;
|
||||
dev->status.data_count = sizeof(cdc_config);
|
||||
return usbd_ack;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
||||
(USB_REQ_INTERFACE | USB_REQ_STANDARD) &&
|
||||
req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) {
|
||||
// standard request
|
||||
switch(req->wValue >> 8) {
|
||||
// get hid descriptor
|
||||
case USB_DTYPE_HID:
|
||||
furi_console_log_printf("get hid descriptor");
|
||||
dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.hid);
|
||||
dev->status.data_count = sizeof(hid_cfg_desc.hid);
|
||||
return usbd_ack;
|
||||
// get hid report descriptor
|
||||
case USB_DTYPE_HID_REPORT:
|
||||
furi_console_log_printf("get hid report descriptor");
|
||||
dev->status.data_ptr = (uint8_t*)hid_report_desc;
|
||||
dev->status.data_count = sizeof(hid_report_desc);
|
||||
return usbd_ack;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return usbd_fail;
|
||||
}
|
55
applications/plugins/dap_link/usb/dap_v2_usb.h
Normal file
55
applications/plugins/dap_link/usb/dap_v2_usb.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include <furi_hal_usb.h>
|
||||
#include <usb_cdc.h>
|
||||
|
||||
extern FuriHalUsbInterface dap_v2_usb_hid;
|
||||
|
||||
// receive callback type
|
||||
typedef void (*DapRxCallback)(void* context);
|
||||
|
||||
typedef void (*DapStateCallback)(bool state, void* context);
|
||||
|
||||
/************************************ V1 ***************************************/
|
||||
|
||||
int32_t dap_v1_usb_tx(uint8_t* buffer, uint8_t size);
|
||||
|
||||
size_t dap_v1_usb_rx(uint8_t* buffer, size_t size);
|
||||
|
||||
void dap_v1_usb_set_rx_callback(DapRxCallback callback);
|
||||
|
||||
/************************************ V2 ***************************************/
|
||||
|
||||
int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size);
|
||||
|
||||
size_t dap_v2_usb_rx(uint8_t* buffer, size_t size);
|
||||
|
||||
void dap_v2_usb_set_rx_callback(DapRxCallback callback);
|
||||
|
||||
/************************************ CDC **************************************/
|
||||
|
||||
typedef void (*DapCDCControlLineCallback)(uint8_t state, void* context);
|
||||
typedef void (*DapCDCConfigCallback)(struct usb_cdc_line_coding* config, void* context);
|
||||
|
||||
int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size);
|
||||
|
||||
size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size);
|
||||
|
||||
void dap_cdc_usb_set_rx_callback(DapRxCallback callback);
|
||||
|
||||
void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback);
|
||||
|
||||
void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback);
|
||||
|
||||
void dap_cdc_usb_set_context(void* context);
|
||||
|
||||
/*********************************** Common ************************************/
|
||||
|
||||
void dap_common_usb_set_context(void* context);
|
||||
|
||||
void dap_common_usb_set_state_callback(DapStateCallback callback);
|
||||
|
||||
void dap_common_usb_alloc_name(const char* name);
|
||||
|
||||
void dap_common_usb_free_name();
|
||||
|
||||
void dap_common_wait_for_deinit();
|
143
applications/plugins/dap_link/usb/usb_winusb.h
Normal file
143
applications/plugins/dap_link/usb/usb_winusb.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
/*- Definitions -------------------------------------------------------------*/
|
||||
|
||||
#define USB_PACK __attribute__((packed))
|
||||
|
||||
#define USB_WINUSB_VENDOR_CODE 0x20
|
||||
|
||||
#define USB_WINUSB_WINDOWS_VERSION 0x06030000 // Windows 8.1
|
||||
|
||||
#define USB_WINUSB_PLATFORM_CAPABILITY_ID \
|
||||
{ \
|
||||
0xdf, 0x60, 0xdd, 0xd8, 0x89, 0x45, 0xc7, 0x4c, 0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, \
|
||||
0x9f \
|
||||
}
|
||||
|
||||
enum // WinUSB Microsoft OS 2.0 descriptor request codes
|
||||
{
|
||||
USB_WINUSB_DESCRIPTOR_INDEX = 0x07,
|
||||
USB_WINUSB_SET_ALT_ENUMERATION = 0x08,
|
||||
};
|
||||
|
||||
enum // wDescriptorType
|
||||
{
|
||||
USB_WINUSB_SET_HEADER_DESCRIPTOR = 0x00,
|
||||
USB_WINUSB_SUBSET_HEADER_CONFIGURATION = 0x01,
|
||||
USB_WINUSB_SUBSET_HEADER_FUNCTION = 0x02,
|
||||
USB_WINUSB_FEATURE_COMPATBLE_ID = 0x03,
|
||||
USB_WINUSB_FEATURE_REG_PROPERTY = 0x04,
|
||||
USB_WINUSB_FEATURE_MIN_RESUME_TIME = 0x05,
|
||||
USB_WINUSB_FEATURE_MODEL_ID = 0x06,
|
||||
USB_WINUSB_FEATURE_CCGP_DEVICE = 0x07,
|
||||
USB_WINUSB_FEATURE_VENDOR_REVISION = 0x08,
|
||||
};
|
||||
|
||||
enum // wPropertyDataType
|
||||
{
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_SZ = 1,
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_EXPAND_SZ = 2,
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_BINARY = 3,
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_DWORD_LITTLE_ENDIAN = 4,
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_DWORD_BIG_ENDIAN = 5,
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_LINK = 6,
|
||||
USB_WINUSB_PROPERTY_DATA_TYPE_MULTI_SZ = 7,
|
||||
};
|
||||
|
||||
/*- Types BOS -------------------------------------------------------------------*/
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t wTotalLength;
|
||||
uint8_t bNumDeviceCaps;
|
||||
} usb_binary_object_store_descriptor_t;
|
||||
|
||||
/*- Types WinUSB -------------------------------------------------------------------*/
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDevCapabilityType;
|
||||
uint8_t bReserved;
|
||||
uint8_t PlatformCapabilityUUID[16];
|
||||
uint32_t dwWindowsVersion;
|
||||
uint16_t wMSOSDescriptorSetTotalLength;
|
||||
uint8_t bMS_VendorCode;
|
||||
uint8_t bAltEnumCode;
|
||||
} usb_winusb_capability_descriptor_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint32_t dwWindowsVersion;
|
||||
uint16_t wDescriptorSetTotalLength;
|
||||
} usb_winusb_set_header_descriptor_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint8_t bConfigurationValue;
|
||||
uint8_t bReserved;
|
||||
uint16_t wTotalLength;
|
||||
} usb_winusb_subset_header_configuration_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint8_t bFirstInterface;
|
||||
uint8_t bReserved;
|
||||
uint16_t wSubsetLength;
|
||||
} usb_winusb_subset_header_function_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint8_t CompatibleID[8];
|
||||
uint8_t SubCompatibleID[8];
|
||||
} usb_winusb_feature_compatble_id_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint16_t wPropertyDataType;
|
||||
//uint16_t wPropertyNameLength;
|
||||
//uint8_t PropertyName[...];
|
||||
//uint16_t wPropertyDataLength
|
||||
//uint8_t PropertyData[...];
|
||||
} usb_winusb_feature_reg_property_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint16_t wPropertyDataType;
|
||||
uint16_t wPropertyNameLength;
|
||||
uint8_t PropertyName[42];
|
||||
uint16_t wPropertyDataLength;
|
||||
uint8_t PropertyData[80];
|
||||
} usb_winusb_feature_reg_property_guids_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint8_t bResumeRecoveryTime;
|
||||
uint8_t bResumeSignalingTime;
|
||||
} usb_winusb_feature_min_resume_time_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint8_t ModelID[16];
|
||||
} usb_winusb_feature_model_id_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
} usb_winusb_feature_ccgp_device_t;
|
||||
|
||||
typedef struct USB_PACK {
|
||||
uint16_t wLength;
|
||||
uint16_t wDescriptorType;
|
||||
uint16_t VendorRevision;
|
||||
} usb_winusb_feature_vendor_revision_t;
|
Reference in New Issue
Block a user