RK3399 HID gadget 配置

        RK3399中提供了USB gadget设备的支持,程序在内核中目录“kernel/drivers/usb/gadget”中,支持的设备如U盘、USB串口、USB网卡、USB键盘鼠标等等,RK3399主板上有6个USB接口,其中的type-c接口是USB OTG接口,既支持USB HOST也支持USB DEVICE设备,要使RK3399配置成一个USB gadget设备(比如配置成一个hid 键盘),就得在type-c上实现,实际中这个功能有广泛的应用,比如pc主机和RK3399进行数据通信,用此就是一种很好的方式,RK3399的USB type-c接口初始时被配置成 Firefly-RK3399和ADB Interface设备,如下图:

        现在我们重新构建内核,把RK3399模拟成一个USB的HID键盘设备。分如下几个步骤进行:
        1、构建RK3399内核构建环境
        构建编译环境,参见:http://wiki.t-firefly.com/zh_CN/Firefly-RK3399/prepare_compile_android.html
        官方推荐 Ubuntu 14.04 操作系统,我安装的是 Ubuntu 16.04.1 ,完全可以
        安装android sdk:参见http://wiki.t-firefly.com/zh_CN/Firefly-RK3399/compile_android7.1_firmware.html
        编译环境的构建和android sdk的配置是一个比较复杂的过程,配置过程中会出现很多奇奇怪怪的问题,好在网上资料较多, 仔细分析,一般都能解决。
         2、修改hid.c文件,此文件在kernel/drivers/usb/gadget/legacy/目录下,增加以下内容:
(1)增加hidg_func_descriptor结构变量my_hid_data
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                         */
        }
    };

(2) 增加platform_device结构变量my_hid
static struct platform_device my_hid = {
    .name            = "hidg",
    .id                = 0,
    .num_resources    = 0,
    .resource        = 0,
    .dev.platform_data    = &my_hid_data,
};
(3)在hidg_init(void)函数中增加如下语句
status = platform_device_register(&my_hid);
    if (status < 0) {
        return status;
    }
(4)在hidg_cleanup(void)函数中增加如下语句
platform_device_unregister(&my_hid);

修改后完整的hid.c文件如下:
/*
 * hid.c -- HID Composite driver
 *
 * Based on multi.c
 *
 * Copyright (C) 2010 Fabien Chouteau <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */


#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb/composite.h>
#include <linux/usb/g_hid.h>

#define DRIVER_DESC            "HID Gadget"
#define DRIVER_VERSION        "2010/03/16"

#include "u_hid.h"

/*-------------------------------------------------------------------------*/

#define HIDG_VENDOR_NUM        0x0525    /* XXX NetChip */
#define HIDG_PRODUCT_NUM    0xa4ac    /* Linux-USB HID gadget */

/*-------------------------------------------------------------------------*/

struct hidg_func_node {
    struct usb_function_instance *fi;
    struct usb_function *f;
    struct list_head node;
    struct hidg_func_descriptor *func;
};

static LIST_HEAD(hidg_func_list);

/*dhl********************************************************************/
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                         */
        }
    };

/*dhl********************************************************************/

扫描二维码关注公众号,回复: 16768289 查看本文章


/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();

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

    .bcdUSB =        cpu_to_le16(0x0200),

    /* .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 const struct usb_descriptor_header *otg_desc[2];

/* string IDs are assigned dynamically */
static struct usb_string strings_dev[] = {
    [USB_GADGET_MANUFACTURER_IDX].s = "",
    [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
    [USB_GADGET_SERIAL_IDX].s = "",
    {  } /* end of list */
};

static struct usb_gadget_strings stringtab_dev = {
    .language    = 0x0409,    /* en-us */
    .strings    = strings_dev,
};

static struct usb_gadget_strings *dev_strings[] = {
    &stringtab_dev,
    NULL,
};

/****************************** Configurations ******************************/

static int do_config(struct usb_configuration *c)
{
    struct hidg_func_node *e, *n;
    int status = 0;

    if (gadget_is_otg(c->cdev->gadget)) {
        c->descriptors = otg_desc;
        c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
    }

    list_for_each_entry(e, &hidg_func_list, node) {
        e->f = usb_get_function(e->fi);
        if (IS_ERR(e->f))
            goto put;
        status = usb_add_function(c, e->f);
        if (status < 0) {
            usb_put_function(e->f);
            goto put;
        }
    }

    return 0;
put:
    list_for_each_entry(n, &hidg_func_list, node) {
        if (n == e)
            break;
        usb_remove_function(c, n->f);
        usb_put_function(n->f);
    }
    return status;
}

static struct usb_configuration config_driver = {
    .label            = "HID Gadget",
    .bConfigurationValue    = 1,
    /* .iConfiguration = DYNAMIC */
    .bmAttributes        = USB_CONFIG_ATT_SELFPOWER,
};

/****************************** Gadget Bind ******************************/

static int hid_bind(struct usb_composite_dev *cdev)
{
    struct usb_gadget *gadget = cdev->gadget;
    struct list_head *tmp;
    struct hidg_func_node *n, *m;
    struct f_hid_opts *hid_opts;
    int status, funcs = 0;

    list_for_each(tmp, &hidg_func_list)
        funcs++;

    if (!funcs)
        return -ENODEV;

    list_for_each_entry(n, &hidg_func_list, node) {
        n->fi = usb_get_function_instance("hid");
        if (IS_ERR(n->fi)) {
            status = PTR_ERR(n->fi);
            goto put;
        }
        hid_opts = container_of(n->fi, struct f_hid_opts, func_inst);
        hid_opts->subclass = n->func->subclass;
        hid_opts->protocol = n->func->protocol;
        hid_opts->report_length = n->func->report_length;
        hid_opts->report_desc_length = n->func->report_desc_length;
        hid_opts->report_desc = n->func->report_desc;
    }


    /* Allocate string descriptor numbers ... note that string
     * contents can be overridden by the composite_dev glue.
     */

    status = usb_string_ids_tab(cdev, strings_dev);
    if (status < 0)
        goto put;
    device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
    device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;

    if (gadget_is_otg(gadget) && !otg_desc[0]) {
        struct usb_descriptor_header *usb_desc;

        usb_desc = usb_otg_descriptor_alloc(gadget);
        if (!usb_desc)
            goto put;
        usb_otg_descriptor_init(gadget, usb_desc);
        otg_desc[0] = usb_desc;
        otg_desc[1] = NULL;
    }

    /* register our configuration */
    status = usb_add_config(cdev, &config_driver, do_config);
    if (status < 0)
        goto free_otg_desc;

    usb_composite_overwrite_options(cdev, &coverwrite);
    dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");

    return 0;

free_otg_desc:
    kfree(otg_desc[0]);
    otg_desc[0] = NULL;
put:
    list_for_each_entry(m, &hidg_func_list, node) {
        if (m == n)
            break;
        usb_put_function_instance(m->fi);
    }
    return status;
}

static int hid_unbind(struct usb_composite_dev *cdev)
{
    struct hidg_func_node *n;

    list_for_each_entry(n, &hidg_func_list, node) {
        usb_put_function(n->f);
        usb_put_function_instance(n->fi);
    }

    kfree(otg_desc[0]);
    otg_desc[0] = NULL;

    return 0;
}

static int hidg_plat_driver_probe(struct platform_device *pdev)
{
    struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
    struct hidg_func_node *entry;

    if (!func) {
        dev_err(&pdev->dev, "Platform data missing\n");
        return -ENODEV;
    }

    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
    if (!entry)
        return -ENOMEM;

    entry->func = func;
    list_add_tail(&entry->node, &hidg_func_list);

    return 0;
}

static int hidg_plat_driver_remove(struct platform_device *pdev)
{
    struct hidg_func_node *e, *n;

    list_for_each_entry_safe(e, n, &hidg_func_list, node) {
        list_del(&e->node);
        kfree(e);
    }

    return 0;
}


/****************************** Some noise ******************************/


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",
    },
};

/*dhl********************************************************************/

static struct platform_device my_hid = {
    .name            = "hidg",
    .id                = 0,
    .num_resources    = 0,
    .resource        = 0,
    .dev.platform_data    = &my_hid_data,
};
/*dhl********************************************************************/


MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
MODULE_LICENSE("GPL");

static int __init hidg_init(void)
{
    int status;
    
    /*dhl********************************************************************/
    printk("donghailin enter hid\n");
    status = platform_device_register(&my_hid);
    if (status < 0) {
        return status;
    }
    /*dhl********************************************************************/

    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;
    }

    return status;
}
module_init(hidg_init);

static void __exit hidg_cleanup(void)
{
    usb_composite_unregister(&hidg_driver);
    platform_driver_unregister(&hidg_plat_driver);

    /*dhl*********************************************************************/
    platform_device_unregister(&my_hid);
    /*dhl*********************************************************************/
}
module_exit(hidg_cleanup);
用以上的hid.c文件替换 “kernel/drivers/usb/gadget/legacy/”下的hid.c文件即可
        3、重新构建内核
        (1)修改内核配置
          进入 kernel目录,首先执行make ARCH=arm64 firefly_defconfig生成默认配置文件
          执行make menuconfig命令,按如配置下路径修改内核配置
           Device Drivers->USB support->USB Gadget support->具体配置如下图:

          
选择保存,配置保存到.config文件中。
        (2)kernel目录下执行make clean命令
        (3)kernel目录下执行make -j8 ARCH=arm64 rk3399-firefly.img命令

        (4)安装新内核,如下图

点击执行重新烧入新的内核,重新启动RK3399后,通过bus hound查看,没有发现usb设备,如下图:

            (5)安装内核模块
          将生成的内核模块libcomposite.ko、usb_f_hid.ko、g_hid.ko三个文件拷贝到RK3399的/sdcard/目录下,然后按如下顺序,执行命令
          insmod libcomposite.ko
          insmod usb_f_hid.ko
          insmod g_hid.ko
          当执行完最后一条命令后,正常情况下,你会听到你的pc会有发现新设备的提示声,到此你就成功了。在看一下bus hound如下图:

进入RK3399的/dev/目录,查看会发现新生成的hidg0设备,执行命令echo “123”>/dev/hidg0,在bus hound上查看,如下图:

猜你喜欢

转载自blog.csdn.net/donghailin/article/details/106096566
今日推荐