国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

嵌入式Linux開發(fā)-USB驅(qū)動

這篇具有很好參考價值的文章主要介紹了嵌入式Linux開發(fā)-USB驅(qū)動。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

0.前言

哥們馬上就要被裁了,總得整理一下技術(shù)方面的積累,準(zhǔn)備開始下一輪的面試和找工作之旅了。。。。

1.概述

通用串行總線(USB)是主機(jī)和外圍設(shè)備之間的一種連接。
從拓?fù)渖蟻砜?,是一顆由幾個點(diǎn)對點(diǎn)的連接構(gòu)建而成的樹。這些連接是連接設(shè)備和集線器(hub)的四線電纜(底線、電源線和兩根信號線)。USB主控制器(host controller)負(fù)責(zé)詢問每一個USB設(shè)備是否有數(shù)據(jù)需要發(fā)送。
Linux內(nèi)核支持兩種主要類型的USB驅(qū)動程序:宿主(host)系統(tǒng)上的驅(qū)動程序和設(shè)備(device)上的驅(qū)動程序。宿主系統(tǒng)上的USB驅(qū)動程序控制插入其中的USB設(shè)備,USB設(shè)備的驅(qū)動程序控制該設(shè)備如何作為一個USB設(shè)備和主機(jī)通信。
USB驅(qū)動程序存在于不同的內(nèi)核子系統(tǒng)和USB硬件控制器之中,USB核心為USB驅(qū)動程序提供了一個用于訪問和控制USB硬件的接口。
嵌入式Linux開發(fā)-USB驅(qū)動

2.USB設(shè)備基礎(chǔ)

USB設(shè)備的構(gòu)成,包括配置、接口和端點(diǎn),以及USB驅(qū)動程序如何綁定到USB接口上,而不是整個USB設(shè)備
嵌入式Linux開發(fā)-USB驅(qū)動

  • 端點(diǎn)
    USB通信最基本的形式是通過一個名為端點(diǎn)(endpoint)的東西。USB端點(diǎn)只能往一個方向傳送數(shù)據(jù),從主機(jī)到設(shè)備(稱為輸出端點(diǎn))或者從設(shè)備到主機(jī)(稱為輸入端點(diǎn))。端點(diǎn)可以看作是單向的管道。
    有四種不同類型的端點(diǎn):
  • 控制
    用來控制對USB設(shè)備不同部分的訪問。通常用于配置設(shè)備、獲取設(shè)備信息、發(fā)送命令到設(shè)備或者獲取設(shè)備的狀態(tài)報告。每個USB設(shè)備都有一個名為“端點(diǎn)0”的控制端點(diǎn),USB核心使用該端點(diǎn)在插入時進(jìn)行設(shè)備的配置。
  • 中斷
    當(dāng)USB宿主要求設(shè)備傳輸數(shù)據(jù)時,中斷端點(diǎn)就以一個固定的速率來傳送少量的數(shù)據(jù)。通常還用于發(fā)送數(shù)據(jù)到USB設(shè)備以控制設(shè)備,一般不用來傳輸大量的數(shù)據(jù)。
  • 批量
    傳輸大批量的數(shù)據(jù)。常見于需要確保沒有數(shù)據(jù)丟失的傳輸?shù)脑O(shè)備。如果總線上的空間不足以發(fā)送整個批量包,它將被分割為多個包進(jìn)行傳輸。
  • 等時
    同樣可以傳送大批量的數(shù)據(jù),但數(shù)據(jù)是否到達(dá)是沒有保證的。實(shí)時的數(shù)據(jù)收集(例如音頻和視頻設(shè)備)幾乎毫無例外都使用這類端點(diǎn)。
    控制和批量端點(diǎn)用于異步的數(shù)據(jù)傳輸。中斷和等時端點(diǎn)是周期性的。
    內(nèi)核使用struct usb_host_endpoint結(jié)構(gòu)體來描述USB端點(diǎn)。該結(jié)構(gòu)體在另一個struct usb_endpoint_descriptor的結(jié)構(gòu)體中包含真正的端點(diǎn)信息。
    bEndpointAddress,特定端點(diǎn)的USB地址。還包含了端點(diǎn)的方向??梢越Y(jié)合位掩碼USB_DIR_OUT和USB_DIR_IN,以確定該端點(diǎn)的數(shù)據(jù)是傳向設(shè)備還是主機(jī)。
    bmAttributes,端點(diǎn)的類型。結(jié)合位掩碼USB_ENDPOINT_XFERTYPE_MASK,以確定此端點(diǎn)的類型是USB_ENDPOINT_XFER_ISOC(等時)、USB_ENDPOINT_XFER_BULK(批量)還是USB_ENDPOINT_XFER_INT(中斷)。
    wMaxPacketSize,該端點(diǎn)一次可以處理的最大字節(jié)數(shù)。驅(qū)動程序可以發(fā)送數(shù)量大于此值的數(shù)據(jù)到端點(diǎn),在實(shí)際傳輸?shù)皆O(shè)備時,數(shù)據(jù)將被分割為wMaxPacketSize大小的塊。
    bInterval,如果端點(diǎn)是中斷類型,該值是端點(diǎn)的間隔設(shè)置。
  • 接口
    USB接口只處理一種USB邏輯連接。內(nèi)核使用struct usb_interface結(jié)構(gòu)體來描述USB接口。USB核心把該結(jié)構(gòu)體傳遞給USB驅(qū)動程序,之后由USB驅(qū)動程序來負(fù)責(zé)控制該結(jié)構(gòu)體。
    struct usb_host_interface *altsetting,一個接口結(jié)構(gòu)體數(shù)組,包含所有可能用于該接口的可選設(shè)置。
    unsigned num_altsetting,altsetting指針?biāo)傅目蛇x設(shè)置的數(shù)量。
    struct usb_host_interface *cur_altsetting,指向altsetting數(shù)組內(nèi)部的指針,表示該接口的當(dāng)前活動設(shè)置。
    int minor,如果捆綁到該接口的USB驅(qū)動程序使用USB主設(shè)備號,這個變量包含USB核心分配給該接口的次設(shè)備號,僅在一個成功的usb_register_dev調(diào)用之后才有效。
  • 配置
    一個USB設(shè)備可以有多個配置,可以在配置之間切換以改變設(shè)備的狀態(tài),而一個時刻只能激活一個配置。
    Linux使用struct usb_host_config結(jié)構(gòu)體來描述USB配置,使用struct usb_device結(jié)構(gòu)體來描述整個USB設(shè)備。
    USB設(shè)備驅(qū)動程序需要把一個給定的struct usb_interface結(jié)構(gòu)體的數(shù)據(jù)轉(zhuǎn)換為struct usb_device結(jié)構(gòu)體,用于轉(zhuǎn)換功能的函數(shù)是interface_to_usbdev。
    USB設(shè)備由許多不同的邏輯單元構(gòu)成,邏輯單元之間的關(guān)系:
    設(shè)備通常具有一個或者更多的配置
    配置經(jīng)常具有一個或者更多的接口
    接口通常具有一個或者更多的設(shè)置
    接口沒有或者具有一個以上的端點(diǎn)

3.USB urb

Linux內(nèi)核中的USB代碼通過一個稱為urb(USB請求塊)的東西與所有的USB設(shè)備通信,使用struct urb結(jié)構(gòu)體來描述這個請求塊。
urb被用來以一種異步的方式往/從特定的USB設(shè)備上的特定USB端點(diǎn)發(fā)送/接收數(shù)據(jù)。
一個urb的典型生命周期:
由USB設(shè)備驅(qū)動程序創(chuàng)建。
分配給一個特定的USB設(shè)備的特定端點(diǎn)。
由USB設(shè)備驅(qū)動程序遞交到USB核心。
由USB核心遞交到特定設(shè)備的特定USB中控制器驅(qū)動程序。
由USB主控制器驅(qū)動程序處理,從設(shè)備進(jìn)行USB傳送。
當(dāng)urb結(jié)束之后,USB主控制器驅(qū)動程序通知USB設(shè)備驅(qū)動程序。

  • 創(chuàng)建和銷毀urb
    必須使用usb_alloc_urb函數(shù)來創(chuàng)建。
    struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
    iso_packets,是該urb應(yīng)該包含的等時數(shù)據(jù)包的數(shù)量,如果不打算創(chuàng)建等時urb,該值為0。
    mem_flags,和傳遞給用于從內(nèi)核分配內(nèi)存的kmalloc函數(shù)的標(biāo)志有相同的類型。
    如果成功為urb分配了足夠的內(nèi)存空間,指向該urb的指針將被返回給調(diào)用函數(shù),如果返回為NULL,表示USB核心發(fā)生了錯誤。
    必須調(diào)用usb_free_urb函數(shù)告訴USB核心驅(qū)動程序已經(jīng)使用完urb。
    void usb_free_urb(struct urb *urb);
    urb,指向所需釋放的struct urb的指針,在該函數(shù)被調(diào)用后,urb結(jié)構(gòu)體就會消失,驅(qū)動程序不能再訪問它。
    中斷urb
    usb_fill_int_urb用來正確地初始化即將被發(fā)送到USB設(shè)備的中斷端點(diǎn)的urb。
    static inline void usb_fill_int_urb(struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context,
    int interval);
    struct urb *urb,指向需要初始化的urb的指針。
    struct usb_device *dev,該urb所發(fā)送的目標(biāo)USB設(shè)備。
    unsigned int pipe,該urb所發(fā)送的目標(biāo)USB設(shè)備的特定端點(diǎn)。使用usb_sndintpipe或者usb_rcvintpipe函數(shù)創(chuàng)建。
    void *transfer_buffer,用來保存外發(fā)數(shù)據(jù)或者接收數(shù)據(jù)的緩沖區(qū)的指針。必須使用kmalloc調(diào)用來創(chuàng)建。
    int buffer_length,transfer_buffer指針?biāo)赶虻木彌_區(qū)的大小。
    usb_complete_t complete_fn,當(dāng)該urb結(jié)束之后調(diào)用的結(jié)束處理例程的指針。
    void *context,指向一小數(shù)據(jù)塊,該塊被添加到urb結(jié)構(gòu)體中以便進(jìn)行結(jié)束處理例程后面的查找。
    int interval,該urb應(yīng)該被調(diào)度的間隔。
    批量urb
    使用的函數(shù)usb_fill_bulk_urb。
    static inline void usb_fill_bulk_urb(struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context);
    參數(shù)和usb_fill_int_urb函數(shù)一樣,不過沒有時間間隔參數(shù),pipe變量使用usb_sndbulkpipe或usb_rcvbulkpipe函數(shù)來初始化。
    控制urb
    調(diào)用usb_fill_control_urb函數(shù)。
    static inline void usb_fill_control_urb(struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    unsigned char *setup_packet,
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context);
    參數(shù)和usb_fill_bulk_urb函數(shù)一樣,setup_packet指向即將被發(fā)送到端點(diǎn)的設(shè)備數(shù)據(jù)包的數(shù)據(jù),pipe變量使用usb_sndctrlpipe或usb_rcvctrlpipe函數(shù)來初始化。
    等時urb
    必須在驅(qū)動程序中“手工地”進(jìn)行初始化。
  • 提交urb
    一旦urb被USB驅(qū)動程序正確地創(chuàng)建和初始化之后,就可以提交到USB核心以發(fā)送到USB設(shè)備了。通過調(diào)用usb_submit_urb函數(shù)來完成。
    int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
    urb參數(shù)指向即將被發(fā)送到設(shè)備的urb的指針。
    mem_flags參數(shù)等同于傳遞給kmalloc調(diào)用的同一個參數(shù),用于告訴USB核心如何在此時及時地分配內(nèi)存緩沖區(qū)。
  • 結(jié)束urb:結(jié)束回調(diào)處理例程
    如果調(diào)用usb_submit_urb成功,把對urb的控制轉(zhuǎn)交給USB核心,該函數(shù)返回0,否則,返回負(fù)的錯誤號。如果函數(shù)調(diào)用成功,當(dāng) urb結(jié)束的時候,usb的結(jié)束處理例程(由結(jié)束函數(shù)指針指定)正好被調(diào)用一次。
    只有三種結(jié)束urb和調(diào)用結(jié)束函數(shù)的情形:
    urb被成功地發(fā)送到了設(shè)備,設(shè)備返回了正確的確認(rèn)。urb中的status變量被設(shè)置為0。
    發(fā)送數(shù)據(jù)到設(shè)備或者從設(shè)備接收數(shù)據(jù)時發(fā)生了錯誤。錯誤情況由urb結(jié)構(gòu)體中的status變量的錯誤值來指示。
    urb從USB核心中被“解開鏈接”。
  • 取消urb
    調(diào)用usb_kill_urb或usb_unlink_urb函數(shù)來終止一個已經(jīng)被提交到USB核心的urb。
    void usb_kill_urb(struct urb *urb);
    int usb_unlink_urb(struct urb *urb);
    urb的參數(shù)指向即將被取消的urb的指針。
    如果調(diào)用usb_kill_urb函數(shù),該urb的生命周期將被終止。通常是當(dāng)設(shè)備從系統(tǒng)中被斷開時,在斷開回調(diào)函數(shù)中調(diào)用該函數(shù)。
    對于某些驅(qū)動程序而言,應(yīng)該使用usb_unlink_urb函數(shù)來告訴USB核心終止一個urb。該函數(shù)并不等到urb完全被終止后才返回到調(diào)用函數(shù)。

4.USB驅(qū)動程序

驅(qū)動程序把驅(qū)動程序?qū)ο笞缘経SB子系統(tǒng)中,稍后再使用制造商和設(shè)備標(biāo)識來判斷是否已經(jīng)安裝了硬件。
USB核心使用struct usb_device_id結(jié)構(gòu)體來判斷對于一個設(shè)備該使用哪一個驅(qū)動程序,熱插拔腳本使用它來確定當(dāng)一個特定的設(shè)備插入到系統(tǒng)時該自動裝載哪一個驅(qū)動程序

 struct usb_device_id {
	__u16		match_flags;      /*確定設(shè)備和結(jié)構(gòu)體中下列字段中的哪一個相匹配*/
	__u16		idVendor;         /*設(shè)備的USB制造商ID*/
	__u16		idProduct;        /*設(shè)備的USB產(chǎn)品ID*/
	/*定義了制造商指派的產(chǎn)品的版本號范圍的最低和最高值。bcdDevice_hi值包括在內(nèi),該值是最高編號的設(shè)備的編號*/
	__u16		bcdDevice_lo;     
	__u16		bcdDevice_hi;
    /*分別定義設(shè)備的類型、子類型和協(xié)議。這些值詳細(xì)說明了整個設(shè)備的行為,包括該設(shè)備上的所有接口*/
	__u8		bDeviceClass;
	__u8		bDeviceSubClass;
	__u8		bDeviceProtocol;
    /*分別定義了類型、子類型和單個接口的協(xié)議*/
	__u8		bInterfaceClass;
	__u8		bInterfaceSubClass;
	__u8		bInterfaceProtocol;

	__u8		bInterfaceNumber;
	/*不是用來比較是否匹配的,包含了驅(qū)動程序在USB驅(qū)動程序的探測回調(diào)函數(shù)中可以用來區(qū)分不同設(shè)備的信息*/
	kernel_ulong_t	driver_info
		__attribute__((aligned(sizeof(kernel_ulong_t))));
};

有許多用來初始化該結(jié)構(gòu)體的宏:
USB_DEVICE(vend, prod),僅和指定的制造商和產(chǎn)品ID值相匹配。用于需要一個特定驅(qū)動程序的USB設(shè)備。
USB_DEVICE_VER(vend, prod, lo, hi),僅和某版本范圍內(nèi)的指定制造商和產(chǎn)品ID值相匹配。
USB_DEVICE_INFO(cl, sc, pr),僅和USB設(shè)備的指定類型相匹配。
USB_INTERFACE_INFO(cl, sc, pr),僅和USB接口的指定類型相匹配。文章來源地址http://www.zghlxwxcb.cn/news/detail-828317.html

  • 注冊USB驅(qū)動程序
    必須創(chuàng)建的主結(jié)構(gòu)體是struct usb_driver,必須由USB驅(qū)動程序來填寫,包括許多回調(diào)函數(shù)和變量,向USB核心代碼描述了USB驅(qū)動程序。
    struct usb_driver {
    	const char *name;    /*指向驅(qū)動程序名字的指針。在內(nèi)核的所有USB驅(qū)動程序中必須是唯一的,通常被設(shè)置為和驅(qū)動程序模塊名相同的名字。*/
    
    	int (*probe) (struct usb_interface *intf,
    		      const struct usb_device_id *id);  /*指向USB驅(qū)動程序中的探測函數(shù)的指針。*/
    
    	void (*disconnect) (struct usb_interface *intf); /*指向USB驅(qū)動程序中的斷開函數(shù)的指針。當(dāng)struct usb_interface被從系統(tǒng)中移除或者驅(qū)動程序正在從USB核心中卸載時,USB核心將調(diào)用該函數(shù)。*/
    
    	int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
    			void *buf);
    
    	int (*suspend) (struct usb_interface *intf, pm_message_t message);
    	int (*resume) (struct usb_interface *intf);
    	int (*reset_resume)(struct usb_interface *intf);
    
    	int (*pre_reset)(struct usb_interface *intf);
    	int (*post_reset)(struct usb_interface *intf);
    
    	const struct usb_device_id *id_table;   /*指向struct usb_device_id表的指針,包含了一系列驅(qū)動程序可以支持的所有不同類型的USB設(shè)備。*/
    
    	struct usb_dynids dynids;
    	struct usbdrv_wrap drvwrap;
    	unsigned int no_dynamic_id:1;
    	unsigned int supports_autosuspend:1;
    	unsigned int disable_hub_initiated_lpm:1;
    	unsigned int soft_unbind:1;
    };
    
    以struct usb_driver指針為參數(shù)的usb_register_driver函數(shù)調(diào)用把struct usb_driver注冊到USB核心。
    當(dāng)USB驅(qū)動程序?qū)⒁恍遁d時,需要把struct usb_drvier從內(nèi)核中注銷,通過調(diào)用usb_deregister_driver來完成該工作。
  • 探測和斷開
    探測和斷開回調(diào)函數(shù)都是在USB集線器內(nèi)核線程的上下文中被調(diào)用的,因此在其中睡眠是合法的。
    在探測回調(diào)函數(shù)中,USB驅(qū)動程序應(yīng)該初始化人任何可能用于控制USB設(shè)備的局部結(jié)構(gòu)體,還應(yīng)該把所需的任何設(shè)備相關(guān)信息保存到局部結(jié)構(gòu)體中。
    USB驅(qū)動程序需要在設(shè)備生命周期的稍后時間獲取和該結(jié)構(gòu)體struct usb_interface相關(guān)聯(lián)的局部數(shù)據(jù)結(jié)構(gòu)體,可以調(diào)用usb_set_intfdata函數(shù):
    void usb_set_intfdata(struct usb_interface *intf, void *data);
    該函數(shù)接受一個指向任意數(shù)據(jù)類型的指針,把它保存到struct usb_interface結(jié)構(gòu)體中以便后面訪問,調(diào)用usb_get_intfdata函數(shù)來獲取數(shù)據(jù):
    void *usb_get_intfdata(struct usb_interface *intf);
    usb_get_intfdata通常在USB驅(qū)動程序的打開函數(shù)和斷開函數(shù)中調(diào)用。
    如果USB驅(qū)動程序沒有和設(shè)備與用戶交互的另一種類型的子系統(tǒng)相關(guān)聯(lián),驅(qū)動程序可以使用USB主設(shè)備號,以便在用戶空間使用傳統(tǒng)的字符驅(qū)動程序接口。USB驅(qū)動程序需要在探測函數(shù)中調(diào)用usb_register_dev函數(shù)來把設(shè)備注冊到USB核心。
    usb_register_dev函數(shù)需要一個指向struct usb_interface的指針和一個指向struct usb_class_driver結(jié)構(gòu)的指針。
    int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver);
    
    struct usb_class_driver {
    	char *name;     /*sysfs用來描述設(shè)備的名字*/
    	char *(*devnode)(struct device *dev, umode_t *mode); /*回調(diào)函數(shù),創(chuàng)建設(shè)備節(jié)點(diǎn)*/
    	const struct file_operations *fops;  /*指向struct file_operations的指針,驅(qū)動程序定義該結(jié)構(gòu)體,用它來注冊為字符設(shè)備*/
    	int minor_base;  /*為驅(qū)動程序指派的次設(shè)備號范圍的開始值*/
    };
    
    當(dāng)一個USB設(shè)備被斷開時,和該設(shè)備相關(guān)聯(lián)的所有資源都應(yīng)該被盡可能的清理掉。必須調(diào)用usb_deregister_dev函數(shù)把次設(shè)備號交還USB核心。
    在斷開函數(shù)中,從接口獲取之前調(diào)用usb_set_intfdata設(shè)置的任何數(shù)據(jù)也是很重要的,然后設(shè)置struct usb_interface結(jié)構(gòu)體中的數(shù)據(jù)指針為NULL。
    在USB設(shè)備已經(jīng)被斷開之后,如果驅(qū)動程序通過調(diào)用usb_submit_urb來提交一個urb給它,提交將會失敗并返回錯誤值-EPIPE。
  • 提交和控制urb
    當(dāng)驅(qū)動程序有數(shù)據(jù)要發(fā)送到USB設(shè)備時,必須分配一個urb來把數(shù)據(jù)傳輸給設(shè)備(struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)),在urb被成功分配之后,創(chuàng)建一個DMA緩沖區(qū)以最高效的方式發(fā)送數(shù)據(jù)到設(shè)備,傳遞給驅(qū)動程序的數(shù)據(jù)復(fù)制到該緩沖區(qū)中(void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma))。一旦數(shù)據(jù)從用戶空間正確的復(fù)制到局部緩沖區(qū)中,urb必須在可以被提交給USB核心之前被正確地初始化(static inline void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context)),然后就可以被提交給USB核心以傳輸?shù)皆O(shè)備(int usb_submit_urb(struct urb *urb, gfp_t mem_flags))。
    /* 創(chuàng)建一個urb */
    urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!urb) {
    	retval = -ENOMEM;
    	goto error;
    }
    /* 創(chuàng)建DMA緩沖區(qū),并把數(shù)據(jù)拷貝到緩沖區(qū) */
    buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
    &urb->transfer_dma);
    if (!buf) {
    	retval = -ENOMEM;
    	goto error;
    }
    
    if (copy_from_user(buf, user_buffer, writesize)) {
    retval = -EFAULT;
    goto error;
    }
    
    /* this lock makes sure we don't submit URBs to gone devices */
    mutex_lock(&dev->io_mutex);
    if (!dev->interface) {		/* disconnect() was called */
    	mutex_unlock(&dev->io_mutex);
    	retval = -ENODEV;
    	goto error;
    }
    
    /* 初始化urb */
    usb_fill_bulk_urb(urb, dev->udev,
    			usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
    			buf, writesize, skel_write_bulk_callback, dev);
    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    usb_anchor_urb(urb, &dev->submitted);
    
    /* 把數(shù)據(jù)從批量端口發(fā)出 */
    retval = usb_submit_urb(urb, GFP_KERNEL);
    mutex_unlock(&dev->io_mutex);
    if (retval) {
    	dev_err(&dev->interface->dev,
    	"%s - failed submitting write urb, error %d\n",
    	__func__, retval);
    	goto error_unanchor;
    }
    
    在urb被成功傳輸?shù)経SB設(shè)備之后(或者傳輸沖發(fā)生了某些事情),urb回調(diào)函數(shù)將被USB核心調(diào)用。
    static void skel_write_bulk_callback(struct urb *urb)
    {
    	struct usb_skel *dev;
    
    	dev = urb->context;
    
    	/* sync/async 解鏈接故障不是錯誤 */
    	if (urb->status) {
    		if (!(urb->status == -ENOENT ||
    		    urb->status == -ECONNRESET ||
    		    urb->status == -ESHUTDOWN))
    			dev_err(&dev->interface->dev,
    				"%s - nonzero write bulk status received: %d\n",
    				__func__, urb->status);
    
    		spin_lock(&dev->err_lock);
    		dev->errors = urb->status;
    		spin_unlock(&dev->err_lock);
    	}
    
    	/* 釋放已分配的緩沖區(qū) */
    	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
    			  urb->transfer_buffer, urb->transfer_dma);
    	up(&dev->limit_sem);
    }
    
    回調(diào)函數(shù)中做的第一件事是檢查urb的狀態(tài),以確定該urb是否已經(jīng)成功地結(jié)束。之后回調(diào)函數(shù)釋放傳輸時分配給該urb的緩沖區(qū)。
    urb回調(diào)函數(shù)是運(yùn)行在中斷上下文中的,因此它不應(yīng)該進(jìn)行任何內(nèi)存分配、持有任何信號量或者做任何其他可能導(dǎo)致進(jìn)程睡眠的事情。
  • 不使用urb的USB傳輸
    有時候USB驅(qū)動程序只是要發(fā)送或者接收一些簡單的USB數(shù)據(jù),有兩個更簡單的接口函數(shù)可以使用usb_bulk_msg和 usb_control_msg。
    usb_bulk_msg創(chuàng)建一個USB批量urb,把它發(fā)送到指定的設(shè)備,然后在返回調(diào)用者之前等待它的結(jié)束。
    int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);
    struct usb_device *usb_dev,指向批量消息所發(fā)送的目標(biāo)USB設(shè)備的指針。
    unsigned int pipe,該批量消息所發(fā)送的目標(biāo)USB設(shè)備的特定端點(diǎn),調(diào)用usb_sndbulkpipe或usb_rcvbulkpipe來創(chuàng)建。
    void *data,如果是一個OUT端點(diǎn),指向即將發(fā)送到設(shè)備的數(shù)據(jù)的指針。如果是一個IN端點(diǎn),指向從設(shè)備讀取的數(shù)據(jù)應(yīng)該存放的位置的指針。
    int len,data參數(shù)所指緩沖區(qū)的大小。
    int *actual_length,指向保存實(shí)際傳輸字節(jié)數(shù)的位置的指針。
    int timeout,以jiffies為單位的應(yīng)該等待的超時時間。如果該值為0,該函數(shù)將一直等待消息的結(jié)束。
    如果函數(shù)調(diào)用成功,返回值為0;否則,返回一個負(fù)的錯誤值。如果成功,actual_length參數(shù)包含從該消息發(fā)送或者接收的字節(jié)數(shù)。
    不能在一個中斷上下文中或者在持有自旋鎖的情況下調(diào)用usb_bulk_msg函數(shù)。
    usb_control_msg,允許驅(qū)動程序發(fā)送和接收USB控制消息。
    int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
    struct usb_device *dev,指向控制消息所發(fā)送的目標(biāo)USB設(shè)備的指針。
    unsigned int pipe,該控制消息所發(fā)送的目標(biāo)USB設(shè)備的特定端點(diǎn),調(diào)用usb_sndctrlpipe或usb_rcvctrlpipe來創(chuàng)建。
    __u8 request,控制消息的USB請求值。
    __u8 requesttype,控制消息的USB請求類型值。
    __u16 value,控制消息的USB消息值。
    __u16 index,控制消息的USB消息索引值。
    void *data,如果是一個OUT端點(diǎn),指向即將發(fā)送到設(shè)備的數(shù)據(jù)的指針。如果是一個IN端點(diǎn),指向從設(shè)備讀取的數(shù)據(jù)應(yīng)該存放的位置的指針。
    __u16 size,data參數(shù)所指緩沖區(qū)的大小。
    int timeout,以jiffies為單位的應(yīng)該等待的超時時間。如果該值為0,該函數(shù)將一直等待消息的結(jié)束。
    如果函數(shù)調(diào)用成功,返回傳輸?shù)皆O(shè)備或者從設(shè)備讀取的字節(jié)數(shù);如果不成功,返回一個負(fù)的錯誤值。
    不能在一個中斷上下文中或者在持有自旋鎖的情況下調(diào)用usb_control_msg函數(shù)。
  • 其他USB數(shù)據(jù)函數(shù)
    USB核心中的許多輔助函數(shù)可以用來從所有USB設(shè)備中獲取標(biāo)準(zhǔn)的信息。這些函數(shù)不能在一個中斷上下文中或者持有自旋鎖的情況下調(diào)用。
    usb_get_descriptor函數(shù)從指定的設(shè)備獲取指定的USB描述符。
    int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size);
    USB驅(qū)動程序可以使用該函數(shù)來從struct usb_device結(jié)構(gòu)體中獲取任何沒有存在于已有struct usb_device和struct usb_interface結(jié)構(gòu)體中的設(shè)備描述符。
    struct usb_device *dev,指向想要獲取設(shè)備描述符的目標(biāo)USB設(shè)備的指針。
    unsigned char desctype,描述符的類型。
    unsigned char descindex,應(yīng)該從設(shè)備獲取的描述符的編號。
    void *buf,指向復(fù)制描述符到其中的緩沖區(qū)的指針。
    int size,buf變量所指內(nèi)存的大小。
    如果函數(shù)調(diào)用成功,返回從設(shè)備讀取的字節(jié)數(shù)。否則,返回一個由該函數(shù)調(diào)用的底層的usb_control_msg函數(shù)返回的一個負(fù)的錯誤值。
    usb_get_descriptor調(diào)用更常用于從USB設(shè)備獲取一個字符串,提供usb_string的輔助函數(shù)來完成該工作。
    int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
    返回從USB設(shè)備讀取的已經(jīng)轉(zhuǎn)換為ISO 8859-1格式的字符串。是USB設(shè)備的字符串的典型格式。

    參考資料:
    《LINUX設(shè)備驅(qū)動程序第三版》
    linux-4.9.88

到了這里,關(guān)于嵌入式Linux開發(fā)-USB驅(qū)動的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 嵌入式Linux驅(qū)動開發(fā)——常見框架梳理

    嵌入式Linux驅(qū)動開發(fā)——常見框架梳理

    本文主要介紹了Linux驅(qū)動開發(fā)中一些常用的驅(qū)動框架,platform、input、iic、spi等,硬件平臺使用的是正點(diǎn)原子的imx6ull開發(fā)板。 不管什么框架最后都是要追溯到配置IO的電氣屬性和復(fù)用功能 如果要使用外部中斷,設(shè)備樹節(jié)點(diǎn)中還需添加相關(guān)信息,什么邊沿觸發(fā) 1:module_init和mod

    2024年02月15日
    瀏覽(32)
  • 嵌入式Linux驅(qū)動開發(fā) 04:基于設(shè)備樹的驅(qū)動開發(fā)

    嵌入式Linux驅(qū)動開發(fā) 04:基于設(shè)備樹的驅(qū)動開發(fā)

    前面文章 《嵌入式Linux驅(qū)動開發(fā) 03:平臺(platform)總線驅(qū)動模型》 引入了資源和驅(qū)動分離的概念,這篇文章將在前面基礎(chǔ)上更進(jìn)一步,引入設(shè)備樹的概念。 在平臺總線驅(qū)動模型中資源和驅(qū)動已經(jīng)從邏輯上和代碼組織上進(jìn)行了分離,但每次調(diào)整資源還是會涉及到內(nèi)核,所以現(xiàn)

    2024年02月16日
    瀏覽(27)
  • 正點(diǎn)原子嵌入式linux驅(qū)動開發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動

    正點(diǎn)原子嵌入式linux驅(qū)動開發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動

    網(wǎng)絡(luò)驅(qū)動是linux里面驅(qū)動三巨頭之一 ,linux下的網(wǎng)絡(luò)功能非常強(qiáng)大,嵌入式linux中也常常用到網(wǎng)絡(luò)功能。前面已經(jīng)講過了字符設(shè)備驅(qū)動和塊設(shè)備驅(qū)動,本章就來學(xué)習(xí)一下linux里面的 網(wǎng)絡(luò)設(shè)備驅(qū)動 。 本次筆記中討論的都是有線網(wǎng)絡(luò)! 提起網(wǎng)絡(luò),一般想到的硬件就是“網(wǎng)卡”。在

    2024年01月17日
    瀏覽(25)
  • 【嵌入式Linux驅(qū)動】驅(qū)動開發(fā)調(diào)試相關(guān)的關(guān)系記錄

    【嵌入式Linux驅(qū)動】驅(qū)動開發(fā)調(diào)試相關(guān)的關(guān)系記錄

    https://www.processon.com/mindmap/64537772b546c76a2f37bd2f

    2024年02月02日
    瀏覽(27)
  • 嵌入式Linux驅(qū)動開發(fā)系列六:Makefile

    嵌入式Linux驅(qū)動開發(fā)系列六:Makefile

    Makefile是什么? gcc hello.c -o hello gcc aa.c bb.c cc.c dd.c ... make工具和Makefile make和Makefile是什么關(guān)系? make工具:找出修改過的文件,根據(jù)依賴關(guān)系,找出受影響的相關(guān)文件,最后按照規(guī)則單獨(dú)編譯這些文件。 Makefile文件:記錄依賴關(guān)系和編譯規(guī)則。 必須要學(xué)精Makefile嗎? 怎么學(xué)習(xí)Makefi

    2024年02月13日
    瀏覽(24)
  • 嵌入式linux驅(qū)動開發(fā)篇之設(shè)備樹

    嵌入式linux驅(qū)動開發(fā)篇之設(shè)備樹

    設(shè)備樹(Device Tree)是一種用于描述嵌入式系統(tǒng)硬件組件及其連接關(guān)系的數(shù)據(jù)結(jié)構(gòu)。它被廣泛用于嵌入式 Linux 系統(tǒng),尤其是針對使用多種不同架構(gòu)和平臺的嵌入式系統(tǒng)。它是一種與硬件描述相關(guān)的中間表示形式,將硬件信息抽象成一種可移植的格式,使得操作系統(tǒng)和引導(dǎo)加載

    2024年02月22日
    瀏覽(25)
  • 嵌入式Linux驅(qū)動開發(fā)(LCD屏幕專題)(一)

    嵌入式Linux驅(qū)動開發(fā)(LCD屏幕專題)(一)

    總的分辨率是 yres*xres。 以下三種方式表示顏色 每個屏幕都有一個內(nèi)存(framebuffer)如下圖,內(nèi)存中每塊數(shù)據(jù)對用屏幕上的一個像素點(diǎn),設(shè)置好LCD后,只需把顏色數(shù)據(jù)寫入framebuffer即可。 Framebuffer驅(qū)動屬于字符設(shè)備驅(qū)動,我們先說字符設(shè)備驅(qū)動框架如下圖: 驅(qū)動主設(shè)備號 構(gòu)造

    2024年02月09日
    瀏覽(30)
  • 嵌入式Linux驅(qū)動開發(fā)(LCD屏幕專題)(三)

    嵌入式Linux驅(qū)動開發(fā)(LCD屏幕專題)(三)

    1. 硬件相關(guān)的操作 LCD驅(qū)動程序的核心就是: 分配fb_info 設(shè)置fb_info 注冊fb_info 硬件相關(guān)的設(shè)置 硬件相關(guān)的設(shè)置又可以分為3部分: 引腳設(shè)置 時鐘設(shè)置 LCD控制器設(shè)置 2. 在設(shè)備樹里指定LCD參數(shù) 3. 編程 3.1 從設(shè)備樹獲得參數(shù) 時序參數(shù)、引腳極性等信息,都被保存在一個display_timi

    2024年02月09日
    瀏覽(33)
  • 嵌入式Linux驅(qū)動開發(fā) 02:將驅(qū)動程序添加到內(nèi)核中

    嵌入式Linux驅(qū)動開發(fā) 02:將驅(qū)動程序添加到內(nèi)核中

    在上一篇文章 《嵌入式Linux驅(qū)動開發(fā) 01:基礎(chǔ)開發(fā)與使用》 中我們已經(jīng)實(shí)現(xiàn)了最基礎(chǔ)的驅(qū)動功能。在那篇文章中我們的驅(qū)動代碼是獨(dú)立于內(nèi)核代碼存放的,并且我們的驅(qū)動編譯后也是一個獨(dú)立的模塊。在實(shí)際使用中將驅(qū)動代碼放在內(nèi)核代碼中,并將驅(qū)動編譯到內(nèi)核中也是比較

    2023年04月09日
    瀏覽(51)
  • 嵌入式Linux驅(qū)動開發(fā)系列五:Linux系統(tǒng)和HelloWorld

    嵌入式Linux驅(qū)動開發(fā)系列五:Linux系統(tǒng)和HelloWorld

    三個問題 了解Hello World程序的執(zhí)行過程有什么用? 編譯和執(zhí)行:Hello World程序的執(zhí)行分為兩個主要步驟:編譯和執(zhí)行。編譯器將源代碼轉(zhuǎn)換為可執(zhí)行文件,然后計算機(jī)執(zhí)行該文件并輸出相應(yīng)的結(jié)果。了解這個過程可以幫助我們理解如何將代碼轉(zhuǎn)化為可運(yùn)行的程序。 語法和語義

    2024年02月13日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包