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 = {
.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 [email protected] 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 "[email protected] 3.2.24
00 04 07 05 02 03 40 00 [email protected] 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水很深,學了大概半個月了,也是一知半解。有錯誤的地方,請高手指點。。。