1. 程式人生 > 實用技巧 >Linux USB 子系統(二)—— USB 驅動幾個重要資料結構

Linux USB 子系統(二)—— USB 驅動幾個重要資料結構

前面我們學習了USB 驅動的一個描述符,下面來學習 USB 驅動的幾個重要資料結構

位於include\linux\usb.h


一、struct usb_device 裝置函式

struct usb_device {
    int devnum;         //devnum只是usb裝置在一條usb總線上的編號.一條usb_bus_type型別的總線上最多可以連上128個裝置
    char devpath [16];   /* Use in messages: /port/port/...*/  //對於root hub.會將dev->devpath[0]=’0’
    enum usb_device_state   state;  //裝置的狀態Attached,Powered,Default,Address,Configured,Suspended;
                               //Attached表示裝置已經連線到usb介面上了,是hub檢測到裝置時的初始狀態。那麼這裡所謂的USB_STATE_NOTATTACHED就是表示裝置並沒有Attached。
                               //Address狀態表示主機分配了一個唯一的地址給裝置,此時裝置可以使用預設管道響應主機的請求
                               //Configured狀態表示裝置已經被主機配置過了,也就是協議裡說的處理了一個帶有非0值的SetConfiguration()請求,此時主機可以使用裝置提供的所有功能
                               //Suspended掛起狀態,為了省電,裝置在指定的時間內,3ms吧,如果沒有發生匯流排傳輸,就要進入掛起狀態。此時,usb裝置要自己維護包括地址、配置在內的資訊             

    enum usb_device_speed   speed;  /* high/full/low (or error) */
    struct usb_tt   *tt;            //如果一個高速裝置裡有這麼一個TT,那麼就可以連線低速/全速裝置,如不然,那低速/全速裝置沒法用,只能連線到OHCI/UHCI那邊出來的hub口裡。
    int             ttport;         //如果一個高速裝置裡有這麼一個TT,那麼就可以連線低速/全速裝置,如不然,那低速/全速裝置沒法用,只能連線到OHCI/UHCI那邊出來的hub口裡。

    unsigned int toggle[2];         /* one bit for each endpoint     //他實際上就是一個位圖.IN方向的是toggle[0].OUT方向的是toggle[1].其實,這個陣列中的每一位表示ep的toggle值
                                             * ([0] = IN, [1] = OUT) */它裡面的每一位表示的就是每個端點當前傳送或接收的資料包是DATA0還是DATA1
    
    struct usb_device *parent;      /* our hub, unless we're the root */
                              //USB裝置是從Root Hub開始,一個一個往外面連的,比如Root Hub有4個口,每個口連一個USB裝置,比如其中有一個是Hub,那麼這個Hub有可以繼續有多個口,於是一級一級的往下連,
                               //最終連成了一棵樹。
    struct usb_bus *bus;            /* Bus we're part of */裝置所在的匯流排
    struct usb_host_endpoint ep0;   //端點0的特殊地位決定了她必將受到特殊的待遇,在struct usb_device物件產生的時候它就要初始化

    struct device dev;              /* Generic device interface */嵌入到struct usb_device結構裡的struct device結構

    struct usb_device_descriptor descriptor;/* Descriptor */裝置描述符,此結構體的bMaxPacketSize0 filed儲存了端點0的maximum packet size
    struct usb_host_config *config; //裝置擁有的所有配置

    struct usb_host_config *actconfig;//裝置正在使用的配置
    struct usb_host_endpoint *ep_in[16];//ep_in[16],359行,ep_out[16],除了端點0,一個裝置即使在高速模式下也最多隻能再有15個IN端點和15個OUT端點,端點0太特殊了,
    struct usb_host_endpoint *ep_out[16];//對應的管道是Message管道,又能進又能出特能屈能伸的那種,所以這裡的ep_in和ep_out陣列都有16個值

    char **rawdescriptors;          /* Raw descriptors for each config */

    unsigned short bus_mA;          /* Current available from the bus */這個值是在host controller的驅動程式中設定的,通常來講,計算機的usb埠可以提供500mA的電流
    u8 portnum;                     //不管是root hub還是一般的hub,你的USB裝置總歸要插在一個hub的埠上才能用,portnum就是那個埠號。
    u8 level;                       //層次,也可以說是級別,表徵usb裝置樹的級連關係。Root Hub的level當然就是0,其下面一層就是level 1,再下面一層就是level 2,依此類推

    unsigned discon_suspended:1;    /* Disconnected while suspended */
    unsigned have_langid:1;         /* whether string_langid is valid */
    int string_langid;              /* language ID for strings */

    /* static strings from the device */
    char *product;                  /* iProduct string, if present */
    char *manufacturer;             /* iManufacturer string, if present */
    char *serial;                   /* iSerialNumber string, if present */
                                    //分別用來儲存產品、廠商和序列號對應的字串描述符資訊

    struct list_head filelist;
#ifdef CONFIG_USB_DEVICE_CLASS
    struct device *usb_classdev;
#endif

#ifdef CONFIG_USB_DEVICEFS
    struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */
#endif
    /*
    * Child devices - these can be either new devices
    * (if this is a hub device), or different instances
    * of this same device.
    *
    * Each instance needs its own set of data structures.
    */

    int maxchild;                   /* Number of ports if hub */
    struct usb_device *children[USB_MAXCHILDREN];

    int pm_usage_cnt;               /* usage counter for autosuspend */
    u32 quirks;                     //quirk就是用來判斷這些有毛病的產品啥毛病的

#ifdef CONFIG_PM
    struct delayed_work autosuspend; /* for delayed autosuspends */
    struct mutex pm_mutex;          /* protects PM operations */
    unsigned long last_busy;        /* time of last use */
    int autosuspend_delay;          /* in jiffies */

    unsigned auto_pm:1;             /* autosuspend/resume in progress */
    unsigned do_remote_wakeup:1;    /* remote wakeup should be enabled */
    unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
    unsigned autoresume_disabled:1;  /*  disabled by the user */
#endif
};



二、struct usb_host_config 配置函式

struct usb_host_config {
    struct usb_config_descriptor    desc;

    char *string;        /* iConfiguration string, if present */

    /* List of any Interface Association Descriptors in this
     * configuration. */
    struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS]; //此配置中所有相關聯的介面描述符的列表

    /* the interfaces associated with this configuration,
     * stored in no particular order */
    struct usb_interface *interface[USB_MAXINTERFACES]; //配置所包含的介面,這個陣列的順序未必是按照配置裡介面號的順序

    /* Interface information available even when this is not the
     * active configuration */
    struct usb_interface_cache *intf_cache[USB_MAXINTERFACES]; //usb介面的快取

    unsigned char *extra;   /* Extra descriptors */
    int extralen;
};



三、struct usb_interface介面函式

usb_interface字面意思既是介面,什麼的介面:裝置的介面。

為什麼會出現這樣的型別出來,根據實際情況,例如:
一個裝置有兩種功能 一個鍵盤 一個音訊,兩種介面,那這樣肯定得要兩個驅動程式,一個是鍵盤驅動程式,一個是音訊流驅動程式。兩種功能整合在一起稱為一個裝置。但是不同的介面需要不同的驅動,音訊驅動 和鍵盤驅動。用interface來區分,就有了介面型別

struct usb_interface {
	/* array of alternate settings for this interface,
	* stored in no particular order */
	struct usb_host_interface *altsetting;  // 當前介面的可選設定
	/* the currently active alternate setting */
	struct usb_host_interface *cur_altsetting;  // 當前介面使用的設定
	/* number of alternate settings */ 
	unsigned num_altsetting;  // 當前介面具有的可選設定總數

	/* If there is an interface association descriptor then it will list
	* the associated interfaces */
	struct usb_interface_assoc_descriptor *intf_assoc;
	/* minor number this interface is * bound to */ 
	int minor;   // 當前介面的在主裝置號為USB_MAJOR時的子裝置號,minor只在USB_MAJOR起作用時起
作用。 usb裝置沒有與其它任何子系統關聯,就需要在對應驅動的probe函式裡使用usb_register_dev函式來註冊並獲得主裝置號USB_MAJOR。如果usb裝置關聯了其它子系統,則需要在對應驅動的probe函式裡使用相應的註冊函式,USB_MAJOR也就該幹嗎幹嗎去,用不著它了。比如,usb鍵盤關聯了input子系統,驅動對應drivers/hid/usbhid目錄下的usbkbd.c檔案,在它的probe函式裡可以看到使用了input_register_device來註冊一個輸入裝置。

	enum usb_interface_condition condition; /* state of binding */ // 當前介面 所處的連線繫結階段
	unsigned sysfs_files_created:1; /* the sysfs attributes exist */
	unsigned ep_devs_created:1; /* endpoint "devices" exist */
	unsigned unregistering:1; /* unregistration is in progress */
	unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
	unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
	unsigned needs_binding:1; /* needs delayed unbind/rebind */
	unsigned resetting_device:1; /* true: bandwidth alloc after reset */

	struct device dev; /* interface specific device info */ // linux裝置模型裡的device嵌在這兒的物件
	struct device *usb_dev;  // 當介面使用USB_MAJOR作為主裝置號時,usb_dev才會用到, usb_register_dev和usb_deregister_dev使用這個結構體,usb_dev指向的
                                   就是usb_register_dev函式裡建立的usb class device。
	atomic_t pm_usage_cnt; /* usage counter for autosuspend */
	struct work_struct reset_ws; /* for resets in atomic context */
}

struct usb_interface中的struct usb_host_interface *cur_altsetting成員,表示當前正在使用的設定


1、struct usb_host_interface

struct usb_host_interface 
{
         struct usb_interface_descriptor desc;//usb描述符,主要有四種usb描述符,裝置描述符,配置描述符,介面描述符和端點描述符,協議裡規定一個usb裝置是必須支援這四大描述符的。

          //usb描述符放在usb裝置的eeprom裡邊
         /* array of desc.bNumEndpoint endpoints associated with this
          * interface setting. these will be in no particular order.
          */
         struct usb_host_endpoint *endpoint;//這個設定所使用的端點

         char *string;           /* iInterface string, if present */ //介面描述字串
         unsigned char *extra;   /* Extra descriptors */關於額外描述符
         int extralen;
};

具體到介面描述符,它當然就是描述介面本身的資訊的。一個介面可以有多個設定,使用不同的設定,描述介面的資訊會有些不同,所以介面描述符並沒有放在struct usb_interface結構裡,而是放在表示介面設定的struct usb_host_interface結構裡。



四、struct usb_host_endpoint 端點函式

struct usb_host_endpoint 
{
         struct usb_endpoint_descriptor desc; //端點描述符
         struct list_head                urb_list;//端點要處理的urb佇列.urb是usb通訊的主角,裝置中的每個端點都可以處理一個urb佇列.要想和你的usb通訊,就得建立一個urb,並且為它賦好值,
                                   //交給咱們的usb core,它會找到合適的host controller,從而進行具體的資料傳輸
         void                            *hcpriv;//這是提供給HCD(host controller driver)用的
         struct ep_device                *ep_dev;        /* For sysfs info */

         unsigned char *extra;   /* Extra descriptors */
         int extralen;
};



參考:

Linux USB 驅動開發(二)—— USB 驅動幾個重要資料結構_知秋一葉-CSDN部落格Linux--usb(6)usb_interface