usb驱动流程分析

一、Usb 驱动关键结构体:

1、usb设备

1.1、usb_device

usb_device保存一个USB设备的信息,包括设备地址,设备描述符,配置描述符等。
每个usb设备是由一个usb_device对象来描述的。

struct usb_device {
	int devnum;   //usb设备在一条usb总线上的编号
	char devpath[16];  //用于消息的设备ID字符串
	u32 route;  //用于xHCI的树拓扑十六进制字符串
	enum usb_device_state state;//usb设备状态
	enum usb_device_speed speed;//设备速度
	unsigned int rx_lanes;//使用的rx线路数量
	unsigned int tx_lanes;//使用的tx线路数量
	enum usb_ssp_rate ssp_rate;// SuperSpeed + phy信令速率和车道数

	struct usb_tt *tt; //如果一个高速设备里有这么一个TT,那么就可以连接低速/全速设备,如不然,那低速/全速设备没法用,只能连接到OHCI/UHCI那边出来的hub口里。
	int ttport;

	unsigned int toggle[2];

	struct usb_device *parent;  //父设备指针
	struct usb_bus *bus;  //设备所在总线
	struct usb_host_endpoint ep0;//在创建usb_device时初始化端点0

	struct device dev;  //通用设备接口

	struct usb_device_descriptor descriptor; //设备描述符
	struct usb_host_bos *bos;
	struct usb_host_config *config; //设备拥有的所有配置

	struct usb_host_config *actconfig; //设备正在使用的配置
	struct usb_host_endpoint *ep_in[16]; //输入端点
	struct usb_host_endpoint *ep_out[16]; //输出端点

	char **rawdescriptors; //配置的原始描述符

	unsigned short bus_mA;
	u8 portnum; //hub 端口号
	u8 level; //usb设备树的级联级别
	u8 devaddr;

	unsigned can_submit : 1;
	unsigned persist_enabled : 1;
	unsigned have_langid : 1;
	unsigned authorized : 1;
	unsigned authenticated : 1;
	unsigned wusb : 1;
	unsigned lpm_capable : 1;
	unsigned lpm_devinit_allow : 1;
	unsigned usb2_hw_lpm_capable : 1;
	unsigned usb2_hw_lpm_besl_capable : 1;
	unsigned usb2_hw_lpm_enabled : 1;
	unsigned usb2_hw_lpm_allowed : 1;
	unsigned usb3_lpm_u1_enabled : 1;
	unsigned usb3_lpm_u2_enabled : 1;
	int string_langid;

	/* static strings from the device */
	char *product;  //分别用来保存产品、厂商和序列号对应的字符串描述符信息
	char *manufacturer;
	char *serial;

	struct list_head filelist;

	int maxchild;

	u32 quirks;
	atomic_t urbnum;

	unsigned long active_duration;

#ifdef CONFIG_PM
	unsigned long connect_time;

	unsigned do_remote_wakeup : 1;
	unsigned reset_resume : 1;
	unsigned port_is_suspended : 1;
#endif
	struct wusb_dev *wusb_dev;
	int slot_id;
	struct usb2_lpm_parameters l1_params;
	struct usb3_lpm_parameters u1_params;
	struct usb3_lpm_parameters u2_params;
	unsigned lpm_disable_count;

	u16 hub_delay;
	unsigned use_generic_driver : 1;
};

端点0:被称为控制端点,是一个数据双向传输的端点,其作用是对设备枚举和对设备进行一些基本的控 制功能,在usb_device对象创建时就需要被初始化。

1.2、usb_device_descriptor

保存usb设备描述符的结构体,通过usb_get_configuration函数创建并初始化。

struct usb_device_descriptor {
	__u8 bLength;     //本描述符的size
	__u8 bDescriptorType;     //描述符的类型,这里是设备描述符DEVICE

	__le16 bcdUSB;     //指明usb的版本,比如usb2.0
	__u8 bDeviceClass;
	__u8 bDeviceSubClass;
	__u8 bDeviceProtocol;
	__u8 bMaxPacketSize0;     //端点0对应的最大包大小
	__le16 idVendor;      //厂家ID
	__le16 idProduct;     //产品ID
	__le16 bcdDevice;     //设备出厂的编号
	__u8 iManufacturer;
	__u8 iProduct;
	__u8 iSerialNumber;
	__u8 bNumConfigurations;   //可能的配置数量
}

2、usb配置

2.1、usb_host_config

描述usb配置的结构体

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];

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

2.2、usb_config_descriptor

usb配置描述符

struct usb_config_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 wTotalLength;
	__u8  bNumInterfaces;
	__u8  bConfigurationValue;
	__u8  iConfiguration;
	__u8  bmAttributes;
	__u8  bMaxPower;
} __attribute__ ((packed));

3、usb接口

每个usb接口对应一种设备功能,绑定一个usb驱动。

3.1、usb_interface

usb接口结构体

struct usb_interface {
	/* array of alternate settings for this interface,
	 * stored in no particular order */
	struct usb_host_interface *altsetting; /* 包含所有可用于该接口的可选设置的接口结构数组。每个 struct usb_host_interface 包含一套端点配置(即struct usb_host_endpoint结构所定义的端点配置。这些接口结构没有特别的顺序。*/

	struct usb_host_interface *cur_altsetting;  /* 指向altsetting内部的指针,表示当前激活的接口配置*/
	unsigned num_altsetting; /* 可选设置的数量*/

	/* If there is an interface association descriptor then it will list
	 * the associated interfaces */
	struct usb_interface_assoc_descriptor *intf_assoc;

	int minor; /* 如果绑定到这个接口的 USB 驱动使用 USB 主设备号, 这个变量包含由 USB 核心分配给接口的次设备号. 这只在一个成功的调用 usb_register_dev后才有效。*/ 
	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 */
	unsigned authorized : 1; /* used for interface authorization */

	struct device dev; /* interface specific device info */
	struct device *usb_dev;
	struct work_struct reset_ws; /* for resets in atomic context */
};

3.2、usb_host_interface

cur_altsetting成员的结构体是usb_host_interface,如下:

/* host-side wrapper for one interface setting's parsed descriptors */
struct usb_host_interface {
	struct usb_interface_descriptor desc;//当前被激活的接口描述符

	int extralen;
	unsigned char *extra; /* 额外的描述符 */

	/* array of desc.bNumEndpoints endpoints associated with this
	 * interface setting.  these will be in no particular order.
	 */
	struct usb_host_endpoint *endpoint; /* 这个接口的所有端点结构体的联合数组*/

	char *string;/* 接口描述字符串 */
};

3.3、usb_interface_descriptor

接口描述符结构体

struct usb_interface_descriptor {
  	__u8  bLength;                      //描述符的长度
  	__u8  bDescriptorType;              //描述符类型的编号

	__u8 bInterfaceNumber;       //接口的编号
	__u8 bAlternateSetting;
	__u8 bNumEndpoints;			//要使用的端点个数,表示有多少个端点描述符(不包括端点0)
	__u8 bInterfaceClass;       //接口的类型
	__u8 bInterfaceSubClass;
	__u8 bInterfaceProtocol;
	__u8 iInterface;
} __attribute__((packed));

4、usb端点

USB 通讯的最基本形式是通过一个称为端点的东西。一个USB端点只能向一个方向传输数据(从主机到设备(称为输出端点)或者从设备到主机(称为输入端点))。端点可被看作一个单向的管道。

一个 USB 端点有 4 种不同类型, 分别具有不同的数据传送方式:

控制CONTROL
控 制端点被用来控制对 USB 设备的不同部分访问. 通常用作配置设备、获取设备信息、发送命令到设备或获取设备状态报告。这些端点通常较小。每个 USB 设备都有一个控制端点称为"端点 0", 被 USB 核心用来在插入时配置设备。USB协议保证总有足够的带宽留给控制端点传送数据到设备.

中断INTERRUPT
每当 USB 主机向设备请求数据时,中断端点以固定的速率传送小量的数据。此为USB 键盘和鼠标的主要的数据传送方法。它还用以传送数据到 USB 设备来控制设备。通常不用来传送大量数据。USB协议保证总有足够的带宽留给中断端点传送数据到设备.

批量BULK
批 量端点用以传送大量数据。这些端点常比中断端点大得多. 它们普遍用于不能有任何数据丢失的数据。USB 协议不保证传输在特定时间范围内完成。如果总线上没有足够的空间来发送整个BULK包,它被分为多个包进行传输。这些端点普遍用于打印机、USB Mass Storage和USB网络设备上。

等时ISOCHRONOUS
等时端点也批量传送大量数据, 但是这个数据不被保证能送达。这些端点用在可以处理数据丢失的设备中,并且更多依赖于保持持续的数据流。如音频和视频设备等等。

控制和批量端点用于异步数据传送,而中断和同步端点是周期性的。这意味着这些端点被设置来在固定的时间连续传送数据,USB 核心为它们保留了相应的带宽。

4.1、usb_host_endpoint

struct usb_host_endpoint {
	struct usb_endpoint_descriptor desc;  //端点描述符
	struct usb_ss_ep_comp_descriptor ss_ep_comp;  //超快速端点描述符
	struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp;
	struct list_head urb_list;  //本端口对应的urb链表
	void *hcpriv;
	struct ep_device *ep_dev; /* For sysfs info */

	unsigned char *extra; /* Extra descriptors */
	int extralen;
	int enabled;  //使能的话urb才能被提交到此端口
	int streams;
};

4.2、usb_endpoint_descriptor

usb端点描述符

struct usb_endpoint_descriptor {
	__u8 bLength;		 //描述符的长度
	__u8 bDescriptorType;//描述符类型的编号

	__u8 bEndpointAddress;	//端点编号,比如端点1,就是1
	__u8 bmAttributes;		//端点的属性, 比如中断传输类型,输入类型
	__le16 wMaxPacketSize;	//一个端点的最大包大小,
	__u8 bInterval;			//间隔时间,用在中断传输上,比如间隔时间查询鼠标的数据

	/* NOTE:  仅在音频端点中使用*/
	/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
	__u8 bRefresh;
	__u8 bSynchAddress;
} __attribute__((packed));

5、usb_driver

usb_driver保存客户驱动信息,包括驱动名称,以及驱动提供给USB内核使用的函数指针等。
USB接口驱动必须提供name,probe(),disconnect()和id_table。其他的可以自行配置。

//描述usb驱动的结构体
struct usb_driver {
	const char *name;  //独有的驱动名称

	int (*probe)(struct usb_interface *intf,
		     const struct usb_device_id *id);
	//驱动的probe函数,查看驱动是否能够管理设备上的一个独特的接口,如果能,probe返回0,如果不能,返回-ENODEV

	void (*disconnect)(struct usb_interface *intf);
	//如果接口不能被访问就调用这个函数,常常因为设备没有连接或者驱动模块没有加载。

	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);
	//当设备要复位时,被usb_reset_device()调用
	int (*post_reset)(struct usb_interface *intf);
	//设备复位后,被usb_reset_device()函数调用

	const struct usb_device_id *id_table;
	//描述了这个usb驱动所支持的usb设备列表,
	//USB驱动使用ID table支持热插拔。输出参数到MODULE_DEVICE_TABLE().这是必须配置的,除非你的驱动probe函数永远不会调用
	const struct attribute_group **dev_groups;

	struct usb_dynids dynids;
	//用来保存设备id的链表
	struct usbdrv_wrap drvwrap;
	//驱动模型核心结构体的封装
	unsigned int no_dynamic_id : 1;
	//配置成1,USB核心将不会允许动态id被加入到驱动(通过阻止系统文件的创建)
	unsigned int supports_autosuspend : 1;
	//配置成1,USB核心允许自动挂起驱动
	unsigned int disable_hub_initiated_lpm : 1;
	unsigned int soft_unbind : 1;
};

const struct usb_device_id *id_table: 它指向一个usb_device_id数组,,usb_device_id结构体包含有USB设备的制造商ID,产品ID,产品版本,设备类,接口类等信息及其要匹配标志成员match_flags。当usb核心检测到某个设备的属性和id_table中的所携带的信息一致时,这个驱动程序的probe函数就会被执行。

6、URB(Universal Request Block)

USB请求块(URB)是USB设备驱动中用来描述与USB设备通信所用的基本载体和核心数据结构,USB设备中的每个端点都处理一个URB队列。

urb 以一种异步的方式同一个特定USB设备的特定端点发送或接受数据。一个 USB 设备驱动可根据驱动的需要,分配多个 urb 给一个端点或重用单个 urb 给多个不同的端点。设备中的每个端点都处理一个 urb 队列, 所以多个 urb 可在队列清空之前被发送到相同的端点。

struct urb {
	/* private: usb core and host controller only fields in the urb */
	struct kref kref; /*URB 引用计数 */
	int unlinked; /* unlink error code */
	void *hcpriv; /* host控制器的私有数据 */
	atomic_t use_count; /* 当前提交计数 */
	atomic_t reject; /* 提交失败计数 */

	/* public: documented fields in the urb that can be used by drivers */
	struct list_head urb_list; /* list head for use by the urb's
					 * current owner */
	struct list_head anchor_list; /* the URB may be anchored */
	struct usb_anchor *anchor;
	struct usb_device *dev; /* 指向这个 urb 要发送的目标 struct usb_device 的指针,这个变量必须在这个 urb 被发送到 USB 核心之前被 USB 驱动初始化 */
	struct usb_host_endpoint *ep; /* (internal) 指向端点的指针 */
	unsigned int pipe; /* 这个 urb 所要发送到的特定struct usb_device的端点消息 */
	unsigned int stream_id; /* (in) stream ID */
	int status; /* (return) non-ISO status */
	unsigned int transfer_flags; /* 传输设置(in) URB_SHORT_NOT_OK | ...*/
	void *transfer_buffer; /* 指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)的缓冲区指针。为了主机控制器驱动正确访问这个缓冲, 它必须使用 kmalloc 调用来创建, 不是在堆栈或者静态内存中。 对控制端点, 这个缓冲区用于数据中转 */
	dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
	struct scatterlist *sg; /* (in) scatter gather buffer list */
	int num_mapped_sgs; /* (internal) mapped sg entries */
	int num_sgs; /* (in) number of entries in the sg list */
	u32 transfer_buffer_length; /* 指向的缓冲区大小。如果这是 0, 传送缓冲没有被 USB 核心所使用 */
	u32 actual_length; /* 当这个 urb 完成后, 该变量被设置为这个 urb (对于 OUT urb)发送或(对于 IN urb)接受数据的真实长度.对于 IN urb, 必须是用此变量而非 transfer_buffer_length , 因为接收的数据可能比整个缓冲小 */
	unsigned char *setup_packet; /* 指向控制urb的设置数据包指针 */
	dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
	int start_frame; /* (modify) start frame (ISO) */
	int number_of_packets; /* (in) number of ISO packets */
	int interval; /* (modify) transfer interval
					 * (INT/ISO) */
	int error_count; /* (return) number of ISO errors */
	void *context; /* (in) context for completion */
	usb_complete_t complete; /* 结束处理例程函数指针, 当 urb 被完全传送或发生错误,它将被 USB 核心调用. 此函数检查这个 urb, 并决定释放它或重新提交给另一个传输中 */
	struct usb_iso_packet_descriptor iso_frame_desc[];/* (in) ISO ONLY */
};

struct urb结构不能静态构建,必须使用usb_alloc_urb函数构建,使用usb_free_urb函数释放。

//* @iso_packets:该urb的iso包数
//* @mem_flags:要分配的内存类型
//* 如果成功,该函数返回一个URB结构体指针,否则返回0.
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
{
	struct urb *urb;

	urb = kmalloc(struct_size(urb, iso_frame_desc, iso_packets),
		      mem_flags);
	if (!urb)
		return NULL;
	usb_init_urb(urb);
	return urb;
}

void usb_free_urb(struct urb *urb);

usb client driver---->usb core---->usb host controller---->usb设备(响应后原路返回)

一个urb的生命循环如下:

(1)被创建;
(2)被分配给一个特定 USB 设备的特定端点;
(3)被提交给 USB 核心;
(4)被 USB 核心提交给特定设备的特定 USB 主机控制器驱动;
(5)被 USB 主机控制器驱动处理, 并传送到设备;
(6)以上操作完成后,USB主机控制器驱动通知 USB 设备驱动。

urb 也可被提交它的驱动在任何时间取消;如果设备被移除,urb 可以被USB核心取消。

二、usb设备启动流程

Created with Raphaël 2.3.0 Usb_hub_init (usb_hub初始化,创建hub线程并进入等待队列khubd_wait等待唤醒) 插入usb设备后,usb主机控制器会产生一个hub_irq中断并唤醒等待队列 khubd_wait hub_port_connect_change(检测到hub上的端口连接被改变) 调用hub_port_connect函数处理新添加的设备

三、usb驱动启动流程函数分析

  • hub_port_connect
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
		u16 portchange)
{
...
    udev = usb_alloc_dev(hdev, hdev->bus, port1);  //(1)注册一个usb_device,然后会放在usb总线上

  choose_devnum(udev);                           //(2)给新的设备分配一个地址编号
 
   status = hub_port_init(hub, udev, port1, i);   //(3)初始化端口,与USB设备建立连接
 
  status = usb_new_device(udev);              //(4)创建USB设备,与USB设备驱动连接
...
}
  • usb_alloc_dev:创建并初始化usb_device结构体
struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
    struct usb_device *dev;              //分配usb_device
    ...
    dev = kzalloc(sizeof(*dev), GFP_KERNEL); //分配内存
    ... ...
 
    device_initialize(&dev->dev);        //初始化
    dev->dev.bus = &usb_bus_type;        //设置bus成员
    dev->dev.type = &usb_device_type;    //设置device成员
 
    ... ...
 
    return dev;                          //返回usb_device
  • choose_devnum:选择设备编号,在devnum_next和128之间寻找一个空设备编号

    设备号被用作usbfs中的文件名,对于USB-2.0总线,它们也被用作设备地址,但在USB-3.0总线地址控制器硬件分配,通常与设备号不相同。

static void choose_devnum(struct usb_device *udev)
{
	int		devnum;
	struct usb_bus	*bus = udev->bus;

	/* be safe when more hub events are proceed in parallel */
	mutex_lock(&bus->devnum_next_mutex);
	if (udev->wusb) {
		devnum = udev->portnum + 1;
		BUG_ON(test_bit(devnum, bus->devmap.devicemap));
	} else {
		/* Try to allocate the next devnum beginning at
		 * bus->devnum_next. */
		devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
					    bus->devnum_next);  //在bus->devnum_next~128区间中,循环查找下一个非0(没有设备)的编号
		if (devnum >= 128)   //若编号大于等于128,说明没有找到空余的地址编号,从头开始找
			devnum = find_next_zero_bit(bus->devmap.devicemap,
						    128, 1);
		bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);  //设置下次寻址的区间+1
	}
	if (devnum < 128) {   
		set_bit(devnum, bus->devmap.devicemap);   //设置位
		udev->devnum = devnum;
	}
	mutex_unlock(&bus->devnum_next_mutex);
}
  • hub_port_init:设置地址,获取设备描述符
//重置设备,(重新)分配地址,获取设备描述符。
//返回USB_STATE_ADDRESS中的设备,错误除外。
//如果调用的是已经存在的设备(作为usb_reset_and_verify_device),调用者必须拥有设备锁和端口锁。
//对于无法访问的新检测到的设备,通过任何全局指针,它不需要锁定设备,但仍然需要锁定端口。
static int
hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
		int retry_counter)
{
    ... ...
 
 	for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
		retval = hub_set_address(udev, devnum);   //设置地址,告诉USB设备新的地址编号
		if (retval >= 0)
			break;
		msleep(200);
	}
 
    ... ...
 
    retval = usb_get_device_descriptor(udev, 8);  //获得USB设备描述符前8个字节
 
    ... ...
 
    retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); //重新获取设备描述符信息
 
}
  • usb_new_device:获取usb设备配置,将新创建的设备添加进dev链表中,寻找与之匹配的驱动
int usb_new_device(struct usb_device *udev)
{
    err = usb_enumerate_device(udev);	/* 获取设备的描述符(枚举) */
 
    ... ...
 
    err = device_add(&udev->dev);   /*将设备添加进dev链表中,并为其匹配相应的驱动*/
}

usb_enumerate_device(udev):内部调用usb_get_configuration函数创建并填充一个usb_config_descriptor类型的结构体。usb_enumerate_device函数使用该结构体中的数据填充usb_device中的相关字段。

device_add:将设备添加到对应的bus的dev链表中,并调用bus_probe_device为设备寻找相应的驱动

int device_add(struct device *dev)
{
	... ...
	error = bus_add_device(dev);   /*将设备添加到对应的bus设备列表中*/
	
	... ...
	
	bus_probe_device(dev);  /*为设备匹配相应的驱动*/
	
	... ...
}

如果device_add调用成功,在移除设备时应该调用device_del函数。
如果device_add调用失败,则使用put_device函数删除引用计数

/**
 * bus_probe_device - probe drivers for a new device
 * @dev: device to probe
 *
 * - Automatically probe for a driver if the bus allows it.
 */
void bus_probe_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;

	if (!bus)
		return;

	if (bus->p->drivers_autoprobe)
		device_initial_probe(dev); //调用__device_attach

	mutex_lock(&bus->p->mutex);
	list_for_each_entry(sif, &bus->p->interfaces, node)
		if (sif->add_dev)
			sif->add_dev(dev, sif);
	mutex_unlock(&bus->p->mutex);
}

void device_initial_probe(struct device *dev)
{
	__device_attach(dev, true);
}
static int __device_attach(struct device *dev, bool allow_async)
{
	... ...

	if (dev->p->dead) {
		goto out_unlock;
	} else if (dev->driver) {
		if (device_is_bound(dev)) {
			ret = 1;
			goto out_unlock;
		}
		ret = device_bind_driver(dev);   //如果dev->driver存在,则将设备与驱动绑定
		if (ret == 0)
			ret = 1;
		else {
			dev->driver = NULL;
			ret = 0;
		}
	} else {
		struct device_attach_data data = {
			.dev = dev,
			.check_async = allow_async,
			.want_async = false,
		};

		if (dev->parent)
			pm_runtime_get_sync(dev->parent);

		ret = bus_for_each_drv(dev->bus, NULL, &data,
					__device_attach_driver);	//遍历总线上的driver并调用__device_attach_driver

	... ...
}

int device_bind_driver(struct device *dev)
{
	int ret;

	ret = driver_sysfs_add(dev);
	if (!ret) {
		device_links_force_bind(dev);
		driver_bound(dev);
	}
	else if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
	return ret;
}

__device_attach_driver:成功返回一个小于零的数,失败则返回0.

static int __device_attach_driver(struct device_driver *drv, void *_data)
{
	... ...
	/*判断driver和device是否匹配*/
	ret = driver_match_device(drv, dev);
	... ...
	/*若匹配,则调用driver_probe_device来probe driver*/
	ret = driver_probe_device(drv, dev);
	... ...
}

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	/*bus->match:platform bus的match函数---platform_match*/
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
static int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int trigger_count = atomic_read(&deferred_trigger_count);
	int ret;

	atomic_inc(&probe_count);
	ret = __driver_probe_device(drv, dev); //调用really_probe函数
	if (ret == -EPROBE_DEFER || ret == EPROBE_DEFER) {
		driver_deferred_probe_add(dev);

		/*
		 * Did a trigger occur while probing? Need to re-trigger if yes
		 */
		if (trigger_count != atomic_read(&deferred_trigger_count) &&
		    !defer_all_probes)
			driver_deferred_probe_trigger();
	}
	atomic_dec(&probe_count);
	wake_up_all(&probe_waitqueue);
	return ret;
}

static int __driver_probe_device(struct device_driver *drv, struct device *dev)
{
	... ...
	//具体执行probe
	ret = really_probe(dev, drv);
	... ...
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
	... ...	
	/*对于挂载在PCI/PCIe总线上的设备来说,在调用call_driver_probe 的时候就会通过ret = drv->probe(dev)调用到对应的设备驱动的probe函数。*/
	ret = call_driver_probe(dev, drv);
	... ...
	
	driver_bound(dev);  //实际将device加入驱动的设备链表
	
	... ...
}

static int call_driver_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;
	/*调用驱动总线所属的probe函数*/
	if (dev->bus->probe)
		ret = dev->bus->probe(dev);
	/*调用驱动中的probe函数*/
	else if (drv->probe)
		ret = drv->probe(dev);

	switch (ret) {
	case 0:
		break;
	case -EPROBE_DEFER:
		/* Driver requested deferred probing */
		dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
		break;
	case -ENODEV:
	case -ENXIO:
		pr_debug("%s: probe of %s rejects match %d\n",
			 drv->name, dev_name(dev), ret);
		break;
	default:
		/* driver matched but the probe failed */
		pr_warn("%s: probe of %s failed with error %d\n",
			drv->name, dev_name(dev), ret);
		break;
	}

	return ret;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值