Linux内核--usb子系统的分析

drivers/usb/core/usb.c

subsys_init(usb_init);
module_exit(usb_exit);

我们 看到一个subsys_initcall,它也是一个宏,我们可以把它理解为module_init,只不过这部分代码比较核心,开发者们把它看做一个子系统,而不仅仅是一个模块。usbcore这个模块它代表的不是某一个设备,而是所有usb设备赖以生存的模块,Linux中,像这样一个类别的设备驱动被鬼节为一个子系统。比如PCI子系统、SCSI子系统,基本上,drivers/目录西面的每一个目录就算为一个子系统,因为他们代表了一类设备。

subsys_initcall(usb_init)的意思就是告诉我们usb_init是usb子系统真正的初始化函数,而usb_exit()将是整个usb子系统的结束时的清理函数。

我们需要从usb_init函数开始分析:

static int __init usb_init(void)

__init标记:它对于内核来说就是一种暗示,表明这个函数仅仅在初始化期间使用,在模块被装载之后,它占用的资源就会释放掉,用作别用。__init的定义在include/linux/init.h

#define __init__section(.init.text) __cold notrace

__attribute__、__section__等等都是GNUC的扩展,GNUC作为能够编译内核的唯一编译器。通常编译器将函数放在.text段,变量放在.data或.bss段,使用section属性,可以让编译器将函数或变量放在指定的段中。__init的定义便表示将它修饰的代码放在.init.text段中。连接器可以把相同段的代码或数据安排在一起,比如__init修饰的所有代码都被放在.init.text段中,初始化结束后就可以释放这部分内存。


设备模型:

总线、设备、驱动:(bus、device、driver)定义在include/linux/device.h

struct bus_type {
	const char		*name;
	struct bus_attribute	*bus_attrs;
	struct device_attribute	*dev_attrs;
	struct driver_attribute	*drv_attrs;

	int (*match)(struct device *dev, struct device_driver *drv);
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
	int (*probe)(struct device *dev);
	int (*remove)(struct device *dev);
	void (*shutdown)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	struct dev_pm_ops *pm;

	struct bus_type_private *p;
};


struct device_driver {
	const char		*name;
	struct bus_type		*bus;

	struct module		*owner;
	const char 		*mod_name;	/* used for built-in modules */

	int (*probe) (struct device *dev);
	int (*remove) (struct device *dev);
	void (*shutdown) (struct device *dev);
	int (*suspend) (struct device *dev, pm_message_t state);
	int (*resume) (struct device *dev);
	struct attribute_group **groups;

	struct dev_pm_ops *pm;

	struct driver_private *p;
};


struct device {
	struct device		*parent;

	struct device_private	*p;

	struct kobject kobj;
	const char		*init_name; /* initial name of the device */
	struct device_type	*type;

	struct semaphore	sem;	/* semaphore to synchronize calls to
					 * its driver.
					 */

	struct bus_type	*bus;		/* type of bus device is on */
	struct device_driver *driver;	/* which driver has allocated this
					   device */
	void		*driver_data;	/* data private to the driver */
	void		*platform_data;	/* Platform specific data, device
					   core doesn't touch it */
	struct dev_pm_info	power;

#ifdef CONFIG_NUMA
	int		numa_node;	/* NUMA node this device is close to */
#endif
	u64		*dma_mask;	/* dma mask (if dma'able device) */
	u64		coherent_dma_mask;/* Like dma_mask, but for
					     alloc_coherent mappings as
					     not all hardware supports
					     64 bit addresses for consistent
					     allocations such descriptors. */

	struct device_dma_parameters *dma_parms;

	struct list_head	dma_pools;	/* dma pools (if dma'ble) */

	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
					     override */
	/* arch specific additions */
	struct dev_archdata	archdata;

	dev_t			devt;	/* dev_t, creates the sysfs "dev" */

	spinlock_t		devres_lock;
	struct list_head	devres_head;

	struct klist_node	knode_class;
	struct class		*class;
	struct attribute_group	**groups;	/* optional groups */

	void	(*release)(struct device *dev);
};


struct device中的bus表示这个设备连到那个总线上,driver表示这个设备的驱动是什么,struct device_driver中的bus表示这个驱动属于那个总线,klist_devices表示这个驱动都支持哪些设备,因为这里device是复数,又是list,更因为一个驱动可以支持多个设备,而一个设备只能绑定一个驱动。当然struct bus_type中的drivers和devices分别表示了这个总线拥有哪些设备和哪些驱动。

kobjece和kset是Linux设备模型中最基本的元素,存在的意义是把总线、设备和驱动这样的对象连接到设备模型上。

整个linux的设备模型是一个OO的体系结构,总线、设备和驱动都是其对象,kobject是它们的基类,所实现的知识一些公共的接口,kset是同种类型kobject对象的集合,也可以说是对象的容器。因为在c里不可能有c++里的class继承、组合等概念,只有通过kobject嵌入到对象结构里来实现。这样,内核使用kobject将各个对象连接起来组成一个分层的结构体系。kobject结构里包含了parent成员,指向了另外一个kobject结构,也就是这个分层结构的上一层结点。而kset是通过链表来实现的,struct bus_type结构中的成员drivers和devices表示了一条总线拥有两条链表,一条是设备链表,一条是驱动链表。我们知道了总线对应的数据结构,就可以找到这条总线关联了多少设备,又有哪些驱动来支持这类设备。






原文地址:https://www.cnblogs.com/pangblog/p/3395487.html