Initial, very incomplete, toolbox interface.
This commit is contained in:
		
							parent
							
								
									794a547414
								
							
						
					
					
						commit
						f9e28ca4c7
					
				|  | @ -17,6 +17,7 @@ add_executable(ploopy_headphones | |||
|     fix16.c | ||||
|     bqf.c | ||||
|     user.c | ||||
|     configuration_manager.c | ||||
| ) | ||||
| 
 | ||||
| target_include_directories(ploopy_headphones PRIVATE ${CMAKE_SOURCE_DIR}) | ||||
|  | @ -49,5 +50,6 @@ target_link_libraries(ploopy_headphones | |||
|     hardware_sync | ||||
|     pico_stdlib | ||||
|     pico_multicore | ||||
|     pico_unique_id | ||||
|     usb_device | ||||
| ) | ||||
|  |  | |||
|  | @ -0,0 +1,64 @@ | |||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <inttypes.h> | ||||
| #include "pico/stdlib.h" | ||||
| #include "pico/usb_device.h" | ||||
| #include "configuration_manager.h" | ||||
| 
 | ||||
| static uint8_t config_buffer[2][512]; | ||||
| static uint8_t active_index = 0; | ||||
| static bool config_dirty = false; | ||||
| static uint16_t write_offset = 0; | ||||
| static uint16_t read_offset = 0; | ||||
| static uint16_t config_length = 0; | ||||
| 
 | ||||
| typedef struct _TLVHeader { | ||||
|     uint16_t type; | ||||
|     uint16_t length; | ||||
| } TLVHeader; | ||||
| 
 | ||||
| typedef struct _ConfigHeaderTLV { | ||||
|     struct _TLVHeader header; | ||||
|     uint32_t config_magic; | ||||
|     uint16_t config_version; | ||||
|     uint16_t reserved; | ||||
| } ConfigHeaderTLV; | ||||
| 
 | ||||
| void load_config() | ||||
| { | ||||
|     // Copy data from flash
 | ||||
|     uint8_t index = active_index ? 0 : 1; | ||||
|     // Load data
 | ||||
|     active_index = index; | ||||
|     config_dirty = true; | ||||
| } | ||||
| 
 | ||||
| void save_config() | ||||
| { | ||||
|     // Write data to flash
 | ||||
| } | ||||
| 
 | ||||
| void config_in_packet(struct usb_endpoint *ep) { | ||||
|     assert(ep->current_transfer); | ||||
|     struct usb_buffer *buffer = usb_current_in_packet_buffer(ep); | ||||
|     assert(buffer->data_max >= 3); | ||||
|     buffer->data_len = 0; | ||||
| 
 | ||||
|     printf("Config In Packet: Buffer Len: %d, Max: %d\n", buffer->data_len, buffer->data_max); | ||||
|     memcpy(buffer->data, "Config In Packet", 17); | ||||
|     buffer->data_len = 64; | ||||
| 
 | ||||
|     usb_grow_transfer(ep->current_transfer, 1); | ||||
|     usb_packet_done(ep); | ||||
| } | ||||
| 
 | ||||
| void config_out_packet(struct usb_endpoint *ep) { | ||||
|     struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep); | ||||
| 
 | ||||
|     printf("Config Out Packet >>%s<< %d %d %d %d\n", usb_buffer->data, usb_buffer->data_len, ep->current_transfer->completed, ep->current_transfer->remaining_packets_to_handle, ep->current_transfer->remaining_packets_to_submit); | ||||
| 
 | ||||
|     usb_grow_transfer(ep->current_transfer, 1); | ||||
|     usb_packet_done(ep); | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| #ifndef CONFIGURATION_MANAGER_H | ||||
| #define CONFIGURATION_MANAGER_H | ||||
| struct usb_endpoint; | ||||
| void config_in_packet(struct usb_endpoint *ep); | ||||
| void config_out_packet(struct usb_endpoint *ep); | ||||
| 
 | ||||
| #endif // CONFIGURATION_MANAGER_H
 | ||||
|  | @ -33,8 +33,10 @@ | |||
| 
 | ||||
| #include "pico/stdlib.h" | ||||
| #include "pico/usb_device.h" | ||||
| #include "pico/usb_stream_helper.h" | ||||
| #include "pico/multicore.h" | ||||
| #include "pico/bootrom.h" | ||||
| #include "pico/unique_id.h" | ||||
| #include "AudioClassCommon.h" | ||||
| 
 | ||||
| #include "run.h" | ||||
|  | @ -42,6 +44,7 @@ | |||
| #include "i2s.h" | ||||
| #include "bqf.h" | ||||
| #include "user.h" | ||||
| #include "configuration_manager.h" | ||||
| 
 | ||||
| i2s_obj_t i2s_write_obj; | ||||
| static uint8_t *userbuf; | ||||
|  | @ -66,8 +69,11 @@ static struct { | |||
|     .freq = 48000, | ||||
| }; | ||||
| 
 | ||||
| static char spi_serial_number[17] = ""; | ||||
| 
 | ||||
| enum vendor_cmds { | ||||
|     REBOOT_BOOTLOADER = 0 | ||||
|     REBOOT_BOOTLOADER = 0, | ||||
|     MICROSOFT_COMPATIBLE_ID_FEATURE_DESRIPTOR | ||||
| }; | ||||
| 
 | ||||
| int main(void) { | ||||
|  | @ -183,6 +189,11 @@ void core1_entry() { | |||
| void setup() { | ||||
|     set_sys_clock_khz(SYSTEM_FREQ / 1000, true); | ||||
|     sleep_ms(100); | ||||
|     stdio_init_all(); | ||||
| 
 | ||||
|     pico_get_unique_board_id_string(spi_serial_number, 17); | ||||
|     descriptor_strings[2] = spi_serial_number; | ||||
|     printf("Serial Number: %s (%p)\n", descriptor_strings[2], descriptor_strings[2]); | ||||
| 
 | ||||
|     userbuf = malloc(sizeof(uint8_t) * RINGBUF_LEN_IN_BYTES); | ||||
|      | ||||
|  | @ -296,7 +307,7 @@ static const audio_device_config ad_conf = { | |||
|         .bLength = sizeof(ad_conf.descriptor), | ||||
|         .bDescriptorType = DTYPE_Configuration, | ||||
|         .wTotalLength = sizeof(ad_conf), | ||||
|         .bNumInterfaces = 2, | ||||
|         .bNumInterfaces = 3, | ||||
|         .bConfigurationValue = 0x01, | ||||
|         .iConfiguration = 0x00, | ||||
|         .bmAttributes = 0x80, | ||||
|  | @ -439,16 +450,45 @@ static const audio_device_config ad_conf = { | |||
|         .bRefresh = 2, | ||||
|         .bSyncAddr = 0, | ||||
|     }, | ||||
|     .configuration_interface = { | ||||
|         .bLength = sizeof(ad_conf.configuration_interface), | ||||
|         .bDescriptorType = DTYPE_Interface, | ||||
|         .bInterfaceNumber = 0x02, | ||||
|         .bAlternateSetting = 0x00, | ||||
|         .bNumEndpoints = 0x02, | ||||
|         .bInterfaceClass = 0xff, // Vendor Specific
 | ||||
|         .bInterfaceSubClass = 0, | ||||
|         .bInterfaceProtocol = 0, | ||||
|         .iInterface = 0x00 | ||||
|     }, | ||||
|     .ep3 = { | ||||
|         .bLength = sizeof(ad_conf.ep3), | ||||
|         .bDescriptorType = 0x05, | ||||
|         .bEndpointAddress = 0x03, | ||||
|         .bmAttributes = 0x2, | ||||
|         .wMaxPacketSize = 0x40, | ||||
|         .bInterval = 0x0 | ||||
|     }, | ||||
|     .ep4 = { | ||||
|         .bLength = sizeof(ad_conf.ep3), | ||||
|         .bDescriptorType = 0x05, | ||||
|         .bEndpointAddress = 0x84, | ||||
|         .bmAttributes = 0x2, | ||||
|         .wMaxPacketSize = 0x40, | ||||
|         .bInterval = 0x0 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| static struct usb_interface ac_interface; | ||||
| static struct usb_interface as_op_interface; | ||||
| static struct usb_endpoint ep_op_out, ep_op_sync; | ||||
| static struct usb_interface configuration_interface; | ||||
| static struct usb_endpoint ep_configuration_in, ep_configuration_out; | ||||
| 
 | ||||
| static const struct usb_device_descriptor boot_device_descriptor = { | ||||
|     .bLength            = 18, | ||||
|     .bDescriptorType    = 0x01, | ||||
|     .bcdUSB             = 0x0110, | ||||
|     .bcdUSB             = 0x0210, | ||||
|     .bDeviceClass       = 0x00, | ||||
|     .bDeviceSubClass    = 0x00, | ||||
|     .bDeviceProtocol    = 0x00, | ||||
|  | @ -520,6 +560,19 @@ static const struct usb_transfer_type as_sync_transfer_type = { | |||
| static struct usb_transfer as_transfer; | ||||
| static struct usb_transfer as_sync_transfer; | ||||
| 
 | ||||
| static const struct usb_transfer_type config_in_transfer_type = { | ||||
|     .on_packet = config_in_packet, | ||||
|     .initial_packet_count = 1, | ||||
| }; | ||||
| 
 | ||||
| static const struct usb_transfer_type config_out_transfer_type = { | ||||
|     .on_packet = config_out_packet, | ||||
|     .initial_packet_count = 1, | ||||
| }; | ||||
| 
 | ||||
| static struct usb_transfer config_in_transfer; | ||||
| static struct usb_transfer config_out_transfer; | ||||
| 
 | ||||
| static bool do_get_current(struct usb_setup_packet *setup) { | ||||
|     if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) { | ||||
|         switch (setup->wValue >> 8u) { | ||||
|  | @ -693,8 +746,112 @@ static bool do_set_current(struct usb_setup_packet *setup) { | |||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static void _tf_send_control_in_ack(__unused struct usb_endpoint *endpoint, __unused struct usb_transfer *transfer) { | ||||
|     assert(endpoint == &usb_control_in); | ||||
|     assert(transfer == &_control_in_transfer); | ||||
|     usb_debug("_tf_setup_control_ack\n"); | ||||
|     static struct usb_transfer _control_out_transfer; | ||||
|     usb_start_empty_transfer(usb_get_control_out_endpoint(), &_control_out_transfer, 0); | ||||
| } | ||||
| 
 | ||||
| static struct usb_stream_transfer _control_in_stream_transfer; | ||||
| #define _control_in_transfer _control_in_stream_transfer.core | ||||
| static struct usb_stream_transfer_funcs control_stream_funcs = { | ||||
|         .on_chunk = usb_stream_noop_on_chunk, | ||||
|         .on_packet_complete = usb_stream_noop_on_packet_complete | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #define TU_U16_HIGH(_u16)      ((uint8_t) (((_u16) >> 8) & 0x00ff)) | ||||
| #define TU_U16_LOW(_u16)       ((uint8_t) ((_u16)       & 0x00ff)) | ||||
| #define U16_TO_U8S_BE(_u16)    TU_U16_HIGH(_u16), TU_U16_LOW(_u16) | ||||
| #define U16_TO_U8S_LE(_u16)    TU_U16_LOW(_u16), TU_U16_HIGH(_u16) | ||||
| #define TU_U32_BYTE3(_u32)     ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB
 | ||||
| #define TU_U32_BYTE2(_u32)     ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff)) | ||||
| #define TU_U32_BYTE1(_u32)     ((uint8_t) ((((uint32_t) _u32) >>  8) & 0x000000ff)) | ||||
| #define TU_U32_BYTE0(_u32)     ((uint8_t) (((uint32_t)  _u32)        & 0x000000ff)) // LSB
 | ||||
| 
 | ||||
| #define U32_TO_U8S_BE(_u32)    TU_U32_BYTE3(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE0(_u32) | ||||
| #define U32_TO_U8S_LE(_u32)    TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32) | ||||
| 
 | ||||
| #define MS_OS_20_DESC_LEN  0xB2 | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   MS_OS_20_SET_HEADER_DESCRIPTOR       = 0x00, | ||||
|   MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, | ||||
|   MS_OS_20_SUBSET_HEADER_FUNCTION      = 0x02, | ||||
|   MS_OS_20_FEATURE_COMPATBLE_ID        = 0x03, | ||||
|   MS_OS_20_FEATURE_REG_PROPERTY        = 0x04, | ||||
|   MS_OS_20_FEATURE_MIN_RESUME_TIME     = 0x05, | ||||
|   MS_OS_20_FEATURE_MODEL_ID            = 0x06, | ||||
|   MS_OS_20_FEATURE_CCGP_DEVICE         = 0x07, | ||||
|   MS_OS_20_FEATURE_VENDOR_REVISION     = 0x08 | ||||
| } microsoft_os_20_type_t; | ||||
| 
 | ||||
| uint8_t desc_ms_os_20[256] = | ||||
| { | ||||
|   // Set header: length, type, windows version, total length
 | ||||
|   U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN), | ||||
| 
 | ||||
|   // Configuration subset header: length, type, configuration index, reserved, configuration total length
 | ||||
|   U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A), | ||||
| 
 | ||||
|   // Function Subset header: length, type, first interface, reserved, subset length
 | ||||
|   U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 2  /*interface*/, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), | ||||
| 
 | ||||
|   // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
 | ||||
|   U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, | ||||
|   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
 | ||||
| 
 | ||||
|   // MS OS 2.0 Registry property descriptor: length, type
 | ||||
|   U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), | ||||
|   U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
 | ||||
|   'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, | ||||
|   'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, | ||||
|   U16_TO_U8S_LE(0x0050), // wPropertyDataLength
 | ||||
| 	//bPropertyData: “{E8379B1D-6AA3-F426-2EAE-83D18090CA79}”.
 | ||||
|   '{', 0x00, 'E', 0x00, '8', 0x00, '3', 0x00, '7', 0x00, '9', 0x00, 'B', 0x00, '1', 0x00, 'D', 0x00, '-', 0x00, | ||||
|   '6', 0x00, 'A', 0x00, 'A', 0x00, '3', 0x00, '-', 0x00, 'F', 0x00, '4', 0x00, '2', 0x00, '6', 0x00, '-', 0x00, | ||||
|   '2', 0x00, 'E', 0x00, 'A', 0x00, 'E', 0x00, '-', 0x00, '8', 0x00, '3', 0x00, 'D', 0x00, '1', 0x00, '8', 0x00, | ||||
|   '0', 0x00, '9', 0x00, '0', 0x00, 'C', 0x00, 'A', 0x00, '7', 0x00, '9', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 | ||||
| }; | ||||
| 
 | ||||
| static bool ad_setup_request_handler(__unused struct usb_device *device, struct usb_setup_packet *setup) { | ||||
|     setup = __builtin_assume_aligned(setup, 4); | ||||
|     printf("ad_setup_request_handler: Type %u, Request %u, Value %u, Index %u, Length %u\n", setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); | ||||
| 
 | ||||
|     if (setup->bmRequestType & USB_DIR_IN) { | ||||
|         if (USB_REQ_TYPE_RECIPIENT_DEVICE == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { | ||||
|             printf("Device request %x\n", (setup->wValue >> 8)); | ||||
|             if ((setup->bRequest == USB_REQUEST_GET_DESCRIPTOR) && ((setup->wValue >> 8) == 0xF /* BOS */)) { | ||||
|                 printf("Request BOS descriptor, idx %d\n", setup->wValue & 0xFF); | ||||
| 
 | ||||
|                 struct usb_endpoint *usb_control_in = usb_get_control_in_endpoint(); | ||||
|                 static __aligned(4) uint8_t descriptor_buf[PICO_USBDEV_MAX_DESCRIPTOR_SIZE] = { | ||||
|                     0x5, 0xF, 0x21, 0x0, 0x1, | ||||
|                     0x1C, 0x10, 0x5, 0x00, | ||||
|                     0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, | ||||
|                     0x0, 0x0, 0x3, 0x6, | ||||
|                     U16_TO_U8S_LE(MS_OS_20_DESC_LEN),  // TODO: len
 | ||||
|                     0x1, | ||||
|                     0x0 }; | ||||
|                 static struct usb_stream_transfer_funcs control_stream_funcs = { | ||||
|                         .on_chunk = usb_stream_noop_on_chunk, | ||||
|                         .on_packet_complete = usb_stream_noop_on_packet_complete | ||||
|                 }; | ||||
|                 int len = 0x21; | ||||
| 
 | ||||
|                 len = MIN(len, setup->wLength); | ||||
|                 usb_stream_setup_transfer(&_control_in_stream_transfer, &control_stream_funcs, descriptor_buf, | ||||
|                                             sizeof(descriptor_buf), len, _tf_send_control_in_ack); | ||||
| 
 | ||||
|                 _control_in_stream_transfer.ep = usb_control_in; | ||||
|                 usb_start_transfer(usb_control_in, &_control_in_stream_transfer.core); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if (USB_REQ_TYPE_TYPE_VENDOR == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { | ||||
|         // To prevent badly behaving software from accidentally triggering a reboot, e expect
 | ||||
|         // the wValue to be equal to the Ploopy vendor id.
 | ||||
|  | @ -703,12 +860,36 @@ static bool ad_setup_request_handler(__unused struct usb_device *device, struct | |||
|             // reset_usb_boot does not return, so we will not respond to this command.
 | ||||
|             return true; | ||||
|         } | ||||
|         else if (USB_REQ_TYPE_RECIPIENT_DEVICE == (setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) && setup->bRequest == MICROSOFT_COMPATIBLE_ID_FEATURE_DESRIPTOR && setup->wIndex == 0x7) | ||||
|         { | ||||
|             const int length = MIN(MS_OS_20_DESC_LEN, setup->wLength); | ||||
| 
 | ||||
|             printf("Sending %u bytes (%u %u)\n", length, MS_OS_20_DESC_LEN, sizeof(desc_ms_os_20)); | ||||
| 
 | ||||
|             struct usb_endpoint *usb_control_in = usb_get_control_in_endpoint(); | ||||
|             usb_stream_setup_transfer(&_control_in_stream_transfer, &control_stream_funcs, desc_ms_os_20, | ||||
|                             sizeof(desc_ms_os_20), length, _tf_send_control_in_ack); | ||||
| 
 | ||||
|             _control_in_stream_transfer.ep = usb_control_in; | ||||
|             usb_start_transfer(usb_control_in, &_control_in_stream_transfer.core); | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static struct usb_stream_transfer _config_in_stream_transfer; | ||||
| static bool configuration_interface_setup_request_handler(__unused struct usb_interface *interface, struct usb_setup_packet *setup) { | ||||
|     setup = __builtin_assume_aligned(setup, 4); | ||||
|     printf("configuration_interface_setup_request_handler: Type %u, Request %u, Value %u, Index %u, Length %u\n", setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static bool ac_setup_request_handler(__unused struct usb_interface *interface, struct usb_setup_packet *setup) { | ||||
|     setup = __builtin_assume_aligned(setup, 4); | ||||
|     printf("ac_setup_request_handler: Type %u, Request %u, Value %u, Index %u, Length %u\n", setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); | ||||
| 
 | ||||
|     if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { | ||||
|         switch (setup->bRequest) { | ||||
|             case AUDIO_REQ_SetCurrent: | ||||
|  | @ -735,6 +916,8 @@ static bool ac_setup_request_handler(__unused struct usb_interface *interface, s | |||
| 
 | ||||
| bool _as_setup_request_handler(__unused struct usb_endpoint *ep, struct usb_setup_packet *setup) { | ||||
|     setup = __builtin_assume_aligned(setup, 4); | ||||
|     printf("as_setup_request_handler: Type %u, Request %u, Value %u, Index %u, Length %u\n", setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); | ||||
| 
 | ||||
|     if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { | ||||
|         switch (setup->bRequest) { | ||||
|             case AUDIO_REQ_SetCurrent: | ||||
|  | @ -777,9 +960,22 @@ void usb_sound_card_init() { | |||
|     as_sync_transfer.type = &as_sync_transfer_type; | ||||
|     usb_set_default_transfer(&ep_op_sync, &as_sync_transfer); | ||||
| 
 | ||||
| 
 | ||||
|     static struct usb_endpoint *const configuration_endpoints[] = { | ||||
|         &ep_configuration_out, &ep_configuration_in | ||||
|     }; | ||||
|     usb_interface_init(&configuration_interface, &ad_conf.configuration_interface, configuration_endpoints, 2, true); | ||||
|     configuration_interface.setup_request_handler = configuration_interface_setup_request_handler; | ||||
| 
 | ||||
|     config_in_transfer.type = &config_in_transfer_type; | ||||
|     usb_set_default_transfer(&ep_configuration_in, &config_in_transfer); | ||||
|     config_out_transfer.type = &config_out_transfer_type; | ||||
|     usb_set_default_transfer(&ep_configuration_out, &config_out_transfer); | ||||
| 
 | ||||
|     static struct usb_interface *const boot_device_interfaces[] = { | ||||
|         &ac_interface, | ||||
|         &as_op_interface, | ||||
|         &configuration_interface | ||||
|     }; | ||||
| 
 | ||||
|     __unused struct usb_device *device = usb_device_init(&boot_device_descriptor, | ||||
|  |  | |||
|  | @ -68,12 +68,16 @@ typedef struct _audio_device_config { | |||
|         USB_Audio_StdDescriptor_StreamEndpoint_Spc_t audio; | ||||
|     } ep1; | ||||
|     struct usb_endpoint_descriptor_long ep2; | ||||
| 
 | ||||
|     struct usb_interface_descriptor configuration_interface; | ||||
|     struct usb_endpoint_descriptor ep3; | ||||
|     struct usb_endpoint_descriptor ep4; | ||||
| } audio_device_config; | ||||
| 
 | ||||
| static char *descriptor_strings[] = { | ||||
|     "Ploopy Corporation", | ||||
|     "Ploopy Headphones", | ||||
|     "000000000001" | ||||
|     "0000000000000001" // Dummy serial number, will be overwritten with the value read from the SPI flash chip. Must be 17bytes.
 | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 George Norton
						George Norton