開發環境: 平臺: DM8168 內核 :linux 2.6.32 RDK:DVRRDK_04.00.00.03 USB口:DM8168有兩個USB口可供選擇,由於特殊緣由我選擇的是USB1,請根據實際須要選擇USB口 ,下面的配置會稍微有些不一樣。php
##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。 摘錄以下:linux
Menuconfig->Device Drviers->USB Support <> Support for Host-side USB
[ ] USB verbose debug messages
[] USB announce new devices
*** Miscellaneous USB options ***
...... <*> USB Gadget Support --->網絡
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 messageside
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測試
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 hubsui
完成以上步驟,先保存退出。 ##2設備註冊 爲了實現設備被識別,需加入設備註冊。修改hid.c 路徑: DVRRDK_04.00.00.03/ti_tools/linux_lsp/kernel/linux-dvr-rdk/drivers/usb/gadget。 因爲鼠標鍵盤爲常見USB設備,設備描述符很好獲得,若是是要自定義hid設備請參照usb協議.pdf(網絡上很容易找到)。 修改以下spa
#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.net
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).debug
編譯內核 以及 上方修改的代碼 ,根據本身的開發環境編譯 個人是 make lsp ##4測試3d
經過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 <module>.ko (eg: #insert g_ether.ko) Insert the gadget
module for usb1 port.
insmod <module>.ko (eg: #insert g_file_storage.kofile=<filepath> 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完成的,思路和代碼大致是按其思路,只有修改了個別設備描述符。