当前位置: 首页 > news >正文

ARM板 usb gadget hid 模拟键鼠

说明

        在rv1106平台上内核版本5.10上通过usb口接入电脑,被电脑识别成鼠标和键盘,模拟成键盘鼠标设备 

一:修改内核配置

        1:增加hid gadget,这里直接编进内核了,进入到内核源码树,make ARCH=arm menuconfig

         Device Drivers--->USB support--->(*)USB Gadget Support--->USB Gadget precomposed configurations--->HID Gadget(*)

        2:usb host修改为usb device

        CONFIG_USB_DWC3=m
        CONFIG_USB_DWC3_GADGET=y

        

二:修改设备树

usb修改为从机模式

/**********USB**********/
&usbdrd_dwc3 {
    status = "okay";
    dr_mode="peripheral";//"host";//dr_mode = "peripheral";
};
 

三:修改hid源码增加键鼠描述符及设备注册

/home/hfzuo/rock/luckfox-pico/sysdrv/source/kernel/drivers/usb/gadget/legacy/hid.c

/* hid descriptor for a keyboard */

static struct hidg_func_descriptor pcduino_keyboard_date = {

    .subclass       = 0, /* No subclass */

    .protocol       = 1, /* Keyboard */

    .report_length      = 8,

    .report_desc_length = 63,

    .report_desc        = {

        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)                 */

        0x95, 0x01, /*   REPORT_COUNT (1)                     */

        0x75, 0x08, /*   REPORT_SIZE (8)                      */

        0x81, 0x03, /*   INPUT (Cnst,Var,Abs)                 */

        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)                */

        0x95, 0x01, /*   REPORT_COUNT (1)                     */

        0x75, 0x03, /*   REPORT_SIZE (3)                      */

        0x91, 0x03, /*   OUTPUT (Cnst,Var,Abs)                */

        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)             */

        0x29, 0x65, /*   USAGE_MAXIMUM (Keyboard Application) */

        0x81, 0x00, /*   INPUT (Data,Ary,Abs)                 */

        0xc0        /* END_COLLECTION                         */

    }

};

static struct platform_device pcduino_hid_keyboard = {

    .name           = "hidg",

    .id         = 0,

    .num_resources      = 0,

    .resource       = 0,

    .dev.platform_data  = &pcduino_keyboard_date,

};

/* hid descriptor for a mouse */

static struct hidg_func_descriptor pcduino_mouse_data = {

 .subclass = 0, //No SubClass

 .protocol = 2, //Mouse

 .report_length = 4,

 .report_desc_length = 52,

 .report_desc = {

 0x05, 0x01,  //Usage Page(Generic Desktop Controls)

 0x09, 0x02,  //Usage (Mouse)

 0xa1, 0x01,  //Collction (Application)

 0x09, 0x01,  //Usage (pointer)

 0xa1, 0x00,  //Collction (Physical)

 0x05, 0x09,  //Usage Page (Button)

 0x19, 0x01,  //Usage Minimum(1)

 0x29, 0x05,  //Usage Maximum(5)

 0x15, 0x00,  //Logical Minimum(1)

 0x25, 0x01,  //Logical Maximum(1)

 0x95, 0x05,  //Report Count(5)

 0x75, 0x01,  //Report Size(1)

 0x81, 0x02,  //Input(Data,Variable,Absolute,BitField)

 0x95, 0x01,  //Report Count(1)

 0x75, 0x03,  //Report Size(3)

 0x81, 0x01,  //Input(Constant,Array,Absolute,BitField)

 0x05, 0x01,  //Usage Page(Generic Desktop Controls)

 0x09, 0x30,  //Usage(x)

 0x09, 0x31,  //Usage(y)

 0x09, 0x38,  //Usage(Wheel)

 0x15, 0x81,  //Logical Minimum(-127)

 0x25, 0x7F,  //Logical Maximum(127)

 0x75, 0x08,  //Report Size(8)

 0x95, 0x03,  //Report Count(3)

 0x81, 0x06,  //Input(Data,Variable,Relative,BitField)

 0xc0,  //End Collection

 0xc0  //End Collection

 }

};

 

static struct platform_device pcduino_hid_mouse = {

 .name = "hidg",

 .id = 1,

 .num_resources = 0,

 .resource = 0,

 .dev.platform_data = &pcduino_mouse_data,

};

static int __init hidg_init(void)
{
	int status;
	status = platform_device_register(&pcduino_hid_keyboard);

    if (status < 0) {

        printk("hid keyboard  reg failed\n");

        platform_device_unregister(&pcduino_hid_keyboard);

        return status;

    }
    status = platform_device_register(&pcduino_hid_mouse);

    if (status < 0) {

        printk("hid mouse reg  failed\n");

        platform_device_unregister(&pcduino_hid_mouse);

        return status;

    }    
        
    status = platform_driver_probe(&hidg_plat_driver,
				hidg_plat_driver_probe);
	if (status < 0)
		return status;

	status = usb_composite_probe(&hidg_driver);
	if (status < 0)
		platform_driver_unregister(&hidg_plat_driver);

	return status;
}
module_init(hidg_init);

static void __exit hidg_cleanup(void)
{
    platform_device_unregister(&pcduino_hid_keyboard);
    platform_device_unregister(&pcduino_hid_mouse);
	usb_composite_unregister(&hidg_driver);
	platform_driver_unregister(&hidg_plat_driver);
}

四:加载驱动

insmod dwc3.ko     insmod dwc3-of-simple.ko,如果没问题就应该造 /sys/class/udc 下能找到udc

五:应用代码测试,模拟键鼠想电脑发送数据

/* hid_gadget_test */

#include <pthread.h>

#include <string.h>

#include <stdio.h>

#include <ctype.h>

#include <fcntl.h>

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#define BUF_LEN 512

struct options
{

    const char *opt;

    unsigned char val;
};

static struct options kmod[] = {
    {.opt = "-left - ctrl", .val = 0x01},

    {.opt = "-right - ctrl", .val = 0x10},

    {.opt = "-left - shift", .val = 0x02},

    {.opt = "-right - shift", .val = 0x20},

    {.opt = "-left - alt", .val = 0x04},

    {.opt = "-right - alt", .val = 0x40},

    {.opt = "-left - meta", .val = 0x08},

    {.opt = "-right - meta", .val = 0x80},

    {.opt = NULL}

};

static struct options kval[] = {

    {.opt = "-return", .val = 0x28},

    {.opt = "-esc", .val = 0x29},

    {.opt = "-bckspc", .val = 0x2a},

    {.opt = "-tab", .val = 0x2b},

    {.opt = "-spacebar", .val = 0x2c},
    {.opt = "-caps - lock", .val = 0x39},

    {.opt = "-f1", .val = 0x3a},

    {.opt = "-f2", .val = 0x3b},

    {.opt = "-f3", .val = 0x3c},

    {.opt = "-f4", .val = 0x3d},

    {.opt = "-f5", .val = 0x3e},

    {.opt = "-f6", .val = 0x3f},

    {.opt = "-f7", .val = 0x40},
    {.opt = "-f8", .val = 0x41},

    {.opt = "-f9", .val = 0x42},

    {.opt = "-f10", .val = 0x43},

    {.opt = "-f11", .val = 0x44},

    {.opt = "-f12", .val = 0x45},

    {.opt = "-insert", .val = 0x49},
    {.opt = "-home", .val = 0x4a},

    {.opt = "-pageup", .val = 0x4b},

    {.opt = "-del", .val = 0x4c},

    {.opt = "-end", .val = 0x4d},

    {.opt = "-pagedown", .val = 0x4e},

    {.opt = "-right", .val = 0x4f},

    {.opt = "-left", .val = 0x50},
    {.opt = "-down", .val = 0x51},

    {.opt = "-kp - enter", .val = 0x58},

    {.opt = "-up", .val = 0x52},
    {.opt = "-num - lock", .val = 0x53},

    {.opt = NULL}};

int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
{

    char *tok = strtok(buf, " ");

    int key = 0;

    int i = 0;

    for (; tok != NULL; tok = strtok(NULL, " "))
    {
        if (strcmp(tok, "-quit") == 0)

            return -1;
        if (strcmp(tok, "-hold") == 0)
        {

            *hold = 1;

            continue;
        }

        if (key < 6)
        {

            for (i = 0; kval[i].opt != NULL; i++)

                if (strcmp(tok, kval[i].opt) == 0)
                {

                    report[2 + key++] = kval[i].val;

                    break;
                }

            if (kval[i].opt != NULL)

                continue;
        }

        if (key < 6)
            if (islower(tok[0]))
            {

                report[2 + key++] = (tok[0] - ('a' - 0x04));

                continue;
            }

        for (i = 0; kmod[i].opt != NULL; i++)

            if (strcmp(tok, kmod[i].opt) == 0)
            {

                report[0] = report[0] | kmod[i].val;

                break;
            }

        if (kmod[i].opt != NULL)

            continue;

        if (key < 6)

            fprintf(stderr, "unknown option : % s\n", tok);
    }

    return 8;
}

static struct options mmod[] = {

    {.opt = "-b1", .val = 0x01},

    {.opt = "-b2", .val = 0x02},

    {.opt = "-b3", .val = 0x04},

    {.opt = NULL}

};

int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)

{

    char *tok = strtok(buf, " ");

    int mvt = 0;

    int i = 0;

    for (; tok != NULL; tok = strtok(NULL, " "))
    {

        if (strcmp(tok, "-quit") == 0)

            return -1;

        if (strcmp(tok, "-hold") == 0)
        {

            *hold = 1;

            continue;
        }

        for (i = 0; mmod[i].opt != NULL; i++)

            if (strcmp(tok, mmod[i].opt) == 0)
            {

                report[0] = report[0] | mmod[i].val;

                break;
            }

        if (mmod[i].opt != NULL)

            continue;

        if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2)
        {

            errno = 0;

            report[1 + mvt++] = (char)strtol(tok, NULL, 0);

            if (errno != 0)
            {

                fprintf(stderr, "Bad value :'% s'\n", tok);

                report[1 + mvt--] = 0;
            }

            continue;
        }

        fprintf(stderr, "unknown option : % s\n", tok);
    }

    return 3;
}

static struct options jmod[] = {

    {.opt = "-b1", .val = 0x10},

    {.opt = "-b2", .val = 0x20},

    {.opt = "-b3", .val = 0x40},

    {.opt = "-b4", .val = 0x80},

    {.opt = "-hat1", .val = 0x00},

    {.opt = "-hat2", .val = 0x01},

    {.opt = "-hat3", .val = 0x02},

    {.opt = "-hat4", .val = 0x03},

    {.opt = "-hatneutral", .val = 0x04},

    {.opt = NULL}

};

int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)

{

    char *tok = strtok(buf, " ");

    int mvt = 0;

    int i = 0;

    *hold = 1;

    /* set default hat position: neutral */

    report[3] = 0x04;

    for (; tok != NULL; tok = strtok(NULL, " "))
    {

        if (strcmp(tok, "-quit") == 0)

            return -1;

        for (i = 0; jmod[i].opt != NULL; i++)

            if (strcmp(tok, jmod[i].opt) == 0)
            {

                report[3] = (report[3] & 0xF0) | jmod[i].val;

                break;
            }

        if (jmod[i].opt != NULL)

            continue;

        if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3)
        {

            errno = 0;

            report[mvt++] = (char)strtol(tok, NULL, 0);

            if (errno != 0)
            {

                fprintf(stderr, "Bad value :'% s'\n", tok);

                report[mvt--] = 0;
            }

            continue;
        }

        fprintf(stderr, "unknown option : % s\n", tok);
    }

    return 4;
}

void print_options(char c)

{

    int i = 0;

    if (c == 'k')
    {

        printf(" keyboard options :\n"

               "        -hold\n");

        for (i = 0; kmod[i].opt != NULL; i++)

            printf("\t\t % s\n", kmod[i].opt);

        printf("\n keyboard values :\n"

               " [a - z] or\n");

        for (i = 0; kval[i].opt != NULL; i++)

            printf("\t\t % -8s % s", kval[i].opt, i % 2 ? "\n" : "");

        printf("\n");
    }
    else if (c == 'm')
    {

        printf(" mouse options :\n"

               "        -hold\n");

        for (i = 0; mmod[i].opt != NULL; i++)

            printf("\t\t % s\n", mmod[i].opt);

        printf("\n mouse values :\n"

               " Two signed numbers\n"

               "-quit to close\n");
    }
    else
    {

        printf(" joystick options :\n");

        for (i = 0; jmod[i].opt != NULL; i++)

            printf("\t\t % s\n", jmod[i].opt);

        printf("\n joystick values :\n"

               " three signed numbers\n"

               "-quit to close\n");
    }
}

int main(int argc, const char *argv[])

{

    const char *filename = NULL;

    int fd = 0;

    char buf[BUF_LEN];

    int cmd_len;

    char report[8];

    int to_send = 8;

    int hold = 0;

    fd_set rfds;

    int retval, i;

    if (argc < 3)
    {

        fprintf(stderr, "Usage : % s devname mouse | keyboard | joystick\n",

                argv[0]);

        return 1;
    }

    if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')

        return 2;

    filename = argv[1];

    if ((fd = open(filename, O_RDWR, 0666)) == -1)
    {

        perror(filename);

        return 3;
    }

    print_options(argv[2][0]);

    while (42)
    {

        FD_ZERO(&rfds);

        FD_SET(STDIN_FILENO, &rfds);

        FD_SET(fd, &rfds);

        retval = select(fd + 1, &rfds, NULL, NULL, NULL);

        if (retval == -1 && errno == EINTR)

            continue;

        if (retval < 0)
        {

            perror("select()");

            return 4;
        }

        if (FD_ISSET(fd, &rfds))
        {

            cmd_len = read(fd, buf, BUF_LEN - 1);

            printf("recv report :");

            for (i = 0; i < cmd_len; i++)

                printf(" % 02x", buf[i]);

            printf("\n");
        }

        if (FD_ISSET(STDIN_FILENO, &rfds))
        {

            memset(report, 0x0, sizeof(report));

            cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);

            if (cmd_len == 0)

                break;

            buf[cmd_len - 1] = '\0';

            hold = 0;

            memset(report, 0x0, sizeof(report));

            if (argv[2][0] == 'k')

                to_send = keyboard_fill_report(report, buf, &hold);

            else if (argv[2][0] == 'm')

                to_send = mouse_fill_report(report, buf, &hold);

            else

                to_send = joystick_fill_report(report, buf, &hold);

            if (to_send == -1)

                break;
            for(i=0;i<to_send;i++)
            {
                printf("data[%d]=%x\r\n",i,report[i]);
            }
            if (write(fd, report, to_send) != to_send)
            {

                perror(filename);

                return 5;
            }

            if (!hold)
            {

                memset(report, 0x0, sizeof(report));

                if (write(fd, report, to_send) != to_send)
                {

                    perror(filename);

                    return 6;
                }
            }
        }
    }

    close(fd);

    return 0;
}

./gadget_hid /dev/hidg1 k  终端按提示输入 a  b  即可看到键盘有输入a b

./gadget_hid /dev/hidg2 j -b3 -10 100  即可看到鼠标移动

五:键鼠数据分析

鼠标发送给 PC 的数据每次 4 个字节

BYTE1 BYTE2 BYTE3 BYTE4

定义分别是:

BYTE1 –

|–bit7:   1   表示   Y   坐标的变化量超出-256   ~   255 的范围,0 表示没有溢出

|–bit6:   1   表示   X   坐标的变化量超出-256   ~   255 的范围,0 表示没有溢出

|–bit5:   Y   坐标变化的符号位,1 表示负数,即鼠标向下移动

|–bit4:   X   坐标变化的符号位,1 表示负数,即鼠标向左移动

|–bit3:     恒为 1

|–bit2:     1 表示中键按下

|–bit1:     1 表示右键按下

|–bit0:     1 表示左键按下

BYTE2 — X 坐标变化量,与 byte 的 bit4 组成 9 位符号数,负数表示向左移,正数表右移。用补码表示变化量

BYTE3 — Y 坐标变化量,与 byte 的 bit5 组成 9 位符号数,负数表示向下移,正数表上移。用补码表示变化量

BYTE4 — 滚轮变化。

由于手上没有 USB 鼠标,对 BYTE1 的 4-7 位没有测试,对于 BYTE2 BYTE3 做个测试,BYTE1 的 4-7 全为 0 的时候,BYTE2 BYTE3 的正负表示鼠标移动方向

键盘发送给 PC 的数据每次 8 个字节

BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8

定义分别是:

BYTE1 –

|–bit0:   Left Control 是否按下,按下为 1

|–bit1:   Left Shift  是否按下,按下为 1

|–bit2:   Left Alt    是否按下,按下为 1

|–bit3:   Left GUI    是否按下,按下为 1

|–bit4:   Right Control 是否按下,按下为 1

|–bit5:   Right Shift 是否按下,按下为 1

|–bit6:   Right Alt   是否按下,按下为 1

|–bit7:   Right GUI   是否按下,按下为 1

BYTE2 — 暂不清楚,有的地方说是保留位

BYTE3–BYTE8 — 这六个为普通按键

键盘经过测试。

例如:键盘发送一帧数据   02 00 0×04 0×05 00 00 00 00

表示同时按下了 Left Shift + ‘a’+‘b’三个键

附件里面是 usb 协议中文版,喜欢折腾的可以看看。USB1.1 协议中文版

http://www.dtcms.com/a/106377.html

相关文章:

  • 基于 Jackson 的 JSON 工具类实现解析与设计模式应用
  • 网盘解析工具v1.3.1发布,希望能解决黑号问题吧
  • LTSPICE仿真电路:(二十四)MOS管推挽驱动电路简单仿真
  • 【idea】实用插件
  • Redis 03
  • HTML表单元素input
  • C++17更新内容汇总
  • CentOS 7 上安装 Hadoop 集群的详细教程
  • 华为2024年营收逼近历史峰值:终端业务复苏、智能汽车爆发式增长
  • Leetcode hot 100(day 3)
  • HDMI接口类型介绍
  • 在openharmony中部署helloworld应用(超详细)
  • 线段树,单点,区间修改查阅
  • 酶动力学预测工具CataPro安装教程
  • Rabbit:流加密的 “极速赛车手”
  • 单例模式与线程安全
  • 每日算法-250402
  • SESSION_UPLOAD_PROGRESS 的利用
  • Spark、Flink 和 TensorFlow 三大分布式数据处理框架对比
  • 微服务架构技术栈选型避坑指南:10大核心要素深度拆解
  • 供应链中的的“四流合一”
  • 以太网报文结构 via ethernetPacket in CAPL
  • 三轴云台之相机技术篇
  • JavaWeb开发基础知识-Servlet终极入门指南(曼波萌新版)
  • KingbaseES物理备份还原之物理备份
  • 单框架鸿蒙开发
  • 解决报错curl: (35) OpenSSL SSL_connect: 连接被对方重设 in connection to download.docker.com:443
  • JavaScript闭包
  • Python设计模式:责任链模式
  • JAVASE(十三)常用类(二)包装类、工具类Arrays类