利用USB OTG把ARM板(瑞芯微RK3568/3588+Linux)模拟为键盘和鼠标

现在大量的ARM CPU芯片都可以支持USB OTG2.0/3.0接口,该接口往往工作为USB Host,用于连接USB设备,同时用该OTG接口用于烧写镜像和固件。不过该接口也可以在Linux下作为USB设备工作,此时ARM板卡可以通过该OTG,将ARM板本身配置为键盘、鼠标,甚至是U盘,将OTG口通过USB线与PC机相连,直接在ARM板和PC机之间进行数据传送。下面以RK3568为实例,将RK3568板的Linux系统上配置为键盘和鼠标工作。

一、Linux配置和编译
1.1 内核驱动配置
通过make menuconfig将OTG口配置为DRD(Dual Role Mode),同时使能Gadget详细如下描述。

  Device Drivers  ---> 
    [*] USB support  ---> 
        <*>   DesignWare USB2 DRD Core Support
                DWC2 Mode Selection (Dual Role mode)  --->

        <*>   USB Gadget Support  ---> 
                 --- USB Gadget Support
                  (500) Maximum VBUS Power usage (2-500 mA)
                  (2)   Number of storage pipeline buffers
                  <M>   USB Gadget Drivers
                  <M>   USB functions configurable through configfs
                  [*]   Mass storage
                  <M>   Gadget Filesyste
                  < >   Function Filesystem
                  <M>     Mass Storage Gadget  -- 这个做U盘时选用

1.2 键盘和鼠标的代码

最核心的就是descriptor的描述,将OTG接口配置为hidg功能模块。

键盘的描述,以下时按照101键盘定义的,如果需要支持特定的键盘,可以修改此描述表。
static struct hidg_func_descriptor kvm_hid_keyboard_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                         */
    }
};

以下是标准三键鼠标的定义。

/*hid descriptor for a mouse*/
static struct hidg_func_descriptor kvm_hid_mouse_data = {
    .subclass = 0, /*NO SubClass*/
    .protocol = 2, /*Mouse*/
    .report_length = 4, //绝对值是6, 相对值是4不然打死调不通,实际很简单。但是没有全面了解协议是很难发现这些细节的
    .report_desc_length = 52, //126,//62,//104,
    .report_desc={
    0x05, 0x01, // USAGE_PAGE (Generic Desktop)
    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 (Button 1)
    0x29, 0x03, // USAGE_MAXIMUM (Button 3)
    0x15, 0x00, // LOGICAL_MINIMUM (0)
    0x25, 0x01, // LOGICAL_MAXIMUM (1)
    0x95, 0x03, // REPORT_COUNT (3)
    0x75, 0x01, // REPORT_SIZE (1)
    0x81, 0x02, // INPUT (Data,Var,Abs)
    0x95, 0x01, // REPORT_COUNT (1)
    0x75, 0x05, // REPORT_SIZE (5)
    0x81, 0x03, // INPUT (Cnst,Ary,Abs)
    0x05, 0x01, // USAGE_PAGE (Generic Desktop)
    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,Var,Rel)
    0xc0, // END_COLLECTION
    0xc0, // END_COLLECTION
    }
};
然后给出键盘和鼠标的驱动定义


static struct platform_device kvm_hid_keyboard = {
    .name            = "hidg",
    .id                = 0,
    .num_resources    = 0,
    .resource        = 0,
    .dev.platform_data    = &kvm_hid_keyboard_data,
};

static struct platform_device kvm_hid_mouse = {
    .name            = "hidg",
    .id                = 1,
    .num_resources    = 0,
    .resource        = 0,
    .dev.platform_data    = &kvm_hid_mouse_data,
};

有了以上的定义和驱动,后续用hidg驱动对键盘和鼠标驱动进行控制和probe即可。

static struct usb_device_descriptor device_desc = {
    .bLength =        sizeof device_desc,
    .bDescriptorType =    USB_DT_DEVICE,

    /* .bcdUSB = DYNAMIC */

    /* .bDeviceClass =        USB_CLASS_COMM, */
    /* .bDeviceSubClass =    0, */
    /* .bDeviceProtocol =    0, */
    .bDeviceClass =        USB_CLASS_PER_INTERFACE,
    .bDeviceSubClass =    0,
    .bDeviceProtocol =    0,
    /* .bMaxPacketSize0 = f(hardware) */

    /* Vendor and product id can be overridden by module parameters.  */
    .idVendor =        cpu_to_le16(HIDG_VENDOR_NUM),
    .idProduct =        cpu_to_le16(HIDG_PRODUCT_NUM),
    /* .bcdDevice = f(hardware) */
    /* .iManufacturer = DYNAMIC */
    /* .iProduct = DYNAMIC */
    /* NO SERIAL NUMBER */
    .bNumConfigurations =    1,
};
 

static struct usb_composite_driver hidg_driver = {
    .name        = "g_hid",
    .dev        = &device_desc,
    .strings    = dev_strings,
    .max_speed    = USB_SPEED_HIGH,
    .bind        = hid_bind,
    .unbind        = hid_unbind,
};

static struct platform_driver hidg_plat_driver = {
    .remove        = hidg_plat_driver_remove,
    .driver        = {
        .name    = "hidg",
    },
};
注意这几个驱动加载的顺序

static int __init hidg_init(void)
{
    int status;

    status = platform_device_register(&kvm_hid_mouse);
        if (status < 0) {
                return status;
        }

    status = platform_device_register(&kvm_hid_keyboard);
        if (status < 0) {
                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)
{
    usb_composite_unregister(&hidg_driver);
    platform_driver_unregister(&hidg_plat_driver);
    platform_device_unregister(&kvm_hid_keyboard);
    platform_device_unregister(&kvm_hid_mouse);
}
module_exit(hidg_cleanup);

二、ARM板Linux系统上USB键盘和鼠标模拟

加载以上模块后,在OTG的USB口插入键盘和鼠标,系统就可以找到键盘和鼠标。然后用编程的方式可以控制相连的对端主机设备。

根据配置的不同,有可能会需要从命令行中切换OTG口为USB device或者host。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值