linux驅動之usb鼠標按鍵的讀取

上一篇博文只是usb總線驅動程序的框架,下面來真正寫一個usb驅動程序。

USB鼠標驅動,鼠標輸入HID類型,其數據傳輸採用中斷URB,鼠標端點類型爲IN

目的:usb鼠標按鍵的驅動代碼編寫:

框架:

  1. 分配一個input_dev結構體
  2. 設置
  3. 註冊
  4. 硬件相關的操作

思路:

1、分配/設置usb_driver結構體

static struct usb_driver usb_mouse_driver = {
	.name		= "usbmouse",
	.probe		= usb_mouse_probe,
	.disconnect	= usb_mouse_disconnect,
	.id_table	= usb_mouse_id_table,
};

a.這個結構體中有兩個函數:1、dev和drv匹配之後會調用probe函數,2、usb鼠標拔出後會調用disconnect函數3、id_table 支持項

支持項中有三個匹配項:接口類,接口子類,接口協議

usb鼠標使用的支持項爲:

static struct usb_device_id usb_mouse_id_table [] = {
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_MOUSE) },
	{ }	/* Terminating entry */
};

b.大部分工作都在probe函數中完成,先寫出usb_mouse_probe函數原型,逐漸完善它,我們truct usb_interface *intf, const struct usb_device_id *id)
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    return 0;
}
以上就是基本的框架,只要usb鼠標插上之後,就會調用 probe函數

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面完成具體的操作:

c、還是用輸入子系統的套路:

  • 分配
  • 設置
  • 註冊
  • 硬件的相關操作

c.1分配

static struct input_dev *um_dev;

um_dev = input_allocate_device();

這樣就分配了一個input_dev結構體。

c.2設置

需要設置兩方面的內容:1能產生哪些類事件,2能產生這個這些類裏面的具體哪個事件。

	/*b.1能產生哪類事件*/
	set_bit(EV_KEY,um_dev->evbit);
	set_bit(EV_REP,um_dev->evbit);
	/*b.2能產生這類裏面的哪些事件*/
	set_bit(KEY_L,um_dev->keybit);
	set_bit(KEY_S,um_dev->keybit);
	set_bit(KEY_ENTER,um_dev->keybit);

EV_KEY:按鍵事件。EV_REP:重複事件。

c.3註冊

只需要註冊 input_dev 結構體:

input_register_device(um_dev);

c.4硬件的相關操作

這個部分主要是設置數據的傳輸。數據傳輸圍繞三個要素:源、目的、長度

源:

pipe = usb_rcvintpipe(dev,endpoint->bEndpointAddress);

根據中斷端點獲取源。

長度:

length = endpoint->wMaxPacketSize;
目的:

usb_buf = usb_buffer_alloc(dev,length,GFP_ATOMIC,&usb_buf_phys);

usb數據會存儲在 usb_buf中。

d。使用這三個要素,完成最終的驅動程序-----》使用urb

urb處理流程:

  1. USB設備驅動程序創建並初始化一個訪問特定USB設備特定端點的urb,並提交給USB core
  2. USB core提交該urb到到USB主控制器驅動程序。
  3. USB主控制器驅動程序根據該urb描述的信息,來訪問usb設備
  4. 當設備訪問結束後,USB的主控制器驅動程序通知USB設備驅動程序。

	um_urb = usb_alloc_urb(0,GFP_KERNEL);
	/*使用三要素設置 urb*/
	usb_fill_int_urb(um_urb, dev, pipe,usb_buf,length,
				 usb_mouse_irq, NULL, endpoint->bInterval);
	um_urb->transfer_dma = usb_buf_phys;
	um_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	/*使用URB( 提交 urb)*/
	usb_submit_urb(um_urb,GFP_KERNEL);
說明1:

usb_alloc_urb(int iso_packets, gfp_t mem_flags);

iso_packets :是這個urb應當包含的等時數據包數目,若爲0:表示不創建等時數據包。

mem_flags   :是分配內存的標誌。

說明2:

對於中斷urb,使用usb_fill_int_urb來初始化urb。函數定義如下:

static inline void usb_fill_int_urb(struct urb *urb,
                    struct usb_device *dev,      //指向這個urb要被髮送的usb設備
                    unsigned int pipe,           //源
                    void *transfer_buffer,       //目的
                    int buffer_length,           //長度
                    usb_complete_t complete_fn,  //這個urb完成時,被調用的完成處理函數
                    void *context,               //完成處理函數的“上下文”
                    int interval)                //urb應當被調用的間隔

那麼在完成處理函數中就可以完成我們想做的東西:

例如,打印 usb鼠標傳回的數據

static void usb_mouse_irq(struct urb *urb)
{
	static unsigned char pre_val;

	int i;
	static int cnt =0;
	printk("data  cnt %d   ",++cnt);
	for(i=0;i<length;i++)
	{
		printk("%02x  ",usb_buf[i]);
	}
	printk("\n");
} 
這樣,一個完整的驅動程序基本就寫好了。完整的驅動代碼,我會在後面使用csdncode 地址的形式給出

測試:

1、make menuconfig 去掉原來的usb鼠標驅動

     -> Device Drivers                                                                                                                                  
         -> HID Devices (HID_SUPPORT [=y]) 
2、make

3、使用新內核

4、加載驅動

5、可以使用 hexdump /dev/event1 查看  插入USB鼠標新生成的event

6、或者使用 cat /dev/tty1


完整驅動程序地址:csdncode 源碼














發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章