1. 程式人生 > >LINUX 自定義USB Gadget HID 裝置

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.409  
  21.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水很深,學了大概半個月了,也是一知半解。有錯誤的地方,請高手指點。。。