最早在去年的时候学习MMC/SD/SDIO的时候就接触过设备驱动模型,但是当时也整天看书也是迷迷糊糊的,所以最终也没有将这部分知识很好的整理一下。现在再次接触到这部分知识。也算是完成一直以来的一个想法。把这部分知识简单的整理一下备忘。
设备驱动模型最初是为了解决设备的电源管理而产生的,但是最后发展起来之后,作用就越来越大了,特别适合设备管理。对于linux设备驱动工程师来说,掌握设备驱动模型非常重要。
linux的设备驱动模型的底层机制主要包括:kobject,kobj_type,kset等几个结构。这几个结构定义在include/linux/kobject.h中。
kobject代表设备驱动模型中一个基本对象。每个kobject都对应于sysfs中的一个目录。上层结构例如device,device_driver,bus_type都嵌入了一个kobject,这相当于面向对象程序设计机制中的继承机制。kobject的定义如下:
60 struct kobject { 61 const char *name;/*名称*/ 62 struct list_head entry;/*用于链入所属的kset的链表*/ 63 struct kobject *parent;/*父object*/ 64 struct kset *kset;/*所属kset*/ 65 struct kobj_type *ktype;/*所属ktype*/ 66 struct sysfs_dirent *sd;/*sysfs中的目录项*/ 67 struct kref kref;/*生命周期(引用计数)管理*/ 68 unsigned int state_initialized:1;/*标记:初始化*/ 69 unsigned int state_in_sysfs:1;/*标记:在sysfs中*/ 70 unsigned int state_add_uevent_sent:1;/*标记:已发出KOBJ_ADD uevent*/ 71 unsigned int state_remove_uevent_sent:1;/*标记:已发出的KOBJ_REMOVE uevent*/ 72 unsigned int uevent_suppress:1;/*标记:禁止发出uevent*/ 73 };kobject的基本操作:
76 int kobject_set_name(struct kobject *kobj, const char *name, ...); 77 extern int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, 78 va_list vargs); 79 80 static inline const char *kobject_name(const struct kobject *kobj) 81 { 82 return kobj->name; 83 } 84 85 extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype); 86 extern __printf(3, 4) __must_check 87 int kobject_add(struct kobject *kobj, struct kobject *parent, 88 const char *fmt, ...); 89 extern __printf(4, 5) __must_check 90 int kobject_init_and_add(struct kobject *kobj, 91 struct kobj_type *ktype, struct kobject *parent, 92 const char *fmt, ...); 93 94 extern void kobject_del(struct kobject *kobj); 95 96 extern struct kobject * __must_check kobject_create(void); 97 extern struct kobject * __must_check kobject_create_and_add(const char *name, 98 struct kobject *parent); 99 100 extern int __must_check kobject_rename(struct kobject *, const char *new_name); 101 extern int __must_check kobject_move(struct kobject *, struct kobject *); 102 103 extern struct kobject *kobject_get(struct kobject *kobj); 104 extern void kobject_put(struct kobject *kobj); 105 106 extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);kobj_type
kobj_type是kobject所属的类型,定义了某种类型的kobject的公共属性和操作。定义如下:
108 struct kobj_type { 109 void (*release)(struct kobject *kobj); 110 const struct sysfs_ops *sysfs_ops; 111 struct attribute **default_attrs; 112 const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);//Callbacks so sysfs can determine namespaces 113 const void *(*namespace)(struct kobject *kobj); 114 };
kset
kset是一个kobject集合(或容器),包含了一系列的kobject。需要注意的是,kset内部也嵌入了kobject,这表明kset本身也是一个kobject。kset的定义如下:
159 struct kset { 160 struct list_head list; 161 spinlock_t list_lock; 162 struct kobject kobj; 163 const struct kset_uevent_ops *uevent_ops; 164 };kset的基本操作:
166 extern void kset_init(struct kset *kset); 167 extern int __must_check kset_register(struct kset *kset); 168 extern void kset_unregister(struct kset *kset); 169 extern struct kset * __must_check kset_create_and_add(const char *name, 170 const struct kset_uevent_ops *u, 171 struct kobject *parent_kobj); 172 173 static inline struct kset *to_kset(struct kobject *kobj) 174 { 175 return kobj ? container_of(kobj, struct kset, kobj) : NULL; 176 } 177 178 static inline struct kset *kset_get(struct kset *k) 179 { 180 return k ? to_kset(kobject_get(&k->kobj)) : NULL; 181 } 182 183 static inline void kset_put(struct kset *k) 184 { 185 kobject_put(&k->kobj); 186 } 187 188 static inline struct kobj_type *get_ktype(struct kobject *kobj) 189 { 190 return kobj->ktype; 191 }上层的数据结构这部分就是我们比较关注的设备,驱动和总线了。linux2.6之后的内核中引入了新的设备管理机制kobject,通过这个数据结构使所有的底层都具有统一的接口,Kobject提供基本的对象管理。它与sysfs文件系统紧密关联,每个内核中注册的kobject对象对应于sysfs文件系统中的一个目录。kobject通常通过kset组织成层次化结构,kset是具有相同类型的kobject的集合。在这些内核对象机制的基础上,linux的设备模型(/include/linux/device.h)包括设备结构devices、驱动结构drivers、总线结构buses、设备类结构classes几个关键组件。linux中的任一设备在设备模型中都由一个device对象描述,其对应的数据结构struct device定义为:633 struct device { 634 struct device *parent; 635 636 struct device_private *p; 637 638 struct kobject kobj; 639 const char *init_name; /* initial name of the device */ 640 const struct device_type *type; 641 642 struct mutex mutex; /* mutex to synchronize calls to 643 * its driver. 644 */ 645 646 struct bus_type *bus; /* type of bus device is on */ 647 struct device_driver *driver; /* which driver has allocated this 648 device */ 649 void *platform_data; /* Platform specific data, device 650 core doesn't touch it */ 651 struct dev_pm_info power; 652 struct dev_pm_domain *pm_domain; 653 654 #ifdef CONFIG_NUMA 655 int numa_node; /* NUMA node this device is close to */ 656 #endif 657 u64 *dma_mask; /* dma mask (if dma'able device) */ 658 u64 coherent_dma_mask;/* Like dma_mask, but for 659 alloc_coherent mappings as 660 not all hardware supports 661 64 bit addresses for consistent 662 allocations such descriptors. */ 663 664 struct device_dma_parameters *dma_parms; 665 666 struct list_head dma_pools; /* dma pools (if dma'ble) */ 667 668 struct dma_coherent_mem *dma_mem; /* internal for coherent mem 669 override */ 670 #ifdef CONFIG_CMA 671 struct cma *cma_area; /* contiguous memory area for dma 672 allocations */ 673 #endif 674 /* arch specific additions */ 675 struct dev_archdata archdata; 676 677 struct device_node *of_node; /* associated device tree node */ 678 679 dev_t devt; /* dev_t, creates the sysfs "dev" */ 680 u32 id; /* device instance */ 681 682 spinlock_t devres_lock; 683 struct list_head devres_head; 684 685 struct klist_node knode_class; 686 struct class *class;/*所属的类别*/ 687 const struct attribute_group **groups; /* optional groups */ 688 689 void (*release)(struct device *dev); 690 };device的基本操作788 extern int __must_check device_register(struct device *dev); 789 extern void device_unregister(struct device *dev); 790 extern void device_initialize(struct device *dev); 791 extern int __must_check device_add(struct device *dev); 792 extern void device_del(struct device *dev); 793 extern int device_for_each_child(struct device *dev, void *data, 794 int (*fn)(struct device *dev, void *data)); 795 extern struct device *device_find_child(struct device *dev, void *data, 796 int (*match)(struct device *dev, void *data));
device_driver
device_driver代表一个设备驱动程序,对应于/sys/bus/xxx/drivers./下的一个目录。定义如下:
215 struct device_driver { 216 const char *name;/*名称*/ 217 struct bus_type *bus;/*总线*/ 218 219 struct module *owner;/*所有者*/ 220 const char *mod_name; /* used for built-in modules */ 221 222 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ 223 224 const struct of_device_id *of_match_table; 225 /*操作设备的方法*/ 226 int (*probe) (struct device *dev); 227 int (*remove) (struct device *dev); 228 void (*shutdown) (struct device *dev); 229 int (*suspend) (struct device *dev, pm_message_t state); 230 int (*resume) (struct device *dev); 231 const struct attribute_group **groups;/*属性组*/ 232 233 const struct dev_pm_ops *pm;/*电源管理*/ 234 235 struct driver_private *p; 236 };bus_type
bus_type代表一个总线,对应于/sys/bus/下的一个目录。定义如下:
90 struct bus_type { 91 const char *name; 92 const char *dev_name; 93 struct device *dev_root; 94 struct bus_attribute *bus_attrs;/*总线属性*/ 95 struct device_attribute *dev_attrs;/*设备缺省属性*/ 96 struct driver_attribute *drv_attrs;/*驱动缺省属性*/ 97 /*对设备和驱动的操作方法*/ 98 int (*match)(struct device *dev, struct device_driver *drv); 99 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 100 int (*probe)(struct device *dev); 101 int (*remove)(struct device *dev); 102 void (*shutdown)(struct device *dev); 103 104 int (*suspend)(struct device *dev, pm_message_t state); 105 int (*resume)(struct device *dev); 106 107 const struct dev_pm_ops *pm; 108 109 struct iommu_ops *iommu_ops; 110 111 struct subsys_private *p; 112 };
match()方法用于判断挂在总线下的某个device和某个device_driver是否匹配,在一个device或一个device_driver注册到总线上时调用。uevent()方法用于为uevent机制添加环境变量,在处理uevent时被调用。其他方法都是操作总线上挂接的device的。probe(),remove().shutdown(),resume()这几个方法在device_driver中也定义了。内核在调用这些方法时,会优先调用bus_type中定义的方法。如果相应的方法在bus_type中未定义,才会调用device_driver中定义的方法。 bus_type的基本操作:
122 extern int __must_check bus_register(struct bus_type *bus); 123 extern void bus_unregister(struct bus_type *bus); 124 125 extern int __must_check bus_rescan_devices(struct bus_type *bus); 126 127 /* iterator helpers for buses */ 128 struct subsys_dev_iter { 129 struct klist_iter ki; 130 const struct device_type *type; 131 }; 132 void subsys_dev_iter_init(struct subsys_dev_iter *iter, 133 struct bus_type *subsys, 134 struct device *start, 135 const struct device_type *type); 136 struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); 137 void subsys_dev_iter_exit(struct subsys_dev_iter *iter); 138 139 int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, 140 int (*fn)(struct device *dev, void *data)); 141 struct device *bus_find_device(struct bus_type *bus, struct device *start, 142 void *data, 143 int (*match)(struct device *dev, void *data)); 144 struct device *bus_find_device_by_name(struct bus_type *bus, 145 struct device *start, 146 const char *name); 147 struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id, 148 struct device *hint); 149 int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, 150 void *data, int (*fn)(struct device_driver *, void *));bus_type、device和device_driver之间的关系
bus_type相当于一个容器,是device和device_driver的管理机构,它包含了一个device集合(kset)和一个device_driver集合(kset),分别表示挂在总线下的所有设备和所有设备驱动程序。
device_driver挂在某个bus_type下面,包含了一个device集合(kset),表示这个驱动程序操作(或控制)的所有设备。device_driver还包含了一个bus_type指针,表示驱动程序所在的总线。
device挂在某个bus_type下面,包含了一个device_driver指针,表示这个设备对应的设备驱动程序。device还包含一个bus_type指针,表示设备所在的总线。
需要说明的是,一个实际的总线在设备驱动模型中是用两个结构表示的:bus_type和device。bus_type代表总线类型,出现在/sys/bus/目录下;device代表总线设备,出现在/sys/devices/目录下,这表明实际的总线本质上是一种设备。/**
EXPORT_SYMBOL_GPL(bus_register);
前面花了很长时间了解了设备驱动和总线的数据结构和常见的一些方法。但是具体在一个设备整个的挂载过程中设备和设备驱动的是如何匹配到总线上并进行工作的,才是我们所有工作的目的和核心。
device的添加和删除
device_register()方法用来在设备驱动模型中添加一个设备。它调用device_initialize()初始化设备,然后调用device_add()添加设备,主要工作在device_add()中完成。
device_add()的源代码在drivers/base/core.c中,下面我们把主要的代码粘贴出来以供参考。
此处主要列举USB中设备的添加过程代码:
/* Handle physical or logical connection change events.
* This routine is called when:
* a port connection-change occurs;
* a port enable-change occurs (often caused by EMI);
* usb_reset_and_verify_device() encounters changed descriptors (as from
* a firmware download)
* caller already locked the hub
*/
static void hub_port_connect_change(struct usb_hub *hub, int port1,
u16 portstatus, u16 portchange)
{
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
unsigned wHubCharacteristics =
le16_to_cpu(hub->descriptor->wHubCharacteristics);
struct usb_device *udev;
int status, i;
dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n",
port1, portstatus, portchange, portspeed(hub, portstatus));
if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
hub->indicator[port1-1] = INDICATOR_AUTO;
}
#ifdef CONFIG_USB_OTG
/* during HNP, don't repeat the debounce */
if (hdev->bus->is_b_host)
portchange &= ~(USB_PORT_STAT_C_CONNECTION |
USB_PORT_STAT_C_ENABLE);
#endif
/* Try to resuscitate an existing device */
udev = hdev->children[port1-1];
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
udev->state != USB_STATE_NOTATTACHED) {
usb_lock_device(udev);
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */
#ifdef CONFIG_USB_SUSPEND
} else if (udev->state == USB_STATE_SUSPENDED &&
udev->persist_enabled) {
/* For a suspended device, treat this as a
* remote wakeup event.
*/
status = usb_remote_wakeup(udev);
#endif
} else {
status = -ENODEV;/* Don't resuscitate */
}
usb_unlock_device(udev);
if (status == 0) {
clear_bit(port1, hub->change_bits);
return;
}
}
/* Disconnect any existing devices under this port */
if (udev)
usb_disconnect(&hdev->children[port1-1]);
clear_bit(port1, hub->change_bits);
/* We can forget about a "removed" device when there's a physical
* disconnect or the connect status changes.
*/
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
(portchange & USB_PORT_STAT_C_CONNECTION))
clear_bit(port1, hub->removed_bits);
if (portchange & (USB_PORT_STAT_C_CONNECTION |
USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce(hub, port1);
if (status < 0) {
if (printk_ratelimit())
dev_err(hub_dev, "connect-debounce failed, "
"port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
} else {
portstatus = status;
}
}
/* Return now if debouncing failed or nothing is connected or
* the device was "removed".
*/
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
test_bit(port1, hub->removed_bits)) {
/* maybe switch power back on (e.g. root hub was reset) */
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
&& !port_is_power_on(hub, portstatus))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
if (portstatus & USB_PORT_STAT_ENABLE)
goto done;
return;
}
for (i = 0; i < SET_CONFIG_TRIES; i++) {
/* reallocate for each attempt, since references
* to the previous one can escape in various ways
*/
udev = usb_alloc_dev(hdev, hdev->bus, port1);
if (!udev) {
dev_err (hub_dev,
"couldn't allocate port %d usb_device\n",
port1);
goto done;
}
usb_set_device_state(udev, USB_STATE_POWERED);
udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
udev->wusb = hub_is_wusb(hub);
/* Only USB 3.0 devices are connected to SuperSpeed hubs. */
if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else
udev->speed = USB_SPEED_UNKNOWN;
choose_devnum(udev);
if (udev->devnum <= 0) {
status = -ENOTCONN;/* Don't retry */
goto loop;
}
/* reset (non-USB 3.0 devices) and get descriptor */
status = hub_port_init(hub, udev, port1, i);
if (status < 0)
goto loop;
usb_detect_quirks(udev);
if (udev->quirks & USB_QUIRK_DELAY_INIT)
msleep(1000);
/* consecutive bus-powered hubs aren't reliable; they can
* violate the voltage drop budget. if the new child has
* a "powered" LED, users should notice we didn't enable it
* (without reading syslog), even without per-port LEDs
* on the parent.
*/
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
&& udev->bus_mA <= 100) {
u16 devstat;
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
&devstat);
if (status < 2) {
dev_dbg(&udev->dev, "get status %d ?\n", status);
goto loop_disable;
}
le16_to_cpus(&devstat);
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_err(&udev->dev,
"can't connect bus-powered hub "
"to this port\n");
if (hub->has_indicators) {
hub->indicator[port1-1] =
INDICATOR_AMBER_BLINK;
schedule_delayed_work (&hub->leds, 0);
}
status = -ENOTCONN;/* Don't retry */
goto loop_disable;
}
}
/* check for devices running slower than they could */
if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
&& udev->speed == USB_SPEED_FULL
&& highspeed_hubs != 0)
check_highspeed (hub, udev, port1);
/* Store the parent's children[] pointer. At this point
* udev becomes globally accessible, although presumably
* no one will look at it until hdev is unlocked.
*/
status = 0;
/* We mustn't add new devices if the parent hub has
* been disconnected; we would race with the
* recursively_mark_NOTATTACHED() routine.
*/
spin_lock_irq(&device_state_lock);
if (hdev->state == USB_STATE_NOTATTACHED)
status = -ENOTCONN;
else
hdev->children[port1-1] = udev;
spin_unlock_irq(&device_state_lock);
/* Run it through the hoops (find a driver, etc) */
if (!status) {
status = usb_new_device(udev);
if (status) {
spin_lock_irq(&device_state_lock);
hdev->children[port1-1] = NULL;
spin_unlock_irq(&device_state_lock);
}
}
if (status)
goto loop_disable;
status = hub_power_remaining(hub);
if (status)
dev_dbg(hub_dev, "%dmA power budget left\n", status);
return;
loop_disable:
hub_port_disable(hub, port1, 1);
loop:
usb_ep0_reinit(udev);
release_devnum(udev);
hub_free_dev(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
if (hub->hdev->parent ||
!hcd->driver->port_handed_over ||
!(hcd->driver->port_handed_over)(hcd, port1))
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
port1);
done:
hub_port_disable(hub, port1, 1);
if (hcd->driver->relinquish_port && !hub->hdev->parent)
hcd->driver->relinquish_port(hcd, port1);
}
USB_ALLOC_DEV主要完成设备的初始化和变量的赋值:
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
* @port1: one-based index of port; ignored for root hubs
* Context: !in_interrupt()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call may not be used in a non-sleeping context.
*/
struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
if (!usb_get_hcd(bus_to_hcd(bus))) {
kfree(dev);
return NULL;
}
/* Root hubs aren't true devices, so don't allocate HCD resources */
if (usb_hcd->driver->alloc_dev && parent &&
!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
usb_put_hcd(bus_to_hcd(bus));
kfree(dev);
return NULL;
}
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.groups = usb_device_groups;
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
usb_enable_endpoint(dev, &dev->ep0, false);
dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
* string is a path along hub ports, from the root. Each device's
* dev->devpath will be stable until USB is re-cabled, and hubs
* are often labeled with these port numbers. The name isn't
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
if (unlikely(!parent)) {
dev->devpath[0] = '0';
dev->route = 0;
dev->dev.parent = bus->controller;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0') {
snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
/* Root ports are not counted in route string */
dev->route = 0;
} else {
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
/* Route string assumes hubs have less than 16 ports */
if (port1 < 15)
dev->route = parent->route +
(port1 << ((parent->level - 1)*4));
else
dev->route = parent->route +
(15 << ((parent->level - 1)*4));
}
dev->dev.parent = &parent->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
/* hub driver sets up TT records */
}
dev->portnum = port1;
dev->bus = bus;
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
pm_runtime_set_autosuspend_delay(&dev->dev,
usb_autosuspend_delay * 1000);
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
#endif
if (root_hub) /* Root hub always ok [and always wired] */
dev->authorized = 1;
else {
dev->authorized = usb_hcd->authorized_default;
dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
}
return dev;
}
USB_NEW_DEVICE完成设备的添加工作主要是封装了device_add函数:
/**
* usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been detected but not fully
* enumerated. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
* It will return if the device is configured properly or not. Zero if
* the interface was registered with the driver core; else a negative
* errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
*/
int usb_new_device(struct usb_device *udev)
{
int err;
if (udev->parent) {
/* Initialize non-root-hub device wakeup to disabled;
* device (un)configuration controls wakeup capable
* sysfs power/wakeup controls wakeup enabled/disabled
*/
device_init_wakeup(&udev->dev, 0);
}
/* Tell the runtime-PM framework the device is active */
pm_runtime_set_active(&udev->dev);
pm_runtime_get_noresume(&udev->dev);
pm_runtime_use_autosuspend(&udev->dev);
pm_runtime_enable(&udev->dev);
/* By default, forbid autosuspend for all devices. It will be
* allowed for hubs during binding.
*/
usb_disable_autosuspend(udev);
err = usb_enumerate_device(udev);/* Read descriptors */
if (err < 0)
goto fail;
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* Tell the world! */
announce_device(udev);
device_enable_async_suspend(&udev->dev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others).
*/
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
usb_mark_last_busy(udev);
pm_runtime_put_sync_autosuspend(&udev->dev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
pm_runtime_disable(&udev->dev);
pm_runtime_set_suspended(&udev->dev);
return err;
}
device_add函数完成的工作就是linux设备驱动通常完成的工作了
/**
* device_add - add device to device hierarchy.
* @dev: device.
*
* This is part 2 of device_register(), though may be called
* separately _iff_ device_initialize() has been called separately.
*
* This adds @dev to the kobject hierarchy via kobject_add(), adds it
* to the global and sibling lists for the device, then
* adds it to the other relevant subsystems of the driver model.
*
* NOTE: _Never_ directly free @dev after calling this function, even
* if it returned an error! Always use put_device() to give up your
* reference instead.
*/
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
if (!dev)
goto done;
if (!dev->p) {
error = device_private_init(dev);
if (error)
goto done;
}
/*
* for statically allocated devices, which should all be converted
* some day, we need to initialize the name. We prevent reading back
* the name, and force the use of dev_name()
*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
parent = get_device(dev->parent);
setup_parent(dev, parent);
/* use parent numa_node */
if (parent)
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
/* Notify clients of device addition. This call must come
* after dpm_sysf_add() and before kobject_uevent().
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
done:
put_device(dev);
return error;
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
ueventattrError:
device_remove_file(dev, &uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
if (parent)
put_device(parent);
name_error:
kfree(dev->p);
dev->p = NULL;
goto done;
}
error = bus_add_device(dev);此函数完成将设备添加到总线上:
/**
* bus_add_device - add device to bus
* @dev: device being added
*
* - Add device's bus attributes.
* - Create links to device's bus.
* - Add the device to its bus's list of devices.
*/
int bus_add_device(struct device *dev)
{
struct bus_type *bus = bus_get(dev->bus);
int error = 0;
if (bus) {
pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
error = device_add_attrs(bus, dev);
if (error)
goto out_put;
error = sysfs_create_link(&bus->p->devices_kset->kobj,
&dev->kobj, dev_name(dev));
if (error)
goto out_id;
error = sysfs_create_link(&dev->kobj,
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
return 0;
out_subsys:
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_id:
device_remove_attrs(bus, dev);
out_put:
bus_put(dev->bus);
return error;
}
bus_probe_device(dev);
/**
* 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;
int ret;
if (bus && bus->p->drivers_autoprobe) {
ret = device_attach(dev);
WARN_ON(ret < 0);
}
}
ret = device_attach(dev);
/**
* device_attach - try to attach device to a driver.
* @dev: device.
*
* Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible
* pair is found, break out and return.
*
* Returns 1 if the device was bound to a driver;
* 0 if no matching driver was found;
* -ENODEV if the device is not registered.
*
* When called for a USB interface, @dev->parent lock must be held.
*/
int device_attach(struct device *dev)
{
int ret = 0;
device_lock(dev);
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
pm_runtime_get_noresume(dev);
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_runtime_put_sync(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
__device_attach
static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
if (!driver_match_device(drv, dev))
return 0;
return driver_probe_device(drv, dev);
}
此处和下面的调用函数是完全相同的,具体的代码在后面进行了粘贴。
device_driver的添加和删除
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
r对于bus_add_driver(drv);
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
kobject_uevent(&priv->kobj, KOBJ_ADD);
return 0;
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
driver_attach(drv);
/**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv,__driver_attach);
}
__driver_attach
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/
if (!driver_match_device(drv, dev))
return 0;
if (dev->parent)/* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
driver_probe_device(drv, dev);
/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* This function returns -ENODEV if the device is not registered,
* 1 if the device is bound successfully and 0 otherwise.
*
* This function must be called with @dev lock held. When called for a
* USB interface, @dev->parent lock must be held as well.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_runtime_put_sync(dev);
return ret;
}
really_probe(dev, drv);
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
/如果设备的总线定义了probe方法则调用总线的probe方法,如果没有定义则去调用device_driver中定义的方法。
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}