Linux USB驅動學習總結(三)---- USB滑鼠的載入、初始化和通信過程

来源:http://www.cnblogs.com/EaIE099/archive/2016/01/12/5124512.html
-Advertisement-
Play Games

1、usbmouse的定義:usb滑鼠既包含usb設備(usb_device)的屬性也包含input輸入設備(input_dev)的屬性struct usb_mouse {char name[128];///USB滑鼠設備名稱char phys[64];///路徑struct usb_device ...


1、usbmouse的定義:usb滑鼠既包含usb設備(usb_device)的屬性也包含input輸入設備(input_dev)的屬性

struct usb_mouse {

char name[128];///USB滑鼠設備名稱

char phys[64];///路徑

struct usb_device *usbdev;///USB設備

struct input_dev *dev;///Input 設備

struct urb *irq; ///urb結構體

 
signed char *data;///數據傳輸緩衝區指針

dma_addr_t data_dma;///

};

2、usbmouse的載入:

module_usb_driver(usb_mouse_driver);///系統啟動時註冊usb_mouse_driver

3、usbmouse的初始化:

 1 static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
 2 {
 3     struct usb_device *dev = interface_to_usbdev(intf);///通過 USB 介面來獲得 usb 設備
 4     struct usb_host_interface *interface;
 5     struct usb_endpoint_descriptor *endpoint;
 6     struct usb_mouse *mouse;
 7     struct input_dev *input_dev;
 8     int pipe, maxp;
 9     int error = -ENOMEM;
10 
11     interface = intf->cur_altsetting;///獲取 usb_host_interface
12 
13     if (interface->desc.bNumEndpoints != 1)/// usb滑鼠端點有且只有一個控制端點,否則返回 ENODEV 
14         return -ENODEV;
15 
16     endpoint = &interface->endpoint[0].desc; ///usb滑鼠只有一個端點,獲取端點描述符
17     if (!usb_endpoint_is_int_in(endpoint))///檢查端點是不是中斷類型的輸入端點
18         return -ENODEV;
19 
20     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);////獲取 pipe(),根據端點地址bEndpointAddress,中斷方式,IN端點就可以得到一個pipe,然後主機就知道跟誰去通信,該如何通信
21     maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));///獲取主機和設備一次通訊的最大位元組數
22 
23     mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);///分配一個usb_mouse
24     input_dev = input_allocate_device();///初始化 input 設備
25     if (!mouse || !input_dev)
26         goto fail1;
27 
28     mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);///為usbmouse的data 分配8個位元組的空間
29     if (!mouse->data)
30         goto fail1;
31 
32     mouse->irq = usb_alloc_urb(0, GFP_KERNEL);///申請分配 urb ,賦值給 usb_mouse 的 urb
33     if (!mouse->irq)
34         goto fail2;
35 
36     mouse->usbdev = dev; //設置usb滑鼠設備的usb設備對象
37     mouse->dev = input_dev;//設備usb滑鼠設備的input設備對象
38 
39     if (dev->manufacturer)///枚舉時候有獲取到有效的廠商名
40         strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));///複製廠商名到 name 
41 
42     if (dev->product) { //枚舉時候有獲取到有效的產品名
43         if (dev->manufacturer) //如果也有廠商名
44             strlcat(mouse->name, " ", sizeof(mouse->name));     //則用空格將廠商名和產品名隔開
45         strlcat(mouse->name, dev->product, sizeof(mouse->name));//追加產品名到name
46     }
47 
48     if (!strlen(mouse->name)) //如果廠商和產品名都沒有
49         snprintf(mouse->name, sizeof(mouse->name), //則直接根據廠商id和產品id給name賦值
50              "USB HIDBP Mouse %04x:%04x",
51              le16_to_cpu(dev->descriptor.idVendor),
52              le16_to_cpu(dev->descriptor.idProduct));
53 
54     usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); //設置設備路徑名
55     strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); //追加/input0
56 
57     input_dev->name = mouse->name; //輸入設備的名字設置成usb滑鼠的名字
58     input_dev->phys = mouse->phys; //輸入設備的路徑設置成usb滑鼠的路徑
59     usb_to_input_id(dev, &input_dev->id); //設置輸入設備的bustype,vendor,product,version
60     input_dev->dev.parent = &intf->dev; //usb介面設備為輸入設備的父設備
61 
62     ////evbit 關於設備支持事件類型的 bitmap 
63     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); ///BIT_MASK 找到參數值所在的 bit位,輸入事件按鍵類型 + 相對位移
64     input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | ///滑鼠支持左鍵、右鍵、中鍵三個按鍵
65         BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
66     input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); ///REL_X REL_Y 表示滑鼠的位置信息 x \ Y 
67     input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | ///在已有按鍵的基礎上加上一個邊鍵和一個而外的鍵
68         BIT_MASK(BTN_EXTRA);
69     input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);///給相對事件加上滾輪的事件
70 
71     input_set_drvdata(input_dev, mouse);///usb滑鼠驅動文件作為輸入設備的設備文件的驅動數據 " input_dev -> dev->driver_data = mouse "
72 
73     input_dev->open = usb_mouse_open; //設置輸入事件的打開方法
74     input_dev->close = usb_mouse_close; //設置輸入事件的關閉方法
75 
76     usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, ///初始化 urb (中斷傳輸方式),並指定 urb 的回調函數是 usb_mouse_irq
77              (maxp > 8 ? 8 : maxp),
78              usb_mouse_irq, mouse, endpoint->bInterval);//// usb_mouse_irq --回調函數,上下文信息 -- mouse
79     mouse->irq->transfer_dma = mouse->data_dma;//dma數據緩衝區指向usb滑鼠設備的data_dma成員
80     mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;///沒有 DMA 映射 
81 
82     error = input_register_device(mouse->dev);///註冊設備驅動 mouse->dev
83     if (error)
84         goto fail3;
85 
86     usb_set_intfdata(intf, mouse);///usb 滑鼠驅動文件作為 usb 介面設備的設備文件的驅動數據 ;intf->dev->driver_data = mouse ;
87     return 0;
88 
89 fail3:    
90     usb_free_urb(mouse->irq);
91 fail2:    
92     usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
93 fail1:    
94     input_free_device(input_dev);
95     kfree(mouse);
96     return error;
97 }

經過probe過程,註冊了輸入設備則會在/dev/input/目錄下會產生對應的滑鼠設備節點,應用程式可以打開該節點來控制usb滑鼠設備

關鍵函數調用順序:

.open   =   evdev_open,///上層應用程式通過系統調用open 打開設備

static int evdev_open(struct inode *inode, struct file *file);

evdev_open_device(evdev);

input_open_device(&evdev->handle);

dev->open(dev);////---->調用usbmouse_open()

input_dev->open = usb_mouse_open; //設置輸入事件的打開方法

usb_submit_urb(mouse->irq, GFP_KERNEL)

usb_mouse_irq(struct urb *urb)

input_report_key\input_report_rel\input_sync ///提交滑鼠數據給input 子系統

usb_submit_urb (urb, GFP_ATOMIC);///usb設備提交urb,主機再次輪詢usb設備

 

 

static int usb_mouse_open(struct input_dev *dev)
{
    struct usb_mouse *mouse = input_get_drvdata(dev); //通過輸入設備獲取usb滑鼠設備

    mouse->irq->dev = mouse->usbdev; //設置urb設備對應的usb設備
    if (usb_submit_urb(mouse->irq, GFP_KERNEL))///提交 urb ,只有打開設備的時候,才會把 urb 發送出去
        return -EIO;

    return 0;
}

 

 1 static void usb_mouse_irq(struct urb *urb)
 2 {
 3     struct usb_mouse *mouse = urb->context; ///獲取 usb 滑鼠設備
 4     signed char *data = mouse->data; ///數據傳輸緩衝區指針
 5     struct input_dev *dev = mouse->dev;//輸入設備
 6     int status;
 7 
 8     switch (urb->status) {///判斷 urb 傳輸的狀態
 9     case 0:            /* success */ ///傳輸成功跳出 switch
10         break;
11     case -ECONNRESET:    /* unlink */
12     case -ENOENT:
13     case -ESHUTDOWN:
14         return;
15     /* -EPIPE:  should clear the halt */
16     default:        /* error */
17         goto resubmit;
18     }
19 
20     input_report_key(dev, BTN_LEFT,   data[0] & 0x01);////提交按鍵信息,data[0] 的第 0 位為 1,表示左鍵按下
21     input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);////提交按鍵信息,data[0] 的第 1 位為 1,表示右鍵按下
22     input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);////提交按鍵信息,data[0] 的第 2 位為 1,表示中鍵按下
23     input_report_key(dev, BTN_SIDE,   data[0] & 0x08);////提交按鍵信息,data[0] 的第 3 位為 1,表示邊鍵按下
24     input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);////提交按鍵信息,data[0] 的第 4 位為 1,表示而外鍵按下
25 
26     input_report_rel(dev, REL_X,     data[1]);///提交滑鼠相對坐標值,data[1] 為 X 坐標
27     input_report_rel(dev, REL_Y,     data[2]);///提交滑鼠相對坐標值,data[2] 為 Y 坐標
28     input_report_rel(dev, REL_WHEEL, data[3]);///提交滑鼠滾輪相對值,data[3] 為 滾輪相對值
29 
30     input_sync(dev);///同步信息,表示上面的信息作為完整一幀傳遞給上層系統
31 resubmit:
32     status = usb_submit_urb (urb, GFP_ATOMIC);///usb設備提交urb,主機再次輪詢usb設備
33     if (status)
34         dev_err(&mouse->usbdev->dev,
35             "can't resubmit intr, %s-%s/input0, status %d\n",
36             mouse->usbdev->bus->bus_name,
37             mouse->usbdev->devpath, status);
38 }

 

 

 

(註:以上圖片來自麥子學院 金鑫老師的課程,在此對其辛勤付出和無私分享表示真摯的感謝!)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • oracle稱分析函數。與聚合函數相同,都是對行集合進行計算!但,由於group by的原因,每組只返回一個值。前者每組可以返回多個值。語法:函數名(列名) over(sql項)當over參數為null,即對所有行進行聚合計算例子: SELECT EmpID,DeptID,PostID, sum(P...
  • 快速建立原生(Native)的行動裝置應用程式: 程式代碼共用: 與 Visual Studio 整合: 確保第一時間更新: 原生的應用程式效能:
  • .net erp(辦公oa)開發平臺架構概要說明之表單設計器介紹
  • 有如下數組,要從中取出id: "[\"3812662409\",\"3812633637\",\"3812627686\",\"3812651467\",\"3812628047\",\"3812650203\"]" 正則匹配可以直接用(\d+),假定上述數組為變數名為input的字元串,C#中可以...
  • 1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System....
  • DateDiff 函數返回 Variant (Long) 的值,表示兩個指定日期間的時間間隔數目。語法 DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])DateDiff 函數語法中有下列命名參數:部分 描述 i...
  • 2013年以來自己因為偷懶,少寫了很多東西,今年計劃把以前積累的總結出來。先從shell開始寫起吧。幹了快3年游戲運維,期間經常會寫一些shell本,不少腳本其實有很多可以復用的部分。按照自己的風格,如果是比較重要的腳本,腳本內容可以分為3部分:輸入部分、核心邏輯部分、輸出部分。本文主要介紹輸入部分...
  • 一、配置防火牆,開啟80埠、3306埠CentOS 7.0預設使用的是firewall作為防火牆,這裡改為iptables防火牆。1、關閉firewall:systemctl stop firewalld.service#停止firewallsystemctl disable firewalld...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...