接著上期講
驅動程式支援哪些裝置?struct usb_device_id 結構提供了此驅動程式支援的不同型別的usb裝置的列表。USB核心使用此列表決定將裝置提供給哪個驅動程式,熱插拔指令碼使用此列表決定在將特定裝置插入系統時自動載入哪個驅動程式。
struct usb_device_id 結構由以下欄位定義:
match_flags 確定應與裝置匹配的結構中的以下哪些欄位idVendor 裝置的USB供應商IDidProduct 裝置的USB產品ID
有許多宏用於初始化此結構:
USB_DEVICE(vendor, product):建立一個struct usb_device_id ,該id只能用於匹配指定的供應商和產品id值。這是非常常用的USB裝置,需要一個特定的驅動程式。USB_DEVICE_VER(vendor, product, lo, hi) : 建立一個struct usb_device_id ,可用於在版本範圍內僅匹配指定的供應商和產品id值。USB_DEVICE_INFO(class, subclass, protocol):建立可用於匹配特定類別usb裝置的結構usb_device_idUSB_INTERFACE_INFO(class, subclass, protocol):建立可用於匹配特定usb介面類的結構usb_device_id因此,對於僅控制單個供應商的單個USB裝置的簡單USB裝置驅動程式,struct usb_device_id 表將定義為:
static struct usb_device_id skel_table [ ] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* Terminating entry */};
註冊USB驅動程式所有USB驅動程式必須建立的主要結構是struct usb_driver驅動程式。此結構必須由USB驅動程式填寫,並由許多函式回撥和變數組成,這些變數將USB驅動程式描述為USB核心程式碼:
1,struct module *owner 指向此驅動程式的模組所有者的指標。USB核心使用它來正確引用這個USB驅動程式,這樣它就不會在不合適的時候被解除安裝。該變數應設定為THIS_MODULE 宏。
2,const char *name 指向驅動程式名稱的指標。它在核心中的所有USB驅動程式中必須是唯一的,並且通常設定為與驅動程式的模組名相同的名稱。當驅動程式在核心中時,它顯示在/sys/bus/usb/drivers/下的sysfs中。
3,const struct usb_device_id *id_table 指向struct usb_device_id 表的指標,該表包含此驅動程式可以接受的所有不同型別的usb裝置的列表。如果未設定此變數,則永遠不會呼叫USB驅動程式中的探測函式(probe)回撥。如果希望系統中的每個USB裝置始終呼叫驅動程式,請建立一個僅設定驅動程式資訊欄位的條目:
static struct usb_device_id usb_ids[ ] = { {.driver_info = 42}, { }};
4,int (*probe) (struct usb_interface *intf, const struct usb_device_id *id)
指向USB驅動程式中探測函式的指標。這個函式是由USB核心呼叫的,當它認為它有一個struct usb_interface 介面,這個驅動程式可以處理。一個指向結構struct usb_device_id的指標,usb核心用來做這個決定,這個指標也被傳遞給這個函式。如果USB驅動程式宣告傳遞給它的struct usb_interface介面,它應該正確初始化裝置並返回0。如果驅動程式不想宣告裝置,或者發生錯誤,它應該返回負的錯誤值。
當安裝了USB核心認為該驅動程式應該處理的裝置時,將呼叫probe函式;probe函式應該檢查傳遞給它的關於該裝置的資訊,並確定驅動程式是否真的適合該裝置。當驅動程式由於某種原因不再控制裝置並且可以進行清理時,將呼叫disconnect函式。
5,void (*disconnect) (struct usb_interface *intf)
指向USB驅動程式中斷開連線功能的指標。當struct usb_interface介面已從系統中移除或驅動程式正在從USB core解除安裝時,USB core將呼叫此函式
註冊:
使用函式 usb_register_driver 將struct usb_driver序註冊到usb core
備註:我們使用的是usb_register 去註冊(此函式就會呼叫usb_register_driver)
怎麼寫USB裝置驅動程式?總體步驟:
1. 分配/設定usb_driver結構體
.id_table .probe .disconnect2. 註冊usb_driver
3,進行相關操作(在probe函式中進行)
(1)分配一個input_dev結構體(2)設定能產生哪類事件及產生這類事件中具體哪一種(3)設定資料長度,資料來源和目的(4)分配一個usb_buffer(5)分配一個usb_urb(6)填充一個usb_urb(7)提交usb_urb驅動程式原始碼#include <linux/kernel.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/usb/input.h>#include <linux/hid.h>#include <linux/module.h>#include <linux/kmod.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/workqueue.h>#include <linux/mii.h>#include <linux/usb.h>#include <linux/crc32.h>static struct input_dev *usb_mouse_dev;static char *usb_mouse_buf;static dma_addr_t usb_mouse_dma_phy;static int buf_length;static struct urb *usb_mouse_urb;//函式宣告static void display_information(struct usb_device *dev );static void usb_mouse_irq(struct urb *urb);static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id){ //printk("doubixiaohanhan usb_mouse_probe "); struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; int pipe; display_information(dev); usb_mouse_dev = input_allocate_device();//分配input_dev 結構體 set_bit(EV_KEY,usb_mouse_dev->evbit); set_bit(EV_REP,usb_mouse_dev->evbit); set_bit(KEY_L,usb_mouse_dev->keybit); set_bit(KEY_S,usb_mouse_dev->keybit); set_bit(KEY_ENTER,usb_mouse_dev->keybit); input_register_device(usb_mouse_dev);//註冊 //硬體操作 interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints != 1) return -ENODEV; endpoint = &interface->endpoint[0].desc; if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);//源 buf_length = endpoint->wMaxPacketSize;//長度 usb_mouse_buf = usb_buffer_alloc(dev, buf_length, GFP_ATOMIC, &usb_mouse_dma_phy);//目的 //分配URB usb_mouse_urb = usb_alloc_urb(0, GFP_KERNEL); //initialize a interrupt urb usb_fill_int_urb(usb_mouse_urb, dev, pipe, usb_mouse_buf,buf_length, usb_mouse_irq, NULL, endpoint->bInterval); usb_mouse_urb->transfer_dma = usb_mouse_dma_phy; usb_mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_submit_urb (usb_mouse_urb, GFP_ATOMIC); return 0;}static void usb_mouse_irq(struct urb *urb){ int i; static unsigned char pre_val; static int count = 0; printk("data count %d: ",count); for(i = 0;i < buf_length;i ++) { printk("%02x: ",usb_mouse_buf[i]); } printk("\n"); if((pre_val & (1 << 0) ) != ( (usb_mouse_buf[0]) & (1 << 0))) { input_event(usb_mouse_dev,EV_KEY,KEY_L,( (usb_mouse_buf[0]) & (1 << 0)) ? 1:0 ); input_sync(usb_mouse_dev); } else if((pre_val & (1 << 1) ) != ( (usb_mouse_buf[0]) & (1 << 1))) { input_event(usb_mouse_dev,EV_KEY,KEY_S,( (usb_mouse_buf[0]) & (1 << 1)) ? 1:0 ); input_sync(usb_mouse_dev); } else if((pre_val & (1 << 2) ) != ( (usb_mouse_buf[0]) & (1 << 2))) { input_event(usb_mouse_dev,EV_KEY,KEY_ENTER,( (usb_mouse_buf[0]) & (1 << 2)) ? 1:0 ); input_sync(usb_mouse_dev); } else; pre_val = usb_mouse_buf[0]; usb_submit_urb (usb_mouse_urb, GFP_ATOMIC);}static void usb_mouse_disconnect(struct usb_interface *intf){ struct usb_device *dev = interface_to_usbdev(intf); usb_kill_urb(usb_mouse_urb); usb_free_urb(usb_mouse_urb); usb_buffer_free(dev, buf_length, usb_mouse_buf, usb_mouse_dma_phy); input_unregister_device(usb_mouse_dev); input_free_device(usb_mouse_dev); }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 */};static struct usb_driver usb_mouse_driver = { .name = "usbmouse", .probe = usb_mouse_probe, .disconnect = usb_mouse_disconnect, .id_table = usb_mouse_id_table,};static int usb_driver_init(void){ int retval = usb_register(&usb_mouse_driver); if (retval == 0) printk("usb driver device register successful"); return retval;}static void usb_driver_exit(void){ usb_deregister(&usb_mouse_driver); }static void display_information(struct usb_device *dev ){ printk(" bcdUSB = %x\n ",dev->descriptor.bcdUSB); printk(" idVendor = %x\n ",dev->descriptor.idVendor); printk(" idProduct = %x\n ",dev->descriptor.idProduct); printk(" iManufacturer = %x\n ",dev->descriptor.iManufacturer); printk(" iProduct = %x\n ",dev->descriptor.iProduct); printk(" iSerialNumber = %x\n ",dev->descriptor.iSerialNumber); }module_init(usb_driver_init);module_exit(usb_driver_exit);MODULE_LICENSE("GPL");