#include "usb_device_config.h" #include "usb.h" #include "usb_device_stack_interface.h" #include "usb_descriptor.h" #include "mouse.h" #include "composite_app.h" ///////////////////////////////// Keyboard endpoint and interface ///////////////////////////////// usb_ep_struct_t keyboard_endpoint[HID_DESC_ENDPOINT_COUNT] = { { HID_ENDPOINT, USB_INTERRUPT_PIPE, USB_SEND, FS_INTERRUPT_OUT_ENDP_PACKET_SIZE, } }; usb_endpoints_t keyboard_endpoints = { HID_DESC_ENDPOINT_COUNT, keyboard_endpoint }; static usb_if_struct_t keyboard_interface[1]; /////////////////////////////////// Mouse endpoint and interface /////////////////////////////////// usb_ep_struct_t mouse_endpoint[HID_DESC_ENDPOINT_COUNT] = { { HID_ENDPOINT, USB_INTERRUPT_PIPE, USB_SEND, FS_INTERRUPT_OUT_ENDP_PACKET_SIZE, } }; usb_endpoints_t mouse_endpoints = { HID_DESC_ENDPOINT_COUNT, mouse_endpoint }; static usb_if_struct_t mouse_interface[1]; ////////////////////////////////////// USB class descriptors ////////////////////////////////////// usb_class_struct_t usb_interfaces[2] = { { USB_CLASS_HID, { 1, keyboard_interface } }, { USB_CLASS_HID, { 1, mouse_interface } }, }; static usb_composite_info_struct_t usb_composite_info = { 2, usb_interfaces }; uint8_t g_device_descriptor[DEVICE_DESCRIPTOR_SIZE] = { DEVICE_DESCRIPTOR_SIZE, /* "Device Descriptor Size */ USB_DEVICE_DESCRIPTOR, /* "Device" Type of descriptor */ 0x00,0x02, /* BCD USB version */ 0x00, /* Device Class is indicated in the interface descriptors */ 0x00, /* Device Subclass is indicated in the interface descriptors */ 0x00, /* Device Protocol */ CONTROL_MAX_PACKET_SIZE, /* Max Packet size */ 0xa2,0x15, /* Vendor ID */ 0x00, 0x02, /* Product ID */ 0x00, 0x02, /* BCD Device version */ 0x01, /* Manufacturer string index */ 0x02, /* Product string index */ 0x00, /* Serial number string index */ 0x01 /* Number of configurations */ }; uint8_t g_config_descriptor[CONFIG_DESC_SIZE] = { CONFIG_ONLY_DESC_SIZE, /* Configuration Descriptor Size - always 9 bytes*/ USB_CONFIG_DESCRIPTOR, /* "Configuration" type of descriptor */ CONFIG_DESC_SIZE, 0x00, /* Total length of the Configuration descriptor */ 0x02, /* NumInterfaces */ 0x01, /* Configuration Value */ 0, /* Configuration Description String Index*/ /* Attributes.support RemoteWakeup and self power */ (USB_DESC_CFG_ATTRIBUTES_D7_POS) | (USBCFG_DEV_SELF_POWER << USB_DESC_CFG_ATTRIBUTES_SELF_POWERED_SHIFT) | (USBCFG_DEV_REMOTE_WAKEUP << USB_DESC_CFG_ATTRIBUTES_REMOTE_WAKEUP_SHIFT), /* S08/CFv1 are both self powered (its compulsory to set bus powered)*/ /*Attributes.support RemoteWakeup and self power*/ 0x32, /* Current draw from bus */ /* Keyboard Interface Descriptor */ IFACE_ONLY_DESC_SIZE, USB_IFACE_DESCRIPTOR, 0x00, 0x00, HID_DESC_ENDPOINT_COUNT, 0x03, 0x01, 0x01, /* 0x01 for keyboard */ 0x00, /* Keyboard HID descriptor */ HID_ONLY_DESC_SIZE, USB_HID_DESCRIPTOR, 0x00, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, /* Keyboard Endpoint descriptor */ ENDP_ONLY_DESC_SIZE, USB_ENDPOINT_DESCRIPTOR, HID_ENDPOINT |(USB_SEND << 7), USB_INTERRUPT_PIPE, FS_INTERRUPT_OUT_ENDP_PACKET_SIZE, 0x00, FS_INTERRUPT_OUT_ENDP_INTERVAL, /* Mouse Interface Descriptor */ IFACE_ONLY_DESC_SIZE, USB_IFACE_DESCRIPTOR, 0x00, 0x00, HID_DESC_ENDPOINT_COUNT, 0x03, 0x01, 0x02, 0x00, /* Mouse HID descriptor */ HID_ONLY_DESC_SIZE, USB_HID_DESCRIPTOR, 0x00,0x01, 0x00, 0x01, 0x22, 0x34,0x00, /* Mouse Endpoint descriptor */ ENDP_ONLY_DESC_SIZE, USB_ENDPOINT_DESCRIPTOR, HID_ENDPOINT | (USB_SEND << 7), USB_INTERRUPT_PIPE, FS_INTERRUPT_OUT_ENDP_PACKET_SIZE, 0x00, FS_INTERRUPT_OUT_ENDP_INTERVAL }; uint8_t USB_STR_0[USB_STR_0_SIZE+USB_STR_DESC_SIZE] = { sizeof(USB_STR_0), USB_STRING_DESCRIPTOR, 0x09, 0x04/*equivalent to 0x0409*/ }; uint8_t USB_STR_1[USB_STR_1_SIZE+USB_STR_DESC_SIZE] = { sizeof(USB_STR_1), USB_STRING_DESCRIPTOR, 'F',0, 'R',0, 'E',0, 'E',0, 'S',0, 'C',0, 'A',0, 'L',0, 'E',0, ' ',0, 'S',0, 'E',0, 'M',0, 'I',0, 'C',0, 'O',0, 'N',0, 'D',0, 'U',0, 'C',0, 'T',0, 'O',0, 'R',0, ' ',0, 'I',0, 'N',0, 'C',0, '.',0 }; uint8_t USB_STR_2[USB_STR_2_SIZE+USB_STR_DESC_SIZE] = { sizeof(USB_STR_2), USB_STRING_DESCRIPTOR, 'U',0, 'S',0, 'B',0, ' ',0, 'A',0, 'U',0, 'D',0, 'I',0, 'O',0, '+',0, 'H',0, 'I',0, 'D',0, ' ',0, 'D',0, 'E',0, 'M',0, 'O',0, }; uint8_t USB_STR_n[USB_STR_n_SIZE+USB_STR_DESC_SIZE] = { sizeof(USB_STR_n), USB_STRING_DESCRIPTOR, 'B',0, 'A',0, 'D',0, ' ',0, 'S',0, 'T',0, 'R',0, 'I',0, 'N',0, 'G',0, ' ',0, 'I',0, 'N',0, 'D',0, 'E',0, 'X',0 }; uint8_t keyboard_hid_report_descriptor[KEYBOARD_REPORT_DESC_SIZE] = { 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 0x09, 0x06, /* USAGE (Keyboard) */ 0xa1, 0x01, /* COLLECTION (Application) */ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0x95, 0x08, /* REPORT_COUNT (8) */ 0x81, 0x02, /* INPUT (Data,Var,Abs) modifier keys (CTRL, ALT, etc...*/ 0x95, 0x01, /* REPORT_COUNT (1) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x81, 0x01, /* INPUT (Cnst,Var,Abs) filupp to byte boundary */ 0x95, 0x05, /* REPORT_COUNT (5) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0x05, 0x08, /* USAGE_PAGE (LEDs) */ 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ 0x91, 0x02, /* OUTPUT (Data,Var,Abs) pc->kbd */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0x75, 0x03, /* REPORT_SIZE (3 */ 0x91, 0x01, /* OUTPUT (Cnst,Var,Abs) filupp to byte boundary */ 0x95, 0x06, /* REPORT_COUNT (6) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ 0x81, 0x00, /* INPUT (Data,Ary,Abs) array for pressed keys */ 0xc0 /* END_COLLECTION */ }; uint8_t mouse_hid_report_descriptor[MOUSE_REPORT_DESC_SIZE] = { 0x05, 0x01, /* Usage Page (Generic Desktop)*/ 0x09, 0x02, /* Usage (Mouse) */ 0xA1, 0x01, /* Collection (Application) */ 0x09, 0x01, /* Usage (Pointer) */ 0xA1, 0x00, /* Collection (Physical) */ 0x05, 0x09, /* Usage Page (Buttons) */ 0x19, 0x01, /* Usage Minimum (01) */ 0x29, 0x03, /* Usage Maximum (03) */ 0x15, 0x00, /* logical Minimum (0) */ 0x25, 0x01, /* logical Maximum (1) */ 0x95, 0x03, /* Report Count (3) */ 0x75, 0x01, /* Report Size (1) */ 0x81, 0x02, /* Input(Data, Variable, Absolute) 3 button bits */ 0x95, 0x01, /* Report count (1) */ 0x75, 0x05, /* Report Size (5) */ 0x81, 0x01, /* Input (Constant), 5 bit padding */ 0x05, 0x01, /* Usage Page (Generic Desktop) */ 0x09, 0x30, /* Usage (X) */ 0x09, 0x31, /* Usage (Y) */ 0x09, 0x38, /* Usage (Z) */ 0x15, 0x81, /* Logical Minimum (-127) */ 0x25, 0x7F, /* Logical Maximum (127) */ 0x75, 0x08, /* Report Size (8) */ 0x95, 0x03, /* Report Count (2) */ 0x81, 0x06, /* Input(Data, Variable, Relative), 2 position bytes (X & Y)*/ 0xC0, /* end collection */ 0xC0 /* end collection */ }; uint32_t g_std_desc_size[USB_MAX_STD_DESCRIPTORS+1] = { 0, DEVICE_DESCRIPTOR_SIZE, CONFIG_DESC_SIZE, 0, /* String */ 0, /* Interface */ 0, /* Endpoint */ 0, /* Device Qualifier */ 0 /* other speed config */ }; uint8_t *g_std_descriptors[USB_MAX_STD_DESCRIPTORS+1] = { NULL, g_device_descriptor, g_config_descriptor, NULL, /* String */ NULL, /* Interface */ NULL, /* Endpoint */ NULL, /* Device Qualifier */ NULL /* Other speed config */ }; uint8_t g_string_desc_size[USB_MAX_STRING_DESCRIPTORS] = { sizeof(USB_STR_0), sizeof(USB_STR_1), sizeof(USB_STR_2), sizeof(USB_STR_n) }; uint8_t *g_string_descriptors[USB_MAX_STRING_DESCRIPTORS+1] = { USB_STR_0, USB_STR_1, USB_STR_2, USB_STR_n }; usb_language_t usb_lang[USB_MAX_SUPPORTED_LANGUAGES] = { { (uint16_t)0x0409, g_string_descriptors, g_string_desc_size } }; usb_all_languages_t g_languages = { USB_STR_0, sizeof(USB_STR_0), USB_MAX_SUPPORTED_LANGUAGES, usb_lang }; uint8_t g_valid_config_values[USB_MAX_CONFIG_SUPPORTED+1]={0,1}; /**************************************************************************** * Global Variables ****************************************************************************/ static uint8_t g_alternate_interface[USB_MAX_SUPPORTED_INTERFACES]; /**************************************************************************//*! * * @name USB_Desc_Get_Descriptor * * @brief The function returns the corresponding descriptor * * @param controller_ID : Controller ID * @param type : Type of descriptor requested * @param sub_type : String index for string descriptor * @param index : String descriptor language Id * @param descriptor : Output descriptor pointer * @param size : Size of descriptor returned * * @return USB_OK When Success * USBERR_INVALID_REQ_TYPE when Error ***************************************************************************** * This function is used to pass the pointer of the requested descriptor *****************************************************************************/ uint8_t USB_Desc_Get_Descriptor ( uint32_t handle, uint8_t type, uint8_t str_num, uint16_t index, uint8_t** descriptor, uint32_t* size ) { /* string descriptors are handled separately */ if (type == USB_STRING_DESCRIPTOR) { if (index == 0) { /* return the string and size of all languages */ *descriptor = (uint8_t *)g_languages.languages_supported_string; *size = g_languages.languages_supported_size; } else { uint8_t lang_id=0; uint8_t lang_index=USB_MAX_LANGUAGES_SUPPORTED; for (; lang_id< USB_MAX_LANGUAGES_SUPPORTED; lang_id++) { /* check whether we have a string for this language */ if (index == g_languages.usb_language[lang_id].language_id) { /* check for max descriptors */ if (str_num < USB_MAX_STRING_DESCRIPTORS) { /* setup index for the string to be returned */ lang_index = str_num; } break; } } /* set return val for descriptor and size */ *descriptor = (uint8_t *)g_languages.usb_language[lang_id].lang_desc[str_num]; *size = g_languages.usb_language[lang_id].lang_desc_size[lang_index]; } } else if (type < USB_MAX_STD_DESCRIPTORS+1) { /* set return val for descriptor and size*/ *descriptor = (uint8_t *)g_std_descriptors[type]; /* if there is no descriptor then return error */ if (*descriptor == NULL) { return USBERR_INVALID_REQ_TYPE; } *size = g_std_desc_size[type]; } else /* invalid descriptor */ { if (type == USB_REPORT_DESCRIPTOR) { type = USB_MAX_STD_DESCRIPTORS; *descriptor = (uint8_t *)g_std_descriptors[type]; *size = g_std_desc_size[type]; } else { return USBERR_INVALID_REQ_TYPE; } } return USB_OK; } /**************************************************************************//*! * * @name USB_Desc_Get_Interface * * @brief The function returns the alternate interface * * @param controller_ID : Controller ID * @param interface : Interface number * @param alt_interface : Output alternate interface * * @return USB_OK When Success * USBERR_INVALID_REQ_TYPE when Error ***************************************************************************** *This function is called by the framework module to get the current interface *****************************************************************************/ uint8_t USB_Desc_Get_Interface(uint32_t handle, uint8_t interface, uint8_t *alt_interface) { if (interface < USB_MAX_SUPPORTED_INTERFACES) { /* if interface valid */ /* get alternate interface */ *alt_interface = g_alternate_interface[interface]; return USB_OK; } return USBERR_INVALID_REQ_TYPE; } /**************************************************************************//*! * * @name USB_Desc_Set_Interface * * @brief The function sets the alternate interface * * @param handle : handle * @param interface : Interface number * @param alt_interface : Input alternate interface * * @return USB_OK When Success * USBERR_INVALID_REQ_TYPE when Error ***************************************************************************** *This function is called by the framework module to set the interface *****************************************************************************/ uint8_t USB_Desc_Set_Interface(uint32_t handle, uint8_t interface, uint8_t alt_interface) { if (interface < USB_MAX_SUPPORTED_INTERFACES) { /* if interface valid */ /* set alternate interface*/ g_alternate_interface[interface] = alt_interface; return USB_OK; } return USBERR_INVALID_REQ_TYPE; } /**************************************************************************//*! * * @name USB_Desc_Valid_Configation * * @brief The function checks whether the configuration parameter * input is valid or not * * @param handle : handle * @param config_val : Configuration value * * @return TRUE When Valid * FALSE When Error ***************************************************************************** * This function checks whether the configuration is valid or not *****************************************************************************/ bool USB_Desc_Valid_Configation ( uint32_t handle,/*[IN] Controller ID */ uint16_t config_val /*[IN] Configuration value */ ) { uint8_t loop_index=0; UNUSED_ARGUMENT(handle) /* check with only supported val right now */ while(loop_index < (USB_MAX_CONFIG_SUPPORTED+1)) { if(config_val == g_valid_config_values[loop_index]) { return TRUE; } loop_index++; } return FALSE; } /**************************************************************************//*! * * @name USB_Desc_Valid_Interface * * @brief The function checks whether the interface parameter * input is valid or not * * @param handle : handle * @param interface : Target interface * * @return TRUE When Valid * FALSE When Error ***************************************************************************** * This function checks whether the interface is valid or not *****************************************************************************/ bool USB_Desc_Valid_Interface ( uint32_t handle, /*[IN] Controller ID */ uint8_t interface /*[IN] Target interface */ ) { uint8_t loop_index=0; UNUSED_ARGUMENT(handle) /* check with only supported val right now */ while(loop_index < USB_MAX_SUPPORTED_INTERFACES) { if(interface == g_alternate_interface[loop_index]) { return TRUE; } loop_index++; } return FALSE; } /**************************************************************************//*! * * @name USB_Desc_Remote_Wakeup * * @brief The function checks whether the remote wakeup is supported or not * * @param handle : handle * * @return REMOTE_WAKEUP_SUPPORT (TRUE) - If remote wakeup supported ***************************************************************************** * This function returns remote wakeup is supported or not *****************************************************************************/ bool USB_Desc_Remote_Wakeup(uint32_t handle /* [IN] Controller ID */) { return USBCFG_DEV_REMOTE_WAKEUP; } /* **************************************************************************** * Local available * Stock Array value of Parameter controller ******************************************************************************/ /**************************************************************************//*! * * @name USB_Set_Configuration * * @brief The function set the configuration value of device * * * @param handle handle * @param config_val configuration value * * @return TRUE When Valid * FALSE When Error *****************************************************************************/ uint8_t USB_Set_Configuration(audio_handle_t handle, uint8_t config) { return USB_OK; /* It's that simple since the device only has one configuration. */ } /**************************************************************************//*! * * @name USB_Desc_Get_Entity * * @brief The function retrieves the entity specified by type. * * @param handle handle * * @return USB_OK - if success *****************************************************************************/ uint8_t USB_Desc_Get_Entity(audio_handle_t handle, entity_type type, uint32_t *object) { switch (type) { case USB_CLASS_INFO: break; case USB_CLASS_INTERFACE_INDEX_INFO: *object = 0xff; if (handle == (uint32_t)g_composite_device.hid_keyboard.app_handle) { *object = (uint32_t)HID_KEYBOARD_INTERFACE_INDEX; break; } else if (handle == (uint32_t)g_composite_device.hid_mouse.app_handle) { *object = (uint32_t)HID_MOUSE_INTERFACE_INDEX; break; } break; case USB_COMPOSITE_INFO: keyboard_interface[0].index = 0; keyboard_interface[0].endpoints = keyboard_endpoints; mouse_interface[0].index = 1; mouse_interface[0].endpoints = mouse_endpoints; *object = (unsigned long)&usb_composite_info; break; default: break; } return USB_OK; } /**************************************************************************//*! * * @name USB_Desc_Set_Speed * * @brief The function is used to set device speed * * @param handle: handle * @param speed: speed * * @return USB_OK When Success * USBERR_INVALID_REQ_TYPE when Error *****************************************************************************/ uint8_t USB_Desc_Set_Speed(uint32_t handle, uint16_t speed) { descriptor_union_t ptr1, ptr2; ptr1.pntr = g_config_descriptor; ptr2.pntr = g_config_descriptor + sizeof(g_config_descriptor); if (handle == g_composite_device.hid_keyboard.app_handle) { while (ptr1.word < ptr2.word) { if (ptr1.common->bDescriptorType == USB_DESC_TYPE_EP) { if (USB_SPEED_HIGH == speed) { ptr1.ndpt->iInterval = HS_INTERRUPT_OUT_ENDP_INTERVAL; ptr1.ndpt->wMaxPacketSize[0] = USB_uint_16_low(HS_INTERRUPT_OUT_ENDP_PACKET_SIZE); ptr1.ndpt->wMaxPacketSize[1] = USB_uint_16_high(HS_INTERRUPT_OUT_ENDP_PACKET_SIZE); } else { ptr1.ndpt->iInterval = FS_INTERRUPT_OUT_ENDP_INTERVAL; ptr1.ndpt->wMaxPacketSize[0] = USB_uint_16_low(FS_INTERRUPT_OUT_ENDP_PACKET_SIZE); ptr1.ndpt->wMaxPacketSize[1] = USB_uint_16_high(FS_INTERRUPT_OUT_ENDP_PACKET_SIZE); } } ptr1.word += ptr1.common->bLength; } for (int i = 0; i < HID_DESC_ENDPOINT_COUNT; i++) { if (USB_SPEED_HIGH == speed) { keyboard_endpoint[i].size = HS_INTERRUPT_OUT_ENDP_PACKET_SIZE; } else { keyboard_endpoint[i].size = FS_INTERRUPT_OUT_ENDP_PACKET_SIZE; } } } else if (handle == g_composite_device.hid_mouse.app_handle) { while (ptr1.word < ptr2.word) { if (ptr1.common->bDescriptorType == USB_DESC_TYPE_EP) { if ((ptr1.ndpt->bmAttributes & 0x03) == USB_INTERRUPT_PIPE) { if (USB_SPEED_HIGH == speed) { ptr1.ndpt->iInterval = HS_INTERRUPT_OUT_ENDP_INTERVAL; ptr1.ndpt->wMaxPacketSize[0] = USB_uint_16_low(HS_INTERRUPT_OUT_ENDP_PACKET_SIZE); ptr1.ndpt->wMaxPacketSize[1] = USB_uint_16_high(HS_INTERRUPT_OUT_ENDP_PACKET_SIZE); } else { ptr1.ndpt->iInterval = FS_INTERRUPT_OUT_ENDP_INTERVAL; ptr1.ndpt->wMaxPacketSize[0] = USB_uint_16_low(FS_INTERRUPT_OUT_ENDP_PACKET_SIZE); ptr1.ndpt->wMaxPacketSize[1] = USB_uint_16_high(FS_INTERRUPT_OUT_ENDP_PACKET_SIZE); } } } ptr1.word += ptr1.common->bLength; } for (int i = 0; i < HID_DESC_ENDPOINT_COUNT; i++) { if (USB_SPEED_HIGH == speed) { mouse_endpoint[i].size = HS_INTERRUPT_OUT_ENDP_PACKET_SIZE; } else { mouse_endpoint[i].size = FS_INTERRUPT_OUT_ENDP_PACKET_SIZE; } } } return USB_OK; } usb_desc_request_notify_struct_t desc_callback = { USB_Desc_Get_Descriptor, USB_Desc_Get_Interface, USB_Desc_Set_Interface, USB_Set_Configuration, USB_Desc_Get_Entity };