978 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			978 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#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);
 | 
						|
 | 
						|
    size_t len = strlen(str);
 | 
						|
    size_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(size_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);
 | 
						|
 | 
						|
    usbd_reg_config(dev, hid_ep_config);
 | 
						|
    usbd_reg_control(dev, hid_control);
 | 
						|
 | 
						|
    usbd_connect(dev, true);
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
}
 |