mtk 平板电脑模拟 HID 鼠标的实现方法

1、Linux USB HID gadget 驱动程序

(1)介绍
Linux HID gadget 驱动程序提供一种模拟 USB 人机接口设备(HID)的方式。基本的 HID 处理是在内核中完成的,并且 HID 报告可以通过字符设备 /dev/hidgX 来进行发送和接收。
有关 HID 的更多详细信息,请参阅 http://www.usb.org/developers/hidpage/

(2)配置
g_hid 是一个平台驱动程序,因此要使用它,需要添加结构 platform_device 到的内核平台代码,同时定义想要使用的 HID 函数描述符——比如类似这样:

#include <linux/platform_device.h>
#include <linux/usb/g_hid.h>

static struct hidg_func_descriptor my_hid_data = {
    .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 my_hid = {
    .name            = "hidg",
    .id            = 0,
    .num_resources        = 0,
    .resource        = 0,
    .dev.platform_data    = &my_hid_data,
};

2、如何实现 mtk 平板电脑模拟 HID 鼠标

(1)在 device/mediatek/mt6771/init.mt6771.usb.rc 中添加脚本,实现 USB gadget 切换到 HID:

on property:sys.usb.ffs.ready=1 && property:sys.usb.config=hid && \
property:vendor.usb.acm_enable=0 && property:sys.usb.configfs=1
    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "HID"
    write /config/usb_gadget/g1/idProduct 0x20FF
    write /config/usb_gadget/g1/functions/hid.gs0/subclass 0
    write /config/usb_gadget/g1/functions/hid.gs0/protocol 2
    symlink /config/usb_gadget/g1/functions/hid.gs0 /config/usb_gadget/g1/configs/b.1/f1
    write /config/usb_gadget/g1/UDC ${vendor.usb.controller}
    setprop sys.usb.state ${sys.usb.config}

(2)在 kernel-4.4/drivers/usb/gadget/function/f_hid.c 定义鼠标 HID 描述符:

static struct hidg_func_descriptor hid_data = {
    .subclass = 0,            // No subclass
    .protocol = 2,            // Mouse
    .report_length = 5,
    .report_desc_length = 74,
    .report_desc = {
        0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
        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 (0x01)
        0x29, 0x05,        //     Usage Maximum (0x05)
        0x15, 0x00,        //     Logical Minimum (0)
        0x25, 0x01,        //     Logical Maximum (1)
        0x95, 0x05,        //     Report Count (5)
        0x75, 0x01,        //     Report Size (1)
        0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x95, 0x01,        //     Report Count (1)
        0x75, 0x03,        //     Report Size (3)
        0x81, 0x01,        //     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
        0x09, 0x30,        //     Usage (X)
        0x15, 0x00,        //     Logical Minimum (0)
        0x26, 0xFF, 0x7F,  //     Logical Maximum (32767)
        0x35, 0x00,        //     Physical Minimum (0)
        0x46, 0xFF, 0x7F,  //     Physical Maximum (32767)
        0x75, 0x10,        //     Report Size (16)
        0x95, 0x01,        //     Report Count (1)
        0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
        0x09, 0x31,        //     Usage (Y)
        0x15, 0x00,        //     Logical Minimum (0)
        0x26, 0xFF, 0x7F,  //     Logical Maximum (32767)
        0x35, 0x00,        //     Physical Minimum (0)
        0x46, 0xFF, 0x7F,  //     Physical Maximum (32767)
        0x75, 0x10,        //     Report Size (16)
        0x95, 0x01,        //     Report Count (1)
        0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0xC0,              //   End Collection
        0xC0,              // End Collection
  }
};

(3)在平板电脑的 touchscreen 驱动里通过字符设备节点 /dev/hidg0 发送触摸消息(包括状态和坐标值)到 USB 主机:

int dev_exist(char *dev)
{
    struct file *fp = NULL;

    fp = filp_open(dev, O_RDWR, 0664);
    if (IS_ERR(fp))
     {
         return -1;
     }     

    return 0;
}

static int write_msg(const char* dev, char *buff, int size)
{
    mm_segment_t fs;
    loff_t pos;
    int ret;

    if(fp == NULL) {
        fp = filp_open(dev, O_RDWR, 0664);
        if (IS_ERR(fp))
        {
            filp_close(fp, NULL);
            fp = NULL;
            return -1;
        }
    }    

    fs = get_fs();
    set_fs(KERNEL_DS);
    pos = 0;
    ret = vfs_write(fp, buff, size, &pos);
    set_fs(fs);

    return 0;
}

void move_to(int state, int x, int y)
{
    char buf[5]={0,0,0,0,0};    
    buf[0] = state & 0xFF;
    buf[1] = x & 0xFF;
    buf[2] = (x >> 8) & 0xFF;
    buf[3] = y & 0xFF;
    buf[4] = (y >> 8) & 0xFF;
    // 发送触摸消息(包括状态和坐标值)
    write_msg("/dev/hidg0", buf , 5);
}

// touchscreen 上报触摸消息的工作队列处理函数
static void ts_work_func(struct work_struct *work) {
    ... // 省略部分代码
    // 检查是否存在 HID 字符设备节点
    if(dev_exist("/dev/hidg0") == 0) {
        move_to(state, input_x, input_y);
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值