利用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。

### RK3568 USB OTG Configuration and Functionality For the Rockchip RK3568 SoC, configuring Universal Serial Bus On-The-Go (USB OTG) involves several key aspects including hardware support verification, driver setup, and system integration. The process begins with ensuring that the hardware supports USB OTG capabilities[^1]. This can be confirmed through documentation provided by manufacturers or technical brochures specific to the chip. Once hardware compatibility is established, software configuration plays a critical role in enabling USB OTG on RK3568 devices. Typically, this entails modifying device tree files which define how peripherals are connected within an embedded Linux environment. For instance: ```device-tree &usbotg { status = "okay"; }; ``` Additionally, kernel source code modifications might also be necessary depending upon requirements. These changes could involve adjusting existing drivers or adding new ones as required for proper operation of USB OTG features[^3]. Furthermore, application-level programming may require setting up interrupts using General Purpose Input Output (GPIO). An example from another context shows initialization steps involving GPIO requests and direction settings similar to what would apply when working with sensors like VL53L0X but adapted specifically towards managing USB connections[^2]: ```c gpio_request(gpio_pin_number, "usb_otg_gpio"); gpio_direction_input(gpio_pin_number); int irq = gpio_to_irq(gpio_pin_number); if (irq < 0) { printk(KERN_ERR "Failed to map GPIO: %d to interrupt:%d\n", gpio_pin_number, irq); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值