/**************************************************************************//** * @file HID.c * @brief HID Class Device sample source file * - Device Descriptor * - USB Device Callback functions * - HID Data Update function * * SPDX-License-Identifier: Apache-2.0 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "N9H20.h" #include "HID.h" #define LEN_CONFIG_AND_SUBORDINATE (LEN_CONFIG+LEN_INTERFACE+LEN_HID+LEN_ENDPOINT) /* Define the interrupt In EP number */ #define INT_IN_EP_NUM 0x01 /* Mass_Storage command base address */ extern volatile USBD_INFO_T usbdInfo; /* USB Device Property */ extern USB_CMD_T _usb_cmd_pkt; UINT32 volatile u32Ready = 0; #ifdef HID_MOUSE UINT8 g_HID_au8MouseReportDescriptor[] __attribute__((aligned(4))) = { 0x05, 0x01, /* Usage Page(Generic Desktop Controls) */ 0x09, 0x02, /* Usage(Mouse) */ 0xA1, 0x01, /* Collection(Application) */ 0x09, 0x01, /* Usage(Pointer) */ 0xA1, 0x00, /* Collection(Physical) */ 0x05, 0x09, /* Usage Page(Button) */ 0x19, 0x01, /* Usage Minimum(0x1) */ 0x29, 0x03, /* Usage Maximum(0x3) */ 0x15, 0x00, /* Logical Minimum(0x0) */ 0x25, 0x01, /* Logical Maximum(0x1) */ 0x75, 0x01, /* Report Size(0x1) */ 0x95, 0x03, /* Report Count(0x3) */ 0x81, 0x02, /* Input(3 button bit) */ 0x75, 0x05, /* Report Size(0x5) */ 0x95, 0x01, /* Report Count(0x1) */ 0x81, 0x01, /* Input(5 bit padding) */ 0x05, 0x01, /* Usage Page(Generic Desktop Controls) */ 0x09, 0x30, /* Usage(X) */ 0x09, 0x31, /* Usage(Y) */ 0x09, 0x38, /* Usage(Wheel) */ 0x15, 0x81, /* Logical Minimum(0x81)(-127) */ 0x25, 0x7F, /* Logical Maximum(0x7F)(127) */ 0x75, 0x08, /* Report Size(0x8) */ 0x95, 0x03, /* Report Count(0x3) */ 0x81, 0x06, /* Input(1 byte wheel) */ 0xC0, /* End Collection */ 0xC0, /* End Collection */ }; #define HID_MOUSE_REPORT_DESCRIPTOR_SIZE \ sizeof (g_HID_au8MouseReportDescriptor) / sizeof(g_HID_au8MouseReportDescriptor[0]) UINT32 g_HID_u32MouseReportDescriptorSize = HID_MOUSE_REPORT_DESCRIPTOR_SIZE; #define HID_REPORT_DESCRIPTOR_SIZE HID_MOUSE_REPORT_DESCRIPTOR_SIZE UINT8 g_au8MouseReport[4] __attribute__((aligned(4))); UINT32 g_u32MouseReportSize = sizeof(g_au8MouseReport) / sizeof(g_au8MouseReport[0]); #endif #ifdef HID_KEYBOARD //keyboard 101keys UINT8 g_HID_au8KeyboardReportDescriptor[] __attribute__((aligned(4))) = { 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0 }; #define HID_KEYBOARD_REPORT_DESCRIPTOR_SIZE \ sizeof(g_HID_au8KeyboardReportDescriptor) / sizeof(g_HID_au8KeyboardReportDescriptor[0]) UINT32 g_HID_u32KeyboardReportDescriptorSize = HID_KEYBOARD_REPORT_DESCRIPTOR_SIZE; # define HID_REPORT_DESCRIPTOR_SIZE HID_KEYBOARD_REPORT_DESCRIPTOR_SIZE UINT8 g_au8KeyboardReport[8] __attribute__((aligned(4))); UINT32 g_u32KeyboardReportSize = sizeof(g_au8KeyboardReport) / sizeof(g_au8KeyboardReport[0]); #endif /* MSC Descriptor */ UINT8 HID_DeviceDescriptor[] __attribute__((aligned(4))) = { LEN_DEVICE, /* bLength */ DESC_DEVICE, /* bDescriptorType */ 0x10, 0x01, /* bcdUSB */ 0x00, /* bDeviceClass */ 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ CEP_MAX_PKT_SIZE,/* bMaxPacketSize0 */ /* idVendor */ USB_VID & 0x00FF, (USB_VID & 0xFF00) >> 8, /* idProduct */ USB_PID & 0x00FF, (USB_PID & 0xFF00) >> 8, 0x00, 0x00, /* bcdDevice */ 0x01, /* iManufacture */ 0x02, /* iProduct */ 0x00, /* iSerialNumber - no serial */ 0x01 /* bNumConfigurations */ }; static UINT8 HID_ConfigurationBlock[] __attribute__((aligned(4))) = { LEN_CONFIG, /* bLength */ DESC_CONFIG, /* bDescriptorType */ /* wTotalLength */ LEN_CONFIG_AND_SUBORDINATE & 0x00FF, (LEN_CONFIG_AND_SUBORDINATE & 0xFF00) >> 8, 0x01, /* bNumInterfaces */ 0x01, /* bConfigurationValue */ 0x00, /* iConfiguration */ 0x80 | (HID_IS_SELF_POWERED << 6) | (HID_IS_REMOTE_WAKEUP << 5),/* bmAttributes */ HID_MAX_POWER, /* MaxPower */ /* I/F descr: HID */ LEN_INTERFACE, /* bLength */ DESC_INTERFACE, /* bDescriptorType */ 0x00, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x01, /* bNumEndpoints */ 0x03, /* bInterfaceClass */ 0x01, /* bInterfaceSubClass */ 0x01, /* bInterfaceProtocol */ 0x00, /* iInterface */ /* HID Descriptor */ LEN_HID, /* Size of this descriptor in UINT8s. */ DESC_HID, /* HID descriptor type. */ 0x10, 0x01, /* HID Class Spec. release number. */ 0x00, /* H/W target country. */ 0x01, /* Number of HID class descriptors to follow. */ DESC_HID_RPT, /* Dscriptor type. */ /* Total length of report descriptor. */ HID_REPORT_DESCRIPTOR_SIZE & 0x00FF, (HID_REPORT_DESCRIPTOR_SIZE & 0xFF00) >> 8, /* EP Descriptor: interrupt in. */ LEN_ENDPOINT, /* bLength */ DESC_ENDPOINT, /* bDescriptorType */ (INT_IN_EP_NUM | EP_INPUT), /* bEndpointAddress */ EP_INT, /* bmAttributes */ /* wMaxPacketSize */ EPA_MAX_PKT_SIZE & 0x00FF, (EPA_MAX_PKT_SIZE & 0xFF00) >> 8, HID_DEFAULT_INT_IN_INTERVAL /* bInterval */ }; /* Identifier Language */ static UINT8 HID_StringDescriptor0[4] __attribute__((aligned(4))) = { 4, /* bLength */ USB_DT_STRING, /* bDescriptorType */ 0x09, 0x04 }; /* iManufacturer */ UINT8 HID_StringDescriptor1[] __attribute__((aligned(4))) = { 0x10, /* bLength (Dafault Value is 0x10, the value will be set to actual value according to the Descriptor size wehn calling mscdInit) */ 0x03, /* bDescriptorType */ 'n', 0, 'u', 0, 'v', 0, 'o', 0, 'T', 0, 'o', 0, 'n', 0 }; /* iProduct */ UINT8 HID_StringDescriptor2[] __attribute__((aligned(4))) = { 0x10, /* bLength (Dafault Value is 0x10, the value will be set to actual value according to the Descriptor size wehn calling mscdInit) */ 0x03, /* bDescriptorType */ 'U', 0, 'S', 0, 'B', 0, ' ', 0, 'H', 0, 'I', 0, 'D', 0 }; /* iSerialNumber */ UINT8 HID_StringDescriptor3[] __attribute__((aligned(4))) = { 0x1A, /* bLength (Dafault Value is 0x1A, the value will be set to actual value according to the Descriptor size wehn calling mscdInit) */ 0x03, /* bDescriptorType */ '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, 'N', 0, '9', 0, 'H', 0, '2', 0, '0', 0 }; /* HID Full Speed Init */ void hidFullSpeedInit(void) { usbdInfo.usbdMaxPacketSize = 0x40; /* bulk in */ outp32(EPA_RSP_SC, 0x00000000); /* auto validation */ outp32(EPA_MPS, EPA_MAX_PKT_SIZE); /* mps 8 */ outp32(EPA_CFG, 0x0000001b); /* bulk in ep no 1 */ outp32(EPA_START_ADDR, CEP_MAX_PKT_SIZE); outp32(EPA_END_ADDR, CEP_MAX_PKT_SIZE +EPA_MAX_PKT_SIZE -1); outp32(OPER, 0); } void hidClassOUT(void) { if(_usb_cmd_pkt.bRequest == HID_SET_IDLE) { outp32(CEP_CTRL_STAT, ZEROLEN); sysprintf("Set IDLE\n"); outp32(CEP_IRQ_STAT, CEP_STACOM_IS); } else if(_usb_cmd_pkt.bRequest == HID_SET_REPORT) { u32Ready = 1; sysprintf("SET_REPORT 0x%X\n",inp8(CEP_DATA_BUF)); } } #ifdef HID_MOUSE UINT8 volatile g_u8EPAReady = 0; signed char mouse_table[] = {-16, -16, -16, 0, 16, 16, 16, 0}; UINT8 mouse_idx = 0; UINT8 move_len, mouse_mode=1; void HID_UpdateMouseData(void) { int volatile i; #ifdef HID_KEYPAD signed char buf[4]; UINT32 u32KpiReport = 0x0; if (g_u8EPAReady) { u32KpiReport = kpi_read(KPI_NONBLOCK); u32KpiReport &= MASK_KEY; if(u32KpiReport != 0) { switch(u32KpiReport) { case UP_KEY: buf[0] = 0; buf[1] = 0; buf[2] = -5; break; case DOWN_KEY: buf[0] = 0; buf[1] = 0; buf[2] = 5; break; case LEFT_KEY: buf[0] = 0; buf[1] = -5; buf[2] = 0; break; case RIGHT_KEY: buf[0] = 0; buf[1] = 5; buf[2] = 0; break; default: break; } g_u8EPAReady = 0; /* Set transfer length and trigger IN transfer */ for (i=0; i<4; i++) outp8(EPA_DATA_BUF ,buf[i]); outp32(EPA_IRQ_ENB, IN_TK_IE); outp32(EPA_RSP_SC, PK_END); /* Set Packet End */ } } #else UINT8 buf[4]; if (g_u8EPAReady) { mouse_mode ^= 1; if (mouse_mode) { if (move_len > 14) { /* Update new report data */ buf[0] = 0x00; buf[1] = mouse_table[mouse_idx & 0x07]; buf[2] = mouse_table[(mouse_idx + 2) & 0x07]; buf[3] = 0x00; mouse_idx++; move_len = 0; } } else { buf[0] = buf[1] = buf[2] = buf[3] = 0; } move_len++; g_u8EPAReady = 0; /* Set transfer length and trigger IN transfer */ for (i=0; i<g_u32MouseReportSize; i++) outp8(EPA_DATA_BUF ,buf[i]); outp32(EPA_IRQ_ENB, IN_TK_IE); outp32(EPA_RSP_SC, PK_END); /* Set Packet End */ } #endif } void EPA_Handler(UINT32 u32IntEn,UINT32 u32IntStatus) /* Interrupt IN handler */ { g_u8EPAReady = 1; } #endif #ifdef HID_KEYBOARD char output_string[] = "THIS IS HID KEYBOARD DEMO"; UINT32 preKey = 0 ; UINT32 string_index = 0; UINT32 delay = 0; void HID_SetInReport(void) { INT32 i; #ifdef HID_KEYPAD UINT32 u32KpiReport = 0x0; #endif UINT8 *buf; if (u32Ready) { if(!(inp32(EPA_IRQ_STAT) & EMPTY_IS)) return; buf = g_au8KeyboardReport; #ifdef HID_KEYPAD u32KpiReport = kpi_read(KPI_NONBLOCK); if(u32KpiReport == 0) { /* No any key pressed */ for (i=0;i<8;i++) buf[i] = 0; if(u32KpiReport != preKey) { /* Trigger to note key release */ for (i=0; i<g_u32KeyboardReportSize; i++) outp8(EPA_DATA_BUF ,buf[i]); outp32(EPA_RSP_SC, PK_END); /* Set Packet End */ } } else { switch(u32KpiReport) { case UP_KEY: buf[2] = 0x04; /* "A" */ break; case DOWN_KEY: buf[2] = 0x05; /* "B" */ break; case LEFT_KEY: buf[2] = 0x06; /* "C" */ break; case RIGHT_KEY: buf[2] = 0x07; /* "D" */ break; case ENTER_KEY: buf[2] = 0x08; /* "E" */ break; case HOME_KEY: buf[2] = 0x09; /* "F" */ break; } preKey = u32KpiReport; /* Trigger to note key release */ for (i=0; i<g_u32KeyboardReportSize; i++) outp8(EPA_DATA_BUF ,buf[i]); outp32(EPA_RSP_SC, PK_END); /* Set Packet End */ } #else if(delay) { delay--; return; } else if (preKey != 0) { /* No any key pressed */ for (i=0;i<8;i++) buf[i] = 0; preKey = 0; /* Trigger to note key release */ for (i=0; i<g_u32KeyboardReportSize; i++) outp8(EPA_DATA_BUF ,buf[i]); outp32(EPA_RSP_SC, PK_END); /* Set Packet End */ } else { if(string_index == sizeof(output_string)) buf[2] = 0x28; /* Return */ else if (output_string[string_index] == ' ') buf[2] = 0x2C; /* Space */ else buf[2] = output_string[string_index] - 'A' + 4; preKey = buf[2]; /* Trigger to note key release */ for (i=0; i<g_u32KeyboardReportSize; i++) outp8(EPA_DATA_BUF ,buf[i]); outp32(EPA_RSP_SC, PK_END); /* Set Packet End */ delay = 2; string_index++; if(string_index > sizeof(output_string)) { string_index = 0; } } #endif } } #endif /* HID Init */ void hidInit(void) { /* Set Endpoint map */ usbdInfo.i32EPA_Num = 1; /* Endpoint 1 */ usbdInfo.i32EPB_Num = -1; /* Not use */ usbdInfo.i32EPC_Num = -1; /* Not use */ usbdInfo.i32EPD_Num = -1; /* Not use */ /* Set Callback Function */ /* Set MSC initialize function */ usbdInfo.pfnFullSpeedInit = hidFullSpeedInit; usbdInfo.pfnHighSpeedInit = hidFullSpeedInit; /* Set Descriptor pointer */ usbdInfo.pu32DevDescriptor = (PUINT32) &HID_DeviceDescriptor; usbdInfo.pu32HSConfDescriptor = (PUINT32) &HID_ConfigurationBlock; usbdInfo.pu32FSConfDescriptor = (PUINT32) &HID_ConfigurationBlock; usbdInfo.pu32HIDDescriptor = (PUINT32) ((UINT32)&HID_ConfigurationBlock + LEN_CONFIG + LEN_INTERFACE); usbdInfo.pfnClassDataOUTCallBack = hidClassOUT; #ifdef HID_MOUSE /* Set the HID report descriptor */ usbdInfo.pu32HIDRPTDescriptor = (PUINT32) &g_HID_au8MouseReportDescriptor; usbdInfo.u32HIDRPTDescriptorLen = g_HID_u32MouseReportDescriptorSize; usbdInfo.pfnEPACallBack = EPA_Handler; g_u8EPAReady = 1; #endif #ifdef HID_KEYBOARD /* Set the HID report descriptor */ usbdInfo.pu32HIDRPTDescriptor = (PUINT32) &g_HID_au8KeyboardReportDescriptor; usbdInfo.u32HIDRPTDescriptorLen = g_HID_u32KeyboardReportDescriptorSize; #endif usbdInfo.pu32StringDescriptor[0] = (PUINT32) &HID_StringDescriptor0; usbdInfo.pu32StringDescriptor[1] = (PUINT32) &HID_StringDescriptor1; usbdInfo.pu32StringDescriptor[2] = (PUINT32) &HID_StringDescriptor2; usbdInfo.pu32StringDescriptor[3] = (PUINT32) &HID_StringDescriptor3; /* Set Descriptor length */ usbdInfo.u32DevDescriptorLen = LEN_DEVICE; usbdInfo.u32HSConfDescriptorLen = LEN_CONFIG_AND_SUBORDINATE; usbdInfo.u32FSConfDescriptorLen = LEN_CONFIG_AND_SUBORDINATE; usbdInfo.u32StringDescriptorLen[0] = HID_STR0_DSCPT_LEN; usbdInfo.u32StringDescriptorLen[1] = HID_StringDescriptor1[0] = sizeof(HID_StringDescriptor1); usbdInfo.u32StringDescriptorLen[2] = HID_StringDescriptor2[0] = sizeof(HID_StringDescriptor2); usbdInfo.u32StringDescriptorLen[3] = HID_StringDescriptor3[0] = sizeof(HID_StringDescriptor3); }