244 lines
9.2 KiB
C
244 lines
9.2 KiB
C
#include "usb_descriptors.h"
|
|
|
|
const USB_DeviceDescriptor_t USB_DeviceDescriptor =
|
|
{
|
|
.bLength = sizeof(USB_DeviceDescriptor_t),
|
|
.bDescriptorType = USB_DEVICE_DESCRIPTOR,
|
|
.bcdUSB = 0x0200,
|
|
.bDeviceClass = 0x02, // CDC
|
|
.bDeviceSubClass = 0x00, // Subclass per interface
|
|
.bDeviceProtocol = 0x00, // Protocol per interface
|
|
.bMaxPacketSize0 = 64,
|
|
.idVendor = 0x16c0,
|
|
.idProduct = 0x05e1,
|
|
.bcdDevice = 0x0200,
|
|
.iManufacturer = 1,
|
|
.iProduct = 2,
|
|
.iSerialNumber = 3,
|
|
.bNumConfigurations = 1
|
|
};
|
|
|
|
const USB_WholeDescriptor_t USB_ConfigurationInterfaceDescriptor =
|
|
{
|
|
.configuration = (USB_ConfigurationDescriptor_t)
|
|
{
|
|
.bLength = sizeof(USB_ConfigurationDescriptor_t),
|
|
.bDescriptorType = USB_CONFIGURATION_DESCRIPTOR,
|
|
.wTotalLength = sizeof(USB_WholeDescriptor_t),
|
|
.bNumInterfaces = 2,
|
|
.bConfigurationValue = 1,
|
|
.iConfiguration = 0,
|
|
.bmAttributes = 0x80,
|
|
.bMaxPower = 100
|
|
},
|
|
|
|
// Interface 0: Control
|
|
.control_interface = (USB_InterfaceDescriptor_t)
|
|
{
|
|
.bLength = sizeof(USB_InterfaceDescriptor_t),
|
|
.bDescriptorType = USB_INTERFACE_DESCRIPTOR,
|
|
.bInterfaceNumber = 0,
|
|
.bAlternateSetting = 0,
|
|
.bNumEndpoints = 1,
|
|
.bInterfaceClass = 0x02, // CDC
|
|
.bInterfaceSubClass = 0x02, // ACM
|
|
.bInterfaceProtocol = 0x00, // No command protocol
|
|
.iInterface = 0
|
|
},
|
|
.control_interface_functional_header = (USB_HeaderFunctionalDescriptor_t)
|
|
{
|
|
.bFunctionLength = sizeof(USB_HeaderFunctionalDescriptor_t),
|
|
.bDescriptorType = USB_CLASS_SPECIFIC_INTERFACE_DESCRIPTOR,
|
|
.bDescriptorSubtype = 0x00, // Header subtype
|
|
.bcdCDC = 0x0120 // TODO: Check differences between 0x0110
|
|
// and 0x0120 (CDC 1.1 vs. CDC 1.2)
|
|
},
|
|
.control_interface_functional_acm = (USB_ACMFunctionalDescriptor_t)
|
|
{
|
|
.bFunctionLength = sizeof(USB_ACMFunctionalDescriptor_t),
|
|
.bDescriptorType = USB_CLASS_SPECIFIC_INTERFACE_DESCRIPTOR,
|
|
.bDescriptorSubtype = 0x02, // ACM
|
|
.bmCapabilities = 0x02 // Device supports Set_Line_Coding,
|
|
// Set_Control_Line_State, Get_Line_Coding,
|
|
// and the notification Serial_State
|
|
},
|
|
.control_interface_functional_unit = (USB_UnionFunctionalDescriptor_t)
|
|
{
|
|
.bFunctionLength = sizeof(USB_UnionFunctionalDescriptor_t),
|
|
.bDescriptorType = USB_CLASS_SPECIFIC_INTERFACE_DESCRIPTOR,
|
|
.bDescriptorSubtype = 0x06, // Union descriptor
|
|
.bControlInterface = 0, // Current interface
|
|
.bSubordinateInterface0 = 1 // Next interface for the actual data
|
|
},
|
|
// Endpoint 1: Notification (in)
|
|
.notification_endpoint = (USB_EndpointDescriptor_t)
|
|
{
|
|
.bLength = sizeof(USB_EndpointDescriptor_t),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
|
|
.bEndpointAddress = USB_ENDPOINT_IN | 1,
|
|
.bmAttributes = USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_NO_SYNCHRONIZATION
|
|
| USB_ENDPOINT_DATA,
|
|
.wMaxPacketSize = 8,
|
|
.bInterval = 0xff
|
|
},
|
|
|
|
// Interface 1: Data
|
|
.data_interface = (USB_InterfaceDescriptor_t)
|
|
{
|
|
.bLength = sizeof(USB_InterfaceDescriptor_t),
|
|
.bDescriptorType = USB_INTERFACE_DESCRIPTOR,
|
|
.bInterfaceNumber = 1,
|
|
.bAlternateSetting = 0,
|
|
.bNumEndpoints = 2,
|
|
.bInterfaceClass = 0x0a, // CDC data class
|
|
.bInterfaceSubClass = 0x00, // No subclass
|
|
.bInterfaceProtocol = 0x00, // No data protocol
|
|
.iInterface = 0
|
|
},
|
|
// Endpoint 3: Data out
|
|
.data_out_endpoint = (USB_EndpointDescriptor_t)
|
|
{
|
|
.bLength = sizeof(USB_EndpointDescriptor_t),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
|
|
.bEndpointAddress = USB_ENDPOINT_OUT | 3,
|
|
.bmAttributes = USB_ENDPOINT_BULK | USB_ENDPOINT_NO_SYNCHRONIZATION
|
|
| USB_ENDPOINT_DATA,
|
|
.wMaxPacketSize = 64,
|
|
.bInterval = 0x05
|
|
},
|
|
// Endpoint 2: Data in
|
|
.data_in_endpoint = (USB_EndpointDescriptor_t)
|
|
{
|
|
.bLength = sizeof(USB_EndpointDescriptor_t),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
|
|
.bEndpointAddress = USB_ENDPOINT_IN | 2,
|
|
.bmAttributes = USB_ENDPOINT_BULK | USB_ENDPOINT_NO_SYNCHRONIZATION
|
|
| USB_ENDPOINT_DATA,
|
|
.wMaxPacketSize = 64,
|
|
.bInterval = 0x05
|
|
},
|
|
};
|
|
|
|
#define USB_STRING_LANGID 0x0409
|
|
#define USB_STRING_VENDOR \
|
|
'2', '5', '1', '2', '0', '.', 'o', 'r', 'g'
|
|
#define USB_STRING_PRODUCT \
|
|
'H', 'P', 'G', 'L', ' ', 'X', 'Y'
|
|
|
|
const uint16_t USB_StringDescriptor_LangID[] =
|
|
USB_BUILD_STRING_DESCRIPTOR(USB_STRING_LANGID);
|
|
const uint16_t USB_StringDescriptor_Vendor[] =
|
|
USB_BUILD_STRING_DESCRIPTOR(USB_STRING_VENDOR);
|
|
const uint16_t USB_StringDescriptor_Product[] =
|
|
USB_BUILD_STRING_DESCRIPTOR(USB_STRING_PRODUCT);
|
|
|
|
void USB_HandleGetDescriptor(USB_DescriptorType_t descriptor_type,
|
|
int descriptor_index, const void **reply_data, int *reply_length,
|
|
uint8_t *reply_response)
|
|
{
|
|
switch(descriptor_type)
|
|
{
|
|
case USB_DEVICE_DESCRIPTOR:
|
|
*reply_data = &USB_DeviceDescriptor;
|
|
*reply_length = USB_DeviceDescriptor.bLength;
|
|
break;
|
|
|
|
case USB_CONFIGURATION_DESCRIPTOR:
|
|
*reply_data = &USB_ConfigurationInterfaceDescriptor;
|
|
if(*reply_length < USB_ConfigurationInterfaceDescriptor
|
|
.configuration.wTotalLength)
|
|
{
|
|
*reply_length = USB_ConfigurationInterfaceDescriptor
|
|
.configuration.bLength;
|
|
}
|
|
else
|
|
{
|
|
*reply_length = USB_ConfigurationInterfaceDescriptor
|
|
.configuration.wTotalLength;
|
|
}
|
|
break;
|
|
|
|
case USB_STRING_DESCRIPTOR:
|
|
switch(descriptor_index)
|
|
{
|
|
case 0:
|
|
*reply_data = (uint8_t*)USB_StringDescriptor_LangID;
|
|
*reply_length = (uint8_t)*USB_StringDescriptor_LangID;
|
|
break;
|
|
case 1:
|
|
*reply_data = (uint8_t*)USB_StringDescriptor_Vendor;
|
|
*reply_length = (uint8_t)*USB_StringDescriptor_Vendor;
|
|
break;
|
|
case 2:
|
|
*reply_data = (uint8_t*)USB_StringDescriptor_Product;
|
|
*reply_length = (uint8_t)*USB_StringDescriptor_Product;
|
|
break;
|
|
case 3:;
|
|
// Serial string
|
|
// The first two bytes are occupied by descriptor length and
|
|
// descriptor type (3 = string descriptor). String
|
|
// descriptors are 16 bits per char and are not zero-
|
|
// terminated, so we're reserving a buffer for 24 characters
|
|
// here.
|
|
static uint16_t buff[25];
|
|
|
|
// The first byte is the total length in bytes, the second
|
|
// byte is the descriptor type (3)
|
|
buff[0] = sizeof(buff) | (USB_STRING_DESCRIPTOR << 8);
|
|
|
|
// The unique device ID is 96 bits = 12 bytes long
|
|
for(int i = 0; i < 12; i++)
|
|
{
|
|
uint8_t uid_byte = *((uint8_t*)UID_BASE + i);
|
|
// We're using one of the first 16 letters of the
|
|
// alphabet for each nibble, just like in the bootloader
|
|
buff[1 + 2 * i] = 'A' + (uid_byte & 0x0f);
|
|
buff[2 + 2 * i] = 'A' + (uid_byte >> 4);
|
|
}
|
|
|
|
*reply_data = (uint8_t*)buff;
|
|
*reply_length = (uint8_t)*buff;
|
|
break;
|
|
default:
|
|
__asm__ volatile("bkpt");
|
|
}
|
|
break;
|
|
|
|
case USB_INTERFACE_DESCRIPTOR:
|
|
switch(descriptor_index)
|
|
{
|
|
case 0:
|
|
*reply_data = &USB_ConfigurationInterfaceDescriptor
|
|
.control_interface;
|
|
*reply_length = USB_ConfigurationInterfaceDescriptor
|
|
.control_interface.bLength;
|
|
break;
|
|
case 1:
|
|
*reply_data = &USB_ConfigurationInterfaceDescriptor
|
|
.data_interface;
|
|
*reply_length = USB_ConfigurationInterfaceDescriptor
|
|
.data_interface.bLength;
|
|
break;
|
|
default:
|
|
__asm__ volatile("bkpt");
|
|
}
|
|
break;
|
|
|
|
case USB_DEVICE_QUALIFIER_DESCRIPTOR:
|
|
// Device is full-speed only, so it must return a request error
|
|
*reply_response = USB_EP_TX_STALL;
|
|
*reply_data = NULL;
|
|
break;
|
|
|
|
case USB_ENDPOINT_DESCRIPTOR:
|
|
case USB_OTHER_DESCRIPTOR:
|
|
case USB_INTERFACE_POWER_DESCRIPTOR:
|
|
case USB_INTERFACE_ASSOCIATION_DESCRIPTOR:
|
|
case USB_CLASS_SPECIFIC_INTERFACE_DESCRIPTOR:
|
|
case USB_CLASS_SPECIFIC_ENDPOINT_DESCRIPTOR:
|
|
// Not implemented
|
|
__asm__ volatile("bkpt");
|
|
break;
|
|
}
|
|
}
|
|
|