SSD_HID KEYBOARD
1. 环境搭建¶
1.1. 修改kernel配置¶
添加配置:make menuconfig
-
usb Gadget 框架配置 -> Device Drivers -> USB support -> Device Drivers -> USB support -> USB Gadget Support
输出模块:usb-common.ko udc-core.ko
-
udc 驱动配置:该模块为硬件ip相关模块,视具体情况进行配置 -> Device Drivers -> USB support -> USB Gadget Support -> USB Peripheral Controller -> Sstar USB 2.0 Device Controller
输出模块:udc-msb250x.ko
-
gadget hid -> Device Drivers -> USB support -> USB Gadget Support -> USB Gadget Drivers -> Device Drivers -> USB support -> USB Gadget Support -> USB Gadget Drivers -> USB HID Gadget
输出模块:libcomposite.ko usb_f_hid.ko g_hid.ko
注意:
-
当配置选项为 y (可在kernel目录查看.config)时,代表该模块编译为builtin模式,默认编译进kernel内核,此时需将该Image替换烧录,通常生成为uImage.xz(目录arch/arm/boot/)文件。
-
当配置选项为 m 时,代表该模块编译为 module模式,在kernel/modules目录会生成相应 xxx.ko,此时需要将相应的文件在linux启动之后进行加载: insmod xxx.ko。
-
模块之前具有相应依赖关系,配置与加载都需要有先后顺序。
1.2. driver端修改¶
drivers/sstar/usb/gadget/udc/usb20/src/msb250x_gadget.c中的修改
修改msb250x_gadget_match_ep函数:
struct usb_ep* msb250x_gadget_match_ep(struct usb_gadget *g, struct usb_endpoint_descriptor *desc, struct usb_ss_ep_comp_descriptor *ep_comp) { ...... switch (usb_endpoint_type(desc)) { //case USB_ENDPOINT_XFER_INT: //MSB250X_INTR_EP(dev, ep); //break; } return ep; } 注意:如果同时支持键盘和鼠标的话,就需要注释上面的case部分;如果只支持鼠标或键盘时,上面的case不需要注释。
1.3. 板端的驱动加载顺序¶
#insmod /config/modules/4.9.84/ehci-hcd.ko //与host控制器相关,不需要加载 insmod /customer/usb-common.ko insmod /customer/udc-core.ko insmod /customer/libcomposite.ko insmod /customer/udc-msb250x.ko insmod /customer/usb_f_hid.ko out_enable=0 //说明:out_enable=0关闭out端点,防止部分平台因端点数量不够导致驱动无法正常运行。 insmod /customer/g_hid.ko hid_mode='composite' //说明:hid_mode='composite'同时支持keyboard和mouse。若只需要键盘,配置hid_mode='key'。若只需要鼠标,配置hid_mode='mouse'。
echo 4 > /proc/sys/kernel/printk insmod /config/modules/4.9.84/cifs.ko insmod /config/modules/4.9.84/nls_utf8.ko insmod /config/modules/4.9.84/grace.ko insmod /config/modules/4.9.84/sunrpc.ko insmod /config/modules/4.9.84/lockd.ko insmod /config/modules/4.9.84/nfs.ko insmod /config/modules/4.9.84/nfsv2.ko insmod /config/modules/4.9.84/mmc_core.ko insmod /config/modules/4.9.84/mmc_block.ko insmod /config/modules/4.9.84/kdrv_sdmmc.ko insmod /config/modules/4.9.84/fat.ko insmod /config/modules/4.9.84/msdos.ko insmod /config/modules/4.9.84/vfat.ko insmod /config/modules/4.9.84/ntfs.ko insmod /config/modules/4.9.84/sd_mod.ko insmod /config/modules/4.9.84/ms_notify.ko # kernel_mod_list insmod /config/modules/4.9.84/mhal.ko # misc_mod_list insmod /config/modules/4.9.84/mi_common.ko insmod /config/modules/4.9.84/mi_sys.ko cmdQBufSize=768 logBufSize=256 insmod /config/modules/4.9.84/mi_sensor.ko insmod /config/modules/4.9.84/mi_gfx.ko insmod /config/modules/4.9.84/mi_rgn.ko insmod /config/modules/4.9.84/mi_ai.ko insmod /config/modules/4.9.84/mi_vpe.ko insmod /config/modules/4.9.84/mi_pspi.ko insmod /config/modules/4.9.84/mi_shadow.ko insmod /config/modules/4.9.84/mi_gyro.ko insmod /config/modules/4.9.84/mi_ao.ko insmod /config/modules/4.9.84/mi_panel.ko insmod /config/modules/4.9.84/mi_disp.ko insmod /config/modules/4.9.84/mi_vif.ko insmod /config/modules/4.9.84/mi_venc.ko insmod /config/modules/4.9.84/mi_divp.ko insmod /config/modules/4.9.84/mi_vdisp.ko # mi module major=`cat /proc/devices | busybox awk "\\$2==\""mi_poll"\" {print \\$1}"` busybox mknod /dev/mi_poll c $major 0 insmod /config/modules/4.9.84/fbdev.ko # misc_mod_list_late insmod /config/modules/4.9.84/media.ko # insmod /config/modules/4.9.84/videodev.ko # insmod /config/modules/4.9.84/v4l2-common.ko # insmod /config/modules/4.9.84/usb-common.ko # insmod /config/modules/4.9.84/usbcore.ko # insmod /config/modules/4.9.84/ehci-hcd.ko # insmod /config/modules/4.9.84/scsi_mod.ko # insmod /config/modules/4.9.84/usb-storage.ko # insmod /config/modules/4.9.84/videobuf2-core.ko # insmod /config/modules/4.9.84/videobuf2-v4l2.ko # insmod /config/modules/4.9.84/videobuf2-memops.ko # insmod /config/modules/4.9.84/videobuf2-vmalloc.ko # insmod /config/modules/4.9.84/uvcvideo.ko insmod /customer/hid/usb-common.ko insmod /config/modules/4.9.84/usbcore.ko insmod /config/modules/4.9.84/scsi_mod.ko insmod /customer/hid/udc-core.ko insmod /customer/hid/libcomposite.ko insmod /customer/hid/udc-msb250x.ko insmod /customer/hid/usb_f_hid.ko out_enable=0 insmod /customer/hid/g_hid.ko hid_mode='key' # kernel_mod_list_late insmod /config/modules/4.9.84/gc1054_dual_MIPI.ko chmap=1 insmod /config/modules/4.9.84/gc1054_MIPI.ko chmap=2 mdev -s mkdir /var/tmp export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/customer/lib:/lib:/config/lib
重烧kernel并正确加载驱动后,会生成两个设备:/dev/hidg0和/dev/hidg1,其中/dev/hidg0代表键盘,/dev/hidg1代表鼠标。
2. USB Key board协议及过程¶
-
USB Key board需每次发送8Byte
-
如果是发送GBK 中文,第0个字节设为0x04
-
如果是发送特殊字符,如 !感叹号或大写字母A,需要Shift配合,第0个字节设为0x02
-
普通字符的发送,第0个字节设为0x00
-
发送过程,如下2个例子:
-
发送字母A
memset(report, 0, 8); report[0] = 0x02; report[2] = 0x04; //键盘上的‘A’, 协议规定键值为0x04 write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x02; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME();
-
发送中文GBK:会, ‘会’的GBK十进制值为48097
static unsigned char gKeyNumValue[10] = { /* 定义 0 ~ 9 对应的键值 */ 0x62, /*0*/ 0x59, /*1*/ 0x5A, /*2*/ 0x5B, /*3*/ 0x5C, /*4*/ 0x5D, /*5*/ 0x5E, /*6*/ 0x5F, /*7*/ 0x60, /*8*/ 0x61, /*9*/ }; while(1) //循环调用如下,依次发送4/8/0/9/7 { memset(report, 0, 8); report[0] = 0x04; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x04; report[2] = gKeyNumValue[buf[i]-'0']; write(key_fd, report, 8); DELAY_TIME(); } //End of one gbk sending, it should send the following memset(report, 0, 8); report[0] = 0x04; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME();
-
3. Code & Makefile¶
keyboard.cpp是完整的demo程序
3.1. App Demo¶
# include <stdio.h> # include <unistd.h> # include <stdlib.h> # include <stdbool.h> # include <poll.h> # include <string.h> # include <time.h> # include <signal.h> # include <fcntl.h> # include <pthread.h> # include <sys/types.h> # include <sys/socket.h> # include <sys/stat.h> # include <sys/time.h> # include <netinet/in.h> # include <netinet/tcp.h> //#include "common.h" # define Key_DevName "/dev/hidg0" static unsigned char gKeyNumValue[10] = { 0x62, /*0*/ 0x59, /*1*/ 0x5A, /*2*/ 0x5B, /*3*/ 0x5C, /*4*/ 0x5D, /*5*/ 0x5E, /*6*/ 0x5F, /*7*/ 0x60, /*8*/ 0x61, /*9*/ }; static int key_fd = -1; # ifdef DEBUG static int idx = 0; # endif # define DELAY_TIME() //usleep(50000) # define DELAY_WAIT_TIME() usleep(100*1000) static bool Hid_Send_OneGBKEnglish(const unsigned char charactor) { int offset = 0; static unsigned char charBase = 0x04; /* A or a */ unsigned char keyType = 0; unsigned char report[8] = {0}; if(charactor >= 'a' && charactor <= 'z') { keyType = 0; offset = charactor - 'a'; } else if(charactor >= 'A' && charactor <= 'Z') { keyType = 0x02; offset = charactor - 'A'; } else { printf("[fun:%s - Line:%d]unable to support charactor:0x%02x\n", __FUNCTION__, __LINE__, charactor); } memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = keyType; report[2] = charBase + offset; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = keyType; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); DELAY_WAIT_TIME(); return true; } static bool Hid_Send_OneGBKChinese(const unsigned char valueH, const unsigned char valueL) { int i; unsigned char buf[16] = {0}; unsigned char report[8] = {0}; unsigned short value = (valueH<<8) | valueL; memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset((unsigned char *)buf, 0, 16); sprintf((char *)buf, "%d", value); printf("value:%d buf:%s\n", value, buf); for(i=0; i<16; i++) { if(buf[i] == 0) { break; } memset(report, 0, 8); report[0] = 0x04; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x04; report[2] = gKeyNumValue[buf[i]-'0']; write(key_fd, report, 8); DELAY_TIME(); } //End of one gbk sending, it should send the following memset(report, 0, 8); report[0] = 0x04; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); DELAY_WAIT_TIME(); return true; } static bool Hid_Send_Enter() { unsigned char report[8] = {0}; memset(report, 0, 8); report[0] = 0x00; report[2] = 0x28; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); DELAY_WAIT_TIME(); return true; } static bool Hid_Send_Space() { unsigned char report[8] = {0}; memset(report, 0, 8); report[0] = 0x00; report[2] = 0x2C; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); DELAY_WAIT_TIME(); return true; } /************************** \1. From ~ to ? \2. From ` to / **************************/ static bool Hid_Send_Symbol(unsigned char symbol) { unsigned char keyType; unsigned char keyValue; unsigned char report[8] = {0}; memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); switch(symbol) { /*From 1 to / */ case '1': keyType = 0x00; keyValue = 0x1E; break; case '2': keyType = 0x00; keyValue = 0x1F; break; case '3': keyType = 0x00; keyValue = 0x20; break; case '4': keyType = 0x00; keyValue = 0x21; break; case '5': keyType = 0x00; keyValue = 0x22; break; case '6': keyType = 0x00; keyValue = 0x23; break; case '7': keyType = 0x00; keyValue = 0x24; break; case '8': keyType = 0x00; keyValue = 0x25; break; case '9': keyType = 0x00; keyValue = 0x26; break; case '0': keyType = 0x00; keyValue = 0x27; break; case '-': keyType = 0x00; keyValue = 0x2D; break; case '=': keyType = 0x00; keyValue = 0x2E; break; case '[': keyType = 0x00; keyValue = 0x2F; break; case ']': keyType = 0x00; keyValue = 0x30; break; case '\\': keyType = 0x00; keyValue = 0x31; break; case ';': keyType = 0x00; keyValue = 0x33; break; case '\'': keyType = 0x00; keyValue = 0x34; break; case '`': keyType = 0x00; keyValue = 0x35; break; case ',': keyType = 0x00; keyValue = 0x36; break; case '.': keyType = 0x00; keyValue = 0x37; break; case '/': keyType = 0x00; keyValue = 0x38; break; /*From ! to ?*/ case '!': keyType = 0x02; keyValue = 0x1E; break; case '@': keyType = 0x02; keyValue = 0x1F; break; case '#': keyType = 0x02; keyValue = 0x20; break; case '$': keyType = 0x02; keyValue = 0x21; break; case '%': keyType = 0x02; keyValue = 0x22; break; case '^': keyType = 0x02; keyValue = 0x23; break; case '&': keyType = 0x02; keyValue = 0x24; break; case '*': keyType = 0x02; keyValue = 0x25; break; case '(': keyType = 0x02; keyValue = 0x26; break; case ')': keyType = 0x02; keyValue = 0x27; break; case '_': keyType = 0x02; keyValue = 0x2D; break; case '+': keyType = 0x02; keyValue = 0x2E; break; case '{': keyType = 0x02; keyValue = 0x2F; break; case '}': keyType = 0x02; keyValue = 0x30; break; case '|': keyType = 0x02; keyValue = 0x31; break; case ':': keyType = 0x02; keyValue = 0x33; break; case '"': keyType = 0x02; keyValue = 0x34; break; case '~': keyType = 0x02; keyValue = 0x35; break; case '<': keyType = 0x02; keyValue = 0x36; break; case '>': keyType = 0x02; keyValue = 0x37; break; case '?': keyType = 0x02; keyValue = 0x38; break; default: printf("[fun:%s - Line:%d]unable to support symbol:0x%x\n", __FUNCTION__, __LINE__, symbol); return false; } memset(report, 0, 8); report[0] = keyType; report[2] = keyValue; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = keyType; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); memset(report, 0, 8); report[0] = 0x00; report[2] = 0x00; write(key_fd, report, 8); DELAY_TIME(); DELAY_WAIT_TIME(); return true; } static bool Hidg_Send_Test() { unsigned char charactor; sleep(5); Hid_Send_OneGBKChinese(0xBB, 0xE1); Hid_Send_OneGBKChinese(0xB5, 0xB1); Hid_Send_Space(); Hid_Send_Enter(); charactor = 'a'; while(charactor <= 'z') { Hid_Send_OneGBKEnglish(charactor++); Hid_Send_Space(); } Hid_Send_Enter(); charactor = 'A'; while(charactor <= 'Z') { Hid_Send_OneGBKEnglish(charactor++); Hid_Send_Space(); } Hid_Send_Enter(); Hid_Send_Symbol('`'); Hid_Send_Space(); Hid_Send_Symbol('1'); Hid_Send_Space(); Hid_Send_Symbol('2'); Hid_Send_Space(); Hid_Send_Symbol('3'); Hid_Send_Space(); Hid_Send_Symbol('4'); Hid_Send_Space(); Hid_Send_Symbol('5'); Hid_Send_Space(); Hid_Send_Symbol('6'); Hid_Send_Space(); Hid_Send_Symbol('7'); Hid_Send_Space(); Hid_Send_Symbol('8'); Hid_Send_Space(); Hid_Send_Symbol('9'); Hid_Send_Space(); Hid_Send_Symbol('0'); Hid_Send_Space(); Hid_Send_Symbol('-'); Hid_Send_Space(); Hid_Send_Symbol('='); Hid_Send_Space(); Hid_Send_Symbol('['); Hid_Send_Space(); Hid_Send_Symbol(']'); Hid_Send_Space(); Hid_Send_Symbol(';'); Hid_Send_Space(); Hid_Send_Symbol('\''); Hid_Send_Space(); Hid_Send_Symbol('\\'); Hid_Send_Space(); Hid_Send_Symbol(','); Hid_Send_Space(); Hid_Send_Symbol('.'); Hid_Send_Space(); Hid_Send_Symbol('/'); Hid_Send_Space(); Hid_Send_Enter(); Hid_Send_Symbol('~'); Hid_Send_Space(); Hid_Send_Symbol('!'); Hid_Send_Space(); Hid_Send_Symbol('@'); Hid_Send_Space(); Hid_Send_Symbol('#'); Hid_Send_Space(); Hid_Send_Symbol('$'); Hid_Send_Space(); Hid_Send_Symbol('%'); Hid_Send_Space(); Hid_Send_Symbol('^'); Hid_Send_Space(); Hid_Send_Symbol('&'); Hid_Send_Space(); Hid_Send_Symbol('*'); Hid_Send_Space(); Hid_Send_Symbol('('); Hid_Send_Space(); Hid_Send_Symbol(')'); Hid_Send_Space(); Hid_Send_Symbol('_'); Hid_Send_Space(); Hid_Send_Symbol('+'); Hid_Send_Space(); Hid_Send_Symbol('{'); Hid_Send_Space(); Hid_Send_Symbol('}'); Hid_Send_Space(); Hid_Send_Symbol(':'); Hid_Send_Space(); Hid_Send_Symbol('"'); Hid_Send_Space(); Hid_Send_Symbol('|'); Hid_Send_Space(); Hid_Send_Symbol('<'); Hid_Send_Space(); Hid_Send_Symbol('>'); Hid_Send_Space(); Hid_Send_Symbol('?'); Hid_Send_Space(); Hid_Send_Enter(); return true; } static bool Hidg_Dev_Init(char *key_path, char *mouse_path) { key_fd = open(key_path, O_RDWR, 0666); if(key_fd < 0) { return false; } return true; } static void Hidg_Dev_DeInit(void) { close(key_fd); } int main(int argc, char **argv) { if(!Hidg_Dev_Init((char *)Key_DevName, (char *)Key_DevName)) { printf("Hidg_Dev_Init err\n"); return -1; } Hidg_Send_Test(); return 0; }
3.2. Makefile¶
all:
arm-linux-gnueabihf-sigmastar-9.1.0-gcc keyboard.cpp -o key -lpthread arm-linux-gnueabihf-sigmastar-9.1.0-strip key
clean:
rm key