編寫USB驅(qū)動程序步驟: 1所有usb驅(qū)動都必須創(chuàng)建主要結(jié)構(gòu)體struct usb_driver struct usb_driver ->struct module *owner (有他可正確對該驅(qū)動程序引用計數(shù),應(yīng)為THIS_MODULE) ->const char *name (驅(qū)動名字,運行時可在查看 /sys/bus/usb/drivers/) ->const struct usb_device_id *id_table (包含該驅(qū)動可支持的所有不同類型的驅(qū)動設(shè)備,沒添探測回調(diào)函數(shù)不會被調(diào)用) ->int (*probe)(struct usb_interface *intf,const struct usb_device_id *id) (usb驅(qū)動探測函數(shù),確認(rèn)后struct usb_interface 應(yīng)恰當(dāng)初始化,然后返0,如果出錯則返負(fù)值) ->void(*disconnect)(struct usb_interface *intf) (當(dāng)struct usb_interface 被從系統(tǒng)中移除或驅(qū)動正從usb核心中卸載時,usb核心將調(diào)用此函數(shù)) 代碼實例: static struct usb_driver skel_driver={ .owner = THIS_MODULE, .name = "skeleton", .id_table = skel_table, .probe = skel_probe, .disconnect = skel_disconnect, }; ↓ 2usb_register()注冊將struct usb_driver 注冊到usb核心,傳統(tǒng)是在usb驅(qū)動程序模塊初始化代碼中完成該工作的 static int __init usb_skel_init(void) { ... usb_register(&skel_driver); ... } ↓ 3struct usb_device_id usb核心用該表判斷哪個設(shè)備該使用哪個驅(qū)動程序,熱插拔腳本使用它來確定當(dāng)一個特定的設(shè)備插入到系統(tǒng)時該自動裝載哪個驅(qū)動程序。 ->__u16 match_flags(確定設(shè)備和結(jié)構(gòu)體中下列字段中哪一個相匹配) ->__u16 idVendor(設(shè)備的usb制造商id) ->__u16 idProduct(設(shè)備的usb產(chǎn)品id) ↓ 4USB骨架程序的關(guān)鍵幾點如下: 1. USB驅(qū)動的注冊和注銷 Usb驅(qū)動程序在注冊時會發(fā)送一個命令給usb_register,通常在驅(qū)動程序的初始化函數(shù)里。 當(dāng)要從系統(tǒng)卸載驅(qū)動程序時,需要注銷usb子系統(tǒng)。即需要usb_unregister 函數(shù)處理。 2 當(dāng)usb設(shè)備插入時,為了使linux-hotplug(Linux中PCI、USB等設(shè)備熱插拔支持)系統(tǒng)自動裝載驅(qū)動程序,你需要創(chuàng)建一個MODULE_DEVICE_TABLE。代碼如下(這個模塊僅支持某一特定設(shè)備): static struct usb_device_id skel_table [] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* Terminating entry */}; MODULE_DEVICE_TABLE (usb, skel_table); USB_DEVICE宏利用廠商ID和產(chǎn)品ID為我們提供了一個設(shè)備的唯一標(biāo)識。當(dāng)系統(tǒng)插入一個ID匹配的USB設(shè)備到USB總線時,驅(qū)動會在USB core中注冊。驅(qū)動程序中probe 函數(shù)也就會被調(diào)用。usb_device 結(jié)構(gòu)指針、接口號和接口ID都會被傳遞到函數(shù)中。 3 static void * skel_probe(struct usb_device *dev,unsigned int ifnum, const struct usb_device_id *id) 驅(qū)動程序需要確認(rèn)插入的設(shè)備是否可以被接受,如果不接受,或者在初始化的過程中發(fā)生任何錯誤,probe函數(shù)返回一個NULL值。否則返回一個含有設(shè)備驅(qū)動程序狀態(tài)的指針。通過這個指針,就可以訪問所有結(jié)構(gòu)中的回調(diào)函數(shù)。 4 在骨架驅(qū)動程序里,最后一點是我們要注冊devfs。我們創(chuàng)建一個緩沖用來保存那些被發(fā)送給usb設(shè)備的數(shù)據(jù)和那些從設(shè)備上接受的數(shù)據(jù),同時USB urb 被初始化,并且我們在devfs子系統(tǒng)中注冊設(shè)備,允許devfs用戶訪問我們的設(shè)備。注冊過程如下:
/* initialize the devfs node for this device and register it */sprintf(name, "skel%d", skel->;minor); skel->devfs = devfs_register (usb_devfs_handle, name,DEVFS_FL_DEFAULT, USB_MAJOR,USB_SKEL_MINOR_BASE + skel->minor, S_IFCHR | S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP | S_IROTH, &skel_fops, NULL); 如果devfs_register函數(shù)失敗,不用擔(dān)心,devfs子系統(tǒng)會將此情況報告給用戶。 當(dāng)然最后,如果設(shè)備從usb總線拔掉,設(shè)備指針會調(diào)用disconnect 函數(shù)。驅(qū)動程序就需要清除那些被分配了的所有私有數(shù)據(jù)、關(guān)閉urbs,并且從devfs上注銷調(diào)自己。 /* remove our devfs node */devfs_unregister(skel->;devfs); ↓ 5其他 1 struct usb_host_endpoint(描述usb端點) →(包含) struct usb_endpoint_descriptor(含真正端點信息,數(shù)據(jù)格式,是真正驅(qū)動關(guān)心的字段) 端點描述符: bEndpointAddress = 81(in)(第8位為1是輸入設(shè)備)(usb的端點地址,包含端點方向) bmAttibutes = 03(interrupt)(端點類型,為中斷傳輸) wMaxPacketSize = 0008(每次傳8個字節(jié))(端點每次可處理最大字節(jié)長度) bInterval = 08(8ms)(如端點為中斷,該值為輪詢間隔) 2 usb端點捆綁為接口,usb接口只處理一種usb邏輯連接,如鼠標(biāo)鍵盤等. 一個usb設(shè)備可有多接口,usb揚聲器:一個usb鍵盤用于按鍵,一個usb音頻流,則需兩個不同的驅(qū)動程序。 usb驅(qū)動 通常將struct usb_interface 轉(zhuǎn)成 struct usb_device 用函數(shù) interface_to_usbdev轉(zhuǎn) 3 struct usb_interface 描述usb接口 →struct usb_host_interface * altsetting(接口結(jié)構(gòu)體數(shù)組,包含所有可能用于該接口的可選設(shè)置) →struct usb_host_endpoint →unsigned num_altsetting(可選設(shè)置的數(shù)量) →struct usb_host_interface * cur_altsetting(接口當(dāng)前活動設(shè)置) →int minor(usb核心分配給接口的次設(shè)備號,成功調(diào)用usb_register_dev有效) 4 usb設(shè)備非常復(fù)雜,由許多不同邏輯單元組成,簡單關(guān)系如下: 設(shè)備通常有一個以上的配置 配置經(jīng)常有一個以上接口 接口通常有一個以上設(shè)置 接口通常有一個以上端點 設(shè)備描述-》配置描述-》接口描述-》端點描述 5 usb sysfs設(shè)備命名方案 根集線器-集線器端口號:配置。接口 對于usb hub樹中層次更高的字樹命名方案 根集線器-集線器端口號-集線器端口號:配置。接口 6 linux內(nèi)核的代碼通過一個成為urb(usb請求塊)和所有usb設(shè)備通信. 用struct urb描述(include/linux/usb.h中定義) ->urb用異步同usb設(shè)備特定usb端點發(fā)送/接收數(shù)據(jù),使用類似網(wǎng)絡(luò)代碼中的struct skbuff -> urb 被動態(tài)創(chuàng)建,隨時可被驅(qū)動程序或usb核心取消,內(nèi)部有引用計數(shù),可被多次調(diào)用,使他們可在最后一個使用者釋放他們時自動地銷毀 -> urb使得流處理或其他復(fù)雜的重疊的通信成為可能,獲得高數(shù)據(jù)傳輸速度。 ->usb_alloc_urb() 創(chuàng)建urb包 usb_free_urb() 釋放urb包 ->usb_fill_int_urb()正確初始化將發(fā)送到usb設(shè)備的中斷端點urb usb_fill_bulk_urb() .. .. .. ... 批量傳輸端點urb usb_fill_control_urb() .. .. .. ... 控制端點urb 等時urb在提交給核心時必須手動初始化(很不幸,沒函數(shù)) ->usb_submit_urb()urb被usb驅(qū)動正確創(chuàng)建和初始化后,就可提交到usb核心,發(fā)送到usb設(shè)備上了,如果調(diào)用成功,函數(shù)返0,urb控制權(quán)轉(zhuǎn)給usb核心 ->usb_kill_urb() or usb_unlink_urb()取消已經(jīng)被提交給核心的urb
|