DM816X 实现 USB HID Gadget 鼠标键盘功能

开发环境:
平台: DM8168
内核 :linux 2.6.32
RDK:DVRRDK_04.00.00.03
USB口:DM8168有两个USB口可供选择,因为特殊原因我选择的是USB1,请根据实际需要选择USB口
,下面的配置会稍微有些不同。

1配置内核

依据参照http://processors.wiki.ti.com/index.php/DM81xx_AM38XX_USB_User_Guide#Introduction
http://processors.wiki.ti.com/index.php/Usbgeneralpage#One_port_as_host_and_other_port_as_Gadget_.28for_DM81XX.29
摘录如下:

1) Select host and gadget support

Menuconfig->Device Drviers->USB Support

      <*>   Support for Host-side USB
      [ ]     USB verbose debug messages
      [*]     USB announce new devices
      *** Miscellaneous USB options ***
      ......
      <*>   USB Gadget Support  --->

2) Select USB OTG support (for TI816X)

Menuconfig->Device Drviers->USB Support

      <*>   Inventra Highspeed Dual Role Controller (TI, ADI, ...)
                   *** Platform Glue Layer ***
      < >     TUSB6010
      < >     OMAP2430 and onwards
      < >     AM35x
      <*>     TI81XX
              TI816X usb connector‘s ID pin control (from software setting)  --->
                        Force TI816X USB0 to  (Host mode)  --->
                        Force TI816X USB1 to  (Host mode)  --->
              Driver Mode (Both host and peripheral:  USB OTG (On The Go) Device)  --->
      [ ]   Disable DMA (always use PIO)
      [*]   Enable debugging messages

3) Select Gadget device controller and gadget driver as modules

Menuconfig->Device Drviers->USB Support

      <*>   USB Gadget Support  --->
            --- USB Gadget Support
            [ ]   Debugging messages (DEVELOPMENT) (NEW)
            [ ]   Debugging information files (DEVELOPMENT) (NEW)
            [ ]   Debugging information files in debugfs (DEVELOPMENT) (NEW)
            (2)   Maximum VBUS Power usage (2-500 mA) (NEW)
            USB Peripheral Controller (Inventra HDRC USB Peripheral (TI, ADI, ...))  --->
           <M>   USB Gadget Drivers
           <M>     Gadget Zero (DEVELOPMENT)
           [ ]       HNP Test Device (NEW)
           < >     Audio Gadget (EXPERIMENTAL) (NEW)
           <M>     Ethernet Gadget (with CDC Ethernet support)
           [*]       RNDIS support (NEW)
           [ ]       Ethernet Emulation Model (EEM) support (NEW)
           < >     Gadget Filesystem (EXPERIMENTAL) (NEW)
           < >     Function Filesystem (EXPERIMENTAL) (NEW)
           <M>     File-backed Storage Gadget
           [*]       File-backed Storage Gadget testing version

4) Unselect the OTG Targeted Peripherals list

Menuconfig->Device Drviers->USB Support

      <*>   Support for Host-side USB
            ....
           [*] USB runtime power management (autosuspend) and wakeup
           -*- OTG support
           [ ]   Rely on OTG Targeted Peripherals List
           [ ]   Disable external hubs

完成以上步骤,先保存退出。

2设备注册

为了实现设备被识别,需加入设备注册。修改hid.c 路径: DVRRDK_04.00.00.03/ti_tools/linux_lsp/kernel/linux-dvr-rdk/drivers/usb/gadget。
由于鼠标键盘为常见USB设备,设备描述符很好得到,如果是要自定义hid设备请参照usb协议.pdf(网络上很容易找到)。
修改如下

#include <linux/usb/g_hid.h>

/* hid descriptor for a keyboard */
static struct hidg_func_descriptor pcdm8168_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 pcdm8168_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,0x03,  /*Usage Maximum(3) */
        0x15,0x00,  /*Logical Minimum(1)*/
        0x25,0x01,  /*Logical Maximum(1)*/
        0x95,0x03,  /*Report Count(5)  */
        0x75,0x01,  /*Report Size(1)*/
        0x81,0x02,  /*Input(Data,Variable,Absolute,BitFiled)*/
        0x95,0x01,  /*Report Count(1)*/
        0x75,0x05,  /*Report Size(5) */
        0x81,0x01,  /*Input(Constant,Array,Absolute,BitFiled) */
        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,0x02,  /*Report Count(2)  */
        0x81,0x06,  /*Input(Data,Variable,Relative,BitFiled)*/
        0xc0,   /*End Collection*/
        0xc0    /*End Collection*/
    }
};

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

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

static int __init hidg_init(void)
{
    int status;

    status = platform_device_register(&pcdm8168_hid_keyboard);
    if (status < 0)
    {
        printk("platform_driver hid keyboard:*****wrong\n");
        platform_device_unregister(&pcdm8168_hid_keyboard);
        return status;
    }

    status = platform_device_register(&pcdm8168_hid_mouse);
    if (status < 0)
    {
        printk("platform_driver hid mouse:*****wrong\n");
        platform_device_unregister(&pcdm8168_hid_mouse);
        return status;
    }

    status = platform_driver_probe(&hidg_plat_driver,
                hidg_plat_driver_probe);
    if (status < 0)
    {
            printk("platform_driver_probe:*****wrong\n");
            return status;
    }
    status = usb_composite_probe(&hidg_driver, hid_bind);
    if (status < 0)
        platform_driver_unregister(&hidg_plat_driver);

    return status;
}
static void __exit hidg_cleanup(void)
{
    platform_driver_unregister(&hidg_plat_driver);
    platform_device_unregister(&pcdm8168_hid_keyboard);
    platform_device_unregister(&pcdm8168_hid_mouse);
    usb_composite_unregister(&hidg_driver);
}

3编译

继续完成内核配置的后续操作
1)Build uImage and usb gadget modules

Build the kernel image and the two usb gadget as modules (like
g_ether.ko, g_file_storage.ko, g_mass_storage.ko or g_zero.ko ..etc).

编译内核 以及 上方修改的代码 ,根据自己的开发环境编译
我的是 make lsp

4测试

通过USB线把8168板子和PC机 连接接起来。
1)Insert the two gadget modules

Load the kernel image and Make sure above setup is done before insert
the modules. Insert the gadget modules for usb0 port.

insmod .ko (eg: #insert g_ether.ko) Insert the gadget

module for usb1 port.

insmod .ko (eg: #insert g_file_storage.kofile= stall=0 buflen=65536)

8168上电,进入工作目录,make init 和 make load(个人需要)
由于我所用板子使用的是USB1,没有使用USB0,但是由于8168的特性,USB0也必须进行配置,
我的配置如下:
insmod g_ether.ko
insmod g_hid.ko

这时打开PC的设别管理器会发现,8168已经被识别成鼠标和键盘。
为了测试其功能是否正常需要写一小测试程序,
如下:

#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.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;
}

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( "    --quit to close\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");
        }
}

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\n",
            argv[0]);
        return 1;
    }

    if(argv[2][0] != ‘k‘ && argv[2][0] != ‘m‘)
    {
        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);

            if (to_send == -1)
                break;

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

需要交叉编译器进行编译,我使用的是arm-none-linux-gnueabi-gcc-4.3.3

编译完成后,把生成的执行文件cp到设备中分别执行
./pcdm8168_hid /dev/hidg0 k和./pcdm8168_hid /dev/hidg1 m
根据提示进行操作即可。



声明:上文是参考http://www.oschina.net/question/1174645_135969完成的,思路和代码大体是按其思路,只有修改了个别设备描述符。

时间: 2024-10-12 23:25:22

DM816X 实现 USB HID Gadget 鼠标键盘功能的相关文章

Qt移植对USB鼠标键盘、触摸屏的支持

.USB键盘 经过一番搜索,发现对Qt键盘的支持主要关系到两个方面: 1. 键盘类型确定: 4.7以前的Qt版本,如果是PS2圆孔键盘,Qt编译时需加上选项:-qt-kbd-vr41xx(未测试):如果是USB键盘,需加上-qt-kbd-usb选项. Qt4.7.3默认的是tty,对于USB键盘可用,不需要配置. 2.环境变量设置: 然后移植到目标板上,还需要设置环境变量QWS_KEYBOARD: $export QWS_KEYBOARD="USB:/dev/input/event0"

转 关于USB HID报告描述符

原文地址 USB HID报告及报告描述符简介 在USB中,USBHOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等.USB报 告描述符(ReportDescriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符.USBHID设备是通过报告来给传送数据的,报告 有输入报告和输出报告.输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等:输出 报告是主机发送在

USB HID描述符【转】

本文转载自: USB是个通用的总线,端口都是统一的.但是USB设备却各种各样,例如USB鼠标,USB键盘,U盘等等,那么USB主机是如何识别出不同的设备的呢?这就要依赖于描述符了.USB的描述符主要有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,HID描述符,报告描述符等等.关于报告描述符,请看我以前写的:<USB HID报告及报告描述符简介 > http://group.ednchina.com/93/198.aspx.一个USB设备有一个设备描述符,设备描述符里面决定了该设

Linux 模拟 鼠标 键盘 事件

/************************************************************************ * Linux 模拟 鼠标 键盘 事件 * 说明: * 以前看到有些软件能够控制鼠标移动,键盘操作等功能,总想知道这些到底 * 是怎么做到的,好像是2年前也尝试去做这件事,但那时候对知识的匮乏直接导致 * 无法进行,早上突然想到这件事,于是又搜索了一下,鉴于目前经常接触Linux * 驱动,对这些东西的理解也就很容易. * * 2016-2-27 深

Windows与自定义USB HID设备通信说明.

1 .   所使用的典型 Windows API CreateFile ReadFile WriteFile 以下函数是 DDK 的内容: HidD_SetFeature HidD_GetFeature HidD_SetOutputReport HidD_GetInputReport 其中, CreateFile 用于打开设备: ReadFile . HidD_GetFeature . HidD_GetInputReport 用于设备到主机方向的数据通信: WriteFile . HidD_Se

Delphi下利用WinIo模拟鼠标键盘详解

http://www.cnblogs.com/rogee/archive/2010/09/14/1827248.html 本文最早在编程论坛上发表,文章地址:http://programbbs.com/bbs/view12-17207-1.htm,相关文件可以在上述地址的页面中下载.转载时请注明出处. 前言 一日发现SendInput对某程序居然无效,无奈只好开始研究WinIo.上网查了很多资料,发现关于WinIo模拟鼠标键盘的资料很少,有的也只是支言片语讲的不是很详细,而且大部分都是关于模拟键

[BLE--HID]USB HID设备类定义

简述 HID设备,即人机交互设备,常见的有鼠标,键盘,游戏手柄,等等.一般有线方式都是通过USB连线连接到机器设备,作为用户输入设备.在蓝牙技术中,HID设备的接入就是无线的了.不过HID的相关定义当然还是一样的,不然设备驱动,兼容等问题都会有很多麻烦了.蓝牙中有HID, HOGP profile,但是只是在蓝牙数据通信上做的规范,HID具体含义相关,还是需要看USB相关的HID文档. USB设备类? USB设备可以在启动时,或者是在之后的连接状态下,都能够被主机进行配置.USB设备种类是非常多

USB HID报告及报告描述符简介

在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等.USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符.        USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告.输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等:输出报告是主机发送给USB设备的,例如键盘上的数字

C# 访问USB(HID)设备

原文:C# 访问USB(HID)设备 二话不说,直接给代码,如果您真想做这方面的东西,还是稍微研究下,没有现成的好类用,就需要自己了解其原理 //引用空间 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using S