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