LINUX 自定义USB Gadget HID 设备
最近在搞自定义的Gadget hid设备,内核版本:LINUX3.15 使用开发板:ATMEL SAMA5D3 编译环境:Ubuntu 12.04
首先配置内核,进入Device driver 菜单
[*] USB support --->
进入此菜单
选择最后一项 <*> USB Gadget Support --->
--- USB Gadget Support
│ │ [*] Debugging messages (DEVELOPMENT)
│ │ [*] Verbose debugging Messages (DEVELOPMENT)
│ │ [*] Debugging information files (DEVELOPMENT)
│ │ [*] Debugging information files in debugfs (DEVELOPMENT)
│ │ (2) Maximum VBUS Power usage (2-500 mA)
│ │ (2) Number of storage pipeline buffers
│ │ USB Peripheral Controller --->
│ │ <*> USB Gadget Drivers (HID Gadget) --->
│ │
进入最后一项
配置最后一项 (X) HID Gadget
保存退出。
2、添加设备
hid相关源码在linux内核源码下的driver/usb/gadget/里面。
首先打开hid.c 文件
在/****************************** Some noise ******************************/
下面你会看到driver的结构体变量
static __refdata struct usb_composite_driver hidg_driver = {
.name = "g_hid",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_HIGH,
.bind = hid_bind,
.unbind = __exit_p(hid_unbind),
};
static struct platform_driver hidg_plat_driver = {
.remove = hidg_plat_driver_remove,
.driver = {
.owner = THIS_MODULE,
.name = "hidg",
},
};
这里我们只需要添加与platform_driver 相对应的device就行了usb_composite_driver 不需要添加device 。下面是我添加的设备
struct platform_device hidg_plat_device = {
.name = "hidg",
.id = 0,
.num_resources = 0,
.resource = 0,
.dev.platform_data = &hidg_plat_pdata,
};
另外hidg_plat_pdata需要根据自己需要匹配报告描述符。可以是键盘、鼠标、或者是HID-complant-device。配置完后记得要注册进内核。
我们在hidg_init初始化函数里面进行注册。
status = platform_device_register(&hidg_plat_device);
if (status < 0)
return status;
同样在内核卸载函数hidg_cleanup里面进行卸载处理platform_device_unregister(&hidg_plat_driver);
更改完后,编译内核。烧尽开发板。
3、解决错误
为了观察我们自定义的hid设备是否成功,我们打开bus hound 软件。这时,当你插上usb设备。在bus hound上面也行会显示下面的信息:
------ ----- ------------------------ ---------------- ----- ------------------ ------------
21.0 CTL 80 06 00 01 00 00 12 00 GET DESCRIPTOR 2.8sc 1.1.0 13:45:02.40921.0 IN 12 01 00 02 00 00 00 40 .......@ 7.0ms 1.2.0 13:45:02.416
83 04 05 00 15 03 01 02 ........ 1.2.8
00 01 .. 1.2.16
21.0 CTL 80 06 00 02 00 00 09 00 GET DESCRIPTOR 35us 2.1.0 13:45:02.416
21.0 IN 09 02 29 00 01 01 00 c0 ..)..... 7.0ms 2.2.0 13:45:02.423
01 . 2.2.8
21.0 CTL 80 06 00 02 00 00 29 00 GET DESCRIPTOR 36us 3.1.0 13:45:02.423
21.0 IN 09 02 29 00 01 01 00 c0 ..)..... 7.0ms 3.2.0 13:45:02.430
01 09 04 00 00 02 03 00 ........ 3.2.8
00 04 09 21 01 01 00 01 ...!.... 3.2.16
22 54 00 07 05 81 03 40 "T.....@ 3.2.24
00 04 07 05 02 03 40 00 ......@. 3.2.32
04 . 3.2.40
21.0 CTL 00 09 01 00 00 00 00 00 SET CONFIG 17us 4.1.0 13:45:02.430
21.0 CTL 21 0a 00 00 00 00 00 00 SET IDLE 63ms 5.1.0 13:45:02.494
21.0 USTS c0000004 stall pid 11ms 5.2.0 13:45:02.505
21.0 CTL 81 06 00 22 00 00 94 00 GET DESCRIPTOR 14us 6.1.0 13:45:02.505
21.0 IN 05 ff 09 ff a1 01 85 01 ........ 14ms 6.2.0 13:45:02.519
05 01 19 00 29 ff 15 00 ....)... 6.2.8
25 ff 75 3f 95 08 81 02 %.u?.... 6.2.16
05 02 19 00 29 ff 15 00 ....)... 6.2.24
25 ff 75 3f 95 08 91 02 %.u?.... 6.2.32
c0 05 01 09 06 a1 01 85 ........ 6.2.40
02 05 07 19 e0 29 e7 15 .....).. 6.2.48
00 25 01 95 08 75 01 81 .%...u.. 6.2.56
02 95 01 75 08 81 03 95 ...u.... 6.2.64
06 75 08 25 ff 19 00 29 .u.%...) 6.2.72
65 81 00 c0 e... 6.2.80
我们发现中间有一行错误信息 USTS c0000004 stall pid 11ms 5.2.0 13:45:02.505 。这是window提示的错误。
这是主机在获取 描述符时没有获取到,当我的设备(当然不是所有的设备)收到主机发送的请求bRequest=0a时,在driver/usb/gadget/f_hid.c文件的hidg_setup函数, 发现没有匹配的选项,就直接进入default:
printk( "Unknown request 0x%x\n", ctrl->bRequest);
goto stall;
break;
直接结束了,这样主机就没有枚举成功,为了让主机继续枚举下去,我们在这个函数中加了一个选项。在default上面添加如下代码
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
| USB_REQ_GET_INTERFACE):
VDBG(cdev, "get_interface | wLenght=%d\n", ctrl->wLength);
/* send an empty report */
length = min_t(unsigned, length, hidg->report_length);
memset(req->buf, 0x0, length);
goto respond;
break;
//patched by hds
default:
printk( "Unknown request 0x%x\n", ctrl->bRequest);
goto stall;
break;
保存,编译内核,加载内核。插上设备发现错误没有出现。
但是当我通信的时候去出现了下面的错误
IN 01 ea fd 01 01 55 00 00 .....U.. 520ms 2002.1.0 17:24:32.392
00 00 00 00 00 00 00 00 ........ 2002.1.8
00 00 00 00 00 00 00 00 ........ 2002.1.16
00 00 00 00 00 00 00 00 ........ 2002.1.24
19 IN 01 ea fd 01 01 55 00 00 .....U.. 19us 2003.1.0 17:24:32.392
00 00 00 00 00 00 00 00 ........ 2003.1.8
00 00 00 00 00 00 00 00 ........ 2003.1.16
00 00 00 00 00 00 00 00 ........ 2003.1.24
18.2 OUT 01 ca ee 01 ce 00 00 00 ........ 966us 2004.1.0 17:24:32.393
00 00 00 00 00 00 00 00 ........ 2004.1.8
00 00 00 00 00 00 00 00 ........ 2004.1.16
00 00 00 00 00 00 00 00 ........ 2004.1.24
19 OUT 01 ca ee 01 ce 00 00 00 ........ 9us 2005.1.0 17:24:32.393
00 00 00 00 00 00 00 00 ........ 2005.1.8
00 00 00 00 00 00 00 00 ........ 2005.1.16
00 00 00 00 00 00 00 00 ........ 2005.1.24
18.1 IN 01 ea fe 01 01 b1 00 00 ........ 520ms 2006.1.0 17:24:32.913
00 00 00 00 00 00 00 00 ........ 2006.1.8
00 00 00 00 00 00 00 00 ........ 2006.1.16
00 00 00 00 00 00 00 00 ........ 2006.1.24
19 IN 01 ea fe 01 01 b1 00 00 ........ 15us 2007.1.0 17:24:32.913
00 00 00 00 00 00 00 00 ........ 2007.1.8
00 00 00 00 00 00 00 00 ........ 2007.1.16
00 00 00 00 00 00 00 00 ........ 2007.1.24
18.2 USTS c0000011 xact error 2.9ms 2008.1.0 17:24:32.916
18.1 IN 01 ea ff 01 01 1a 00 00 ........ 526ms 2009.1.0 17:24:33.443
00 00 00 00 00 00 00 00 ........ 2009.1.8
00 00 00 00 00 00 00 00 ........ 2009.1.16
00 00 00 00 00 00 00 00 ........ 2009.1.24
19 IN 01 ea ff 01 01 1a 00 00 ........ 18us 2010.1.0 17:24:33.443
00 00 00 00 00 00 00 00 ........ 2010.1.8
00 00 00 00 00 00 00 00 ........ 2010.1.16
00 00 00 00 00 00 00 00 ........ 2010.1.24
18.2 USTS c0000030 endpoint halted 138us 2011.1.0 17:24:33.443
每次交互读写几分钟后就出现这样的错误。
哎,大概找个一个礼拜的时间,把内核调试信息都打开了,什么调试信息更是加的哪里都有。整的很乱。。。
首先,大概许多同学还不知道怎么打开当前内核文件的调试信息的,我也是网上搜的,这里跟大家一起分享一下。
1、打开调试开关:你调试的文件中必然包含了<linux/device.h>,或者《linux/paltforam_device.h》,后者包含了前者,在包含此头文件之前,使用#define DEBUG 1 来打开调试开关:例如
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#define DEBUG 1
#include <linux/platform_device.h>
但是这个打开了之后,也不能顺利的输出信息,原因是printk有默认的信息级别。
2、修改文件kernel/printk文件
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
/* We show everything that is MORE important than this.. */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
#define DEFAULT_CONSOLE_LOGLEVEL 8 /* anything MORE serious than KERN_DEBUG */
其中DEFAULT_CONSOLE_LOGLEVEL为终端console输出的最低级别,比这严重的都将输出。原来该值为7,则调试信息无法输出,修改为8则全部有输出
。
听老大讲,是因为2方面。
1、我用的是台式机的前面插口,这的插口电流没有后面足,而且这usb接口是经主板引接过来的,会有信号损耗。
2、我连接usb设备的usb线也选择的太长了,有一米多吧。2者加起来,导致信号丢失。造成window报错。
主要还是因为第一点,直接把线拔掉插在后面usb接口,错误不在出现了。
感觉usb水很深,学了大概半个月了,也是一知半解。有错误的地方,请高手指点。。。
更多推荐
所有评论(0)