linux设备驱动模型

调试Learning to Generate Questions by Learning What not to Generate代码bug及解决 一 路径问题 按要求下载BPE后,在prepro_util.py中修改路径,一直找不到,本来以为用相对路径,后来改成绝对路径就可以了,虽然bug很小,但解决时间过长,效率较低,还是对代码的基本功太差。 二 导入时错误 经查阅资料,应该是导入时 找不到这个包,直接修改成相对路径即可 这个代码里几乎导包都是这个方法,所以每个都需要改,直接.不行。 三 下载en包 尝试了很多方法,与主机连接不上,于是先下载下来en_core_web_sm-2.0.0.tar.gz,采用pip +路径+ 阅读详情

最早在去年的时候学习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/目录下,这表明实际的总线本质上是一种设备。
 

/**
 * bus_register - register a bus with the system.
 * @bus: bus.
 *
 * Once we have that, we registered the bus with the kobject
 * infrastructure, then register the children subsystems it has:
 * the devices and drivers that belong to the bus.
 */
int bus_register(struct bus_type *bus)
{
int retval;
struct subsys_private *priv;


priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;


priv->bus = bus;
bus->p = priv;


BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);


retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;


priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;


retval = kset_register(&priv->subsys);
if (retval)
goto out;


retval = bus_create_file(bus, &bus_attr_uevent);
if (retval)
goto bus_uevent_fail;


priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}


priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}


klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);



retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;


retval = bus_add_attrs(bus);
if (retval)
goto bus_attrs_fail;


pr_debug("bus: '%s': registered\n", bus->name);
return 0;


bus_attrs_fail:
remove_probe_files(bus);
bus_probe_files_fail:
kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
kset_unregister(bus->p->devices_kset);
bus_devices_fail:
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
kset_unregister(&bus->p->subsys);
out:
kfree(bus->p);
bus->p = NULL;
return retval;
}

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

五.linux设备驱动模型 站在设备驱动这个角度分析,设备驱动模型是如何构建出来,起到什么作用,认识它并在写驱动的时候去利用设备驱动模型 目录 一.linux 设备驱动模型简介 1.1、 什么是设备驱动模型 1.2、 为什么需要设备驱动模型 1.3、 驱动开发的2个点 二.设备驱动模型的底层架构 2.1、kobject结构体 2.2、kobj_type结构体 2.3、kset结构体 三.总线式设备驱... 阅读详情

相关推荐

linux设备驱动的模型详解

一、什么是设备驱动模型 (1)类class、总线bus、设备device、驱动driver 四个结构体 (2)kobject和对象生命周期 (3)sysfs cat 查看属性信息 、 echo 往里面写东西 (4)udev 同步信息2、设备模型解决了一些什么问题? (1)设备驱动模型负责统一实现和维护一些特性,诸如:电源管理、热插拔、对象生命周期、用

huangliangben的博客 1696

【翻译】torch.device的使用举例

参考链接: class torch.device

敲代码的小风 5641

【processing】创意编程

首先接到这个作业的时候,我是很崩溃的,我是真的不会画画QAQ,还画自己,这也太难了,于是我决定!还是祸害我爱豆吧!于是我从微博太太那里找了个图临摹 下面是太太的图 先给太太道歉!都是为了作业! 然后我画出来是这样子的 还可以!!!没有特别丑!(虽然也不是特别像吧) 但是画这个真是画死我了,下面贴上代码吧,没啥特殊的就是各种贝塞尔曲线各种圆各种线 //face stroke(70,27,11...

qq_25700571的博客 1267

从DM9000驱动看platform device与driver的关系

 快乐虾http://blog.youkuaiyun.com/lights_joy/lights@hb165.com  本文适用于ADSP-BF561uclinux-2008r1.5-rc3 (smp patch)Visual DSP++ 5.0(update 5)  欢迎转载,但请保留作者信息内核中的platform driver机制需要将设备本身的资源注册进内核

gc315630的专栏 733

python爬取《你好, 李焕英》豆瓣评论数据

# 导入工具包 import requests from bs4 import BeautifulSoup import time import pandas as pd import numpy as np # 请求头 headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'} # =

python技巧分享 3457

接口调试必看:status显示canceled的3种常见原因及修复方法

本文深度解析了接口调试中status显示canceled的三种核心原因:网络层中断(如请求超时)、应用层逻辑主动取消(如请求竞态、组件卸载)以及用户交互与浏览器行为。文章提供了从诊断到修复的系统性方案,包括分析Network Timing、使用Axios CancelToken、优化请求策略与性能,帮助开发者从根本上解决这一常见问题。

bb456的博客 937

Linux驱动开发实战(一)——设备驱动模型

在早期的Linux内核中并没有为设备驱动提供统一的设备模型。随着内核的不断扩大及系统更加复杂,编写一个驱动程序越来越困难,所以在Linux2.6内核中添加了一个统一的设备模型。这样,写设备驱动程序就稍微容易一些了。本章将对设备模型进行详细的介绍。设备驱动模型比较复杂,Linux系统将设备和驱动归一到设备驱动模型中来管理。设备驱动模型的提出,解决了以前编写驱动程序没有统一方法的局面。设备驱动模型给各种驱动程序提供了很多辅助性的函数,这些函数经过严格测试,可以很大程度上地提高驱动开发人员的工作效率。

m0_56145255的博客 3358

Maxwell个人初学经验及资料分享

前段时间学习了课题组基于Maxwell所建立的模型,因为以前从来没有使用过,只是按照一步一步记忆了操作,但总觉得不熟悉,我想是缺乏对这个软件整体的了解,真正想上手只会这一个模型也没有办法扩展。但是我感觉这些有限元分析软件学习起来应该有一些共性,基于以前对COMSOL学习的一点经验,我就在官网和其他网站找了一些学习资源构成一条基础入门之路,也可能有更好的资源,仅代表个人观点做一下分享。以上就是本人对该软件初步学习的一点理解,跟着这样的操作不到一个星期就能初步的掌握。...

怎么又是萝卜的博客 5632

Spark Streaming 出现‘numRecords must not be negative‘报错解决

参考过:https://blog.youkuaiyun.com/xueba207/article/details/51135423?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7E

u011135852的博客 1098

VMware Converter 6.2.0保姆级教程:从物理机到ESXi主机的完整迁移指南(含常见错误排查)

本文提供VMware Converter 6.2.0从物理机迁移至ESXi主机的完整保姆级教程。详细解析了迁移前的环境规划、核心转换过程步骤、版本差异对比,并重点针对代理安装失败、任务卡顿、虚拟机无法启动等常见错误提供了实战排查与解决方案,确保P2V迁移顺利进行。

sam99的博客 380

手把手教你学AUTOSAR(13.1)--基于 AUTOSAR 的开发实战实例(一)

通过上述几个基于 AUTOSAR 的开发实战实例,你可以全面了解如何从需求分析、系统设计、软件开发、集成测试到部署和验证等多个环节进行 AUTOSAR 系统的开发。这些实例不仅涵盖了不同的应用场景,还提供了具体的代码实现和技术细节,帮助你更好地应用 AUTOSAR 标准。

MHD0815的博客 1195

Linux设备驱动模型

文章目录前言1.linux设备驱动模型简介2.设备驱动模型的底层架构3.总线式设备驱动组织方式4.platform平台总线工作原理4.平台总线实践环节 前言 1.linux设备驱动模型简介 1、什么是设备驱动模型 (1)类class、总线bus、设备device、驱动driver(内核代码中有4个结构体) (2)kobject和对象生命周期(自动管理生命周期) (3)sysfs(虚拟文件系统,在内核空间和用户空间间建立关系,把内核的结构体变量的一些值以文件的形式展现出来,通过echo、cat操作属性节点

weixin_44705391的博客 4320

【Simulink教程案例7】基于Simulink的滑模控制器设计与实现

欢迎订阅滑膜控制是一种变结构控制策略,其和常规控制方法的主要区别在于控制的不连续性,即一种使系统结构随时间变化的开关特性。所以,滑膜控制器也叫做变结构控制器,其本质是一类特殊的非线性控制器,并且这种非线性为不连续性。滑膜控制器和其他控制方式最大的区别在于其结构的不固定性,在其工作过程中,系统当前的状态会发生变化,使得系统按照预先设置的“滑动模态”的状态轨迹运动。正是由于这个特点,滑膜控制器具有快速响应的优点。滑模控制的基本定义如下所示:1).穿越切换面上的某个点;2).从切换面上的某个点离开;

FPGA/MATLAB学习教程/源码/项目合作开发 3241

Linux 设备驱动模型

本质:描述硬件特性的数据结构职责声明硬件资源(内存地址、中断号、寄存器映射等)描述设备唯一标识(如 PCI 厂商/设备 ID)提供设备树(Device Tree)兼容性标识本质:操作硬件的软件接口职责实现设备操作方法(probe()remove()注册字符/块/网络设备接口处理中断和数据传输管理电源状态组件角色生命周期依赖关系设备硬件描述符内核启动/热插拔时创建不依赖特定驱动驱动硬件操作器模块加载时注册依赖设备存在总线匹配中介内核初始化时建立。

X 1053

13、无人机网络安全攻击检测:入侵检测系统综述

本文综述了无人机网络(FANETs)中的网络安全攻击与入侵检测系统(IDS)研究进展。文章介绍了无人机网络的架构设计、路由协议分类及移动模型,重点分析了DoS、DDoS、病毒蠕虫和零日攻击等常见安全威胁,并系统梳理了网络型、主机型、签名型、异常型、混合型等多种IDS的技术原理与应用。通过对比不同攻击类型及其检测机制,提出了综合使用多类IDS、更新签名库、优化路由、加强加密和建立应急响应等安全防护建议。同时展望了人工智能、量子安全和融合安全架构等未来发展趋势,旨在为提升无人机网络的安全性提供全面的技术参考。

wasm7browser的博客 162

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

LINUX设备驱动模型简介

××××××××××××××LINUX设备驱动模型简介×××××××××××××××××第一部分————————————————————————————————————- 1.linux设备驱动模型简介 2.设备驱动模型的底层架构:类,总线,设备,驱动,platform3.实践:使用设备驱动模型来加载上一个led驱动1.linux设备驱动模型简介 《1》什么是设备驱动模型将一个概念时怎样讲明白

love23_linuxer的博客 666

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

LINUX设备驱动模型之class

1、LINUX设备驱动模型中的bus、device、driver,。其中bus:实际的总线,device:实际的设备和接口,而driver:对应存在的驱动。 2、但本节要介绍的class,是设备类,完全是抽象出来的概念,没有对应的实体。所谓设备类,是指提供的用户接口相似的一类设备的集合,常见的设备类的有block、tty、input、usb等等。 3、class对应的代码在drivers/ba

当我荒废时间的时候,会有多少人在拼命 3299

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

(五)Linux设备驱动模型介绍

本系列导航 (一)初识Linux驱动 (二)Linux设备驱动的模块化编程 (三)写一个完整的Linux驱动程序访问硬件并写应用程序进行测试 (四)Linux设备驱动之多个同类设备共用一套驱动 (五)Linux设备驱动模型介绍 (六)Linux驱动子系统-I2C子系统 (七)Linux驱动子系统-SPI子系统 (八)Linux驱动子系统-PWM子系统 (九)Linux驱动子系统-Light子系统 ...

韩朋的博客 3882

LINUX设备驱动模型分析之一 总体概念说明

这段时间阅读了LINUX SYSFS模块的代码,并完成了相应的学习笔记,阅读这些代码,为我们分析LINUX设备驱动模型提供了基础。下面这一段时间我将分析LINUX设备驱动模型。 本次分析的LINUX设备驱动模型,主要涉及如下几个部分: 一、LINUX设备驱动模型总体概述 二、LINUX总线(BUS)接口分析 三、LINUX设备(DEVICE)接口...

lickylin的专栏 2593
上一篇: 我想大声对你说--USB
下一篇: 函数运行时间计算
野-百-合
博客等级 码龄17年 308粉丝 118原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值