chapter 14 the linux device model
DESCRIPTION
Chapter 14 The Linux Device Model. 潘仁義 CCU EE&COMM. The 2.6 device model. The model provides abstraction, which supports: Power management and system shutdown Understanding of the system’s structure Right order to shutdown Communication with user space Sysfs - PowerPoint PPT PresentationTRANSCRIPT
Chapter 14Chapter 14The Linux Device ModelThe Linux Device Model
潘仁義CCU EE&COMM
The 2.6 device modelThe 2.6 device model
The model provides abstraction, which supports:Power management and system shutdown
Understanding of the system’s structure
Right order to shutdown
Communication with user spaceSysfs
Knobs for changing operating parameters
Hot-pluggable devices
Device classesDescribe devices at a functional level
Object lifecyclesReference count
Device model treeDevice model tree
Sysfs ( 跑個 tree /sys 吧 ?)/proc, /dev, /sysfs
Authors can ignore the model, and trust itUnderstanding device model is good, if struct leaks
Ex. the generic DMA code works with struct device
Advanced material that need not be read
Object oriented programming (Object oriented programming ( 插個花插個花 ))
Abstract Data typingInformation hiding
Encapsulation
InheritanceDerive more specialized classes from a common class
PolymorphismRefers to the object's ability to respond in an individual manner to the same message
Dynamic bindingRefers to the mechanism that resolves a virtual function call at runtime
You can derive modified action that override the old one even after the code is compiled .
Kobject, KseKobject, Ksett
Bus, driver, Bus, driver, device, device,
partition…partition…
hotplug(), match(), hotplug(), match(), probe(), kobj_type probe(), kobj_type
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
Kobject, Ksets, and SubsystemsKobject, Ksets, and Subsystems
struct kobject supportsReference counting of objects
Tracking the lifecycle
Sysfs representationA visible representation
Data structure glueMade up of multiple hierarchies with numerous links
Hotplug event handlingNotify user space about the comings and goings of hardware
$(KERNELDIR)/lib/kobject*.c
Kobject basics (0/3)Kobject basics (0/3)
1. struct kobject {2. const char * k_name;3. char name[KOBJ_NAME_LEN];4. struct kref kref;5. struct list_head entry;6. struct kobject * parent;7. struct kset * kset;8. struct kobj_type * ktype;9. struct dentry * dentry;10. };
11. struct kset {12. struct subsystem * subsys;13. struct kobj_type * ktype;14. struct list_head list;15. spinlock_t list_lock;16. struct kobject kobj;17. struct kset_hotplug_ops * hotplug_ops;18. };
Directory entry, maybe for sysfs
Kobject basics (1/3)Kobject basics (1/3)
Embedded kobjectsA common type embedded in other structures
A top-level, abstract class from which other classes are derived
Ex. in ch3,struct cdev {
struct kobject kobj;
struct module *owner;
struct file_operations *ops;
dev_t dev;
};
struct kobject *kp = …;
struct cdev *device = container_of(kp, struct cdev, kobj);
Kobject basics (2/3)Kobject basics (2/3)
InitializationSet the entire kobject to 0, memset()
Set up some of fields with kobject_init(), ex. reference count to 1
Set the name by kobject_set_name(kobj, char *format, …)
Set up the other field, such as ktype, kset and parent
Reference countstruct kobject *kobject_get(struct kobject *kobj); //++
void kobject_put(struct kobject *kobj); //--, 0 to cleanup
“struct module *owner” in struct cdev?The existence of a kobject require the existence of module that created that kobject. ex. cdev_get()
Kobject basics (3/3)Kobject basics (3/3)
Release functionsEven predictable object life cycles become more complicated when sysfs is brought in; user-space programs can keep a reference for an arbitrary period of time.Every kobject must have a release method.The release method is not stored in the kobject itself
kobject types – kobj_typestruct kobj_type { void (*release)(struct kobject *); struct sysfs_ops * sysfs_ops; struct attribute ** default_attrs;};
The kobject contains a field, pointer ktypeIf kobject is a member of kset, the pointer provided by ksetstruct kobj_type *get_ktype(struct kobject*kobj);
跟 sysfs 有關
也許因為 擴充或 overload 方便
Kobject hierarchies, ksetKobject hierarchies, kset
The parent pointer and ksets“parent” points to another kobject, representing the next level up
“kset” is a collection of kobjects
kset are always represented in sysfs
Every kobject that is a member of a kset is represented in sysfs
ksetsksets
Adding a kobject to a ksetkobject’s kset must be pointed at the kset of interest
Call kobject_add(struct kobject *kobj); // reference count ++
kobject_init( ) + kobject_add( ) kobject_register( )
Removing from the ksetkobject_del( )
kobject_del( ) + kobject_put( ) kobject_unregister( )
Operation on ksetsvoid kset_init(struct kset *kset);
int kset_add(struct kset *kset);
int kset_register(struct kset *kset);
void kset_unregister(struct kset *kset);
struct kset *kset_get(struct kset *kset);
void kset_put(struct kset *kset);
ktype, is used in preference to the ktype in a kobject
Kobjects’ hierarchy of block subsystemKobjects’ hierarchy of block subsystem
Subsystems Subsystems
Representation for a high-level portion of the kernel
Usually show up at the top of the sysfsBlock devices, block_subsys, /sys/block
Core device hierarchy, devices_subsys, /sys/devices
Every bus type known to the kernel…
Driver authors almost never needs to create oneProbably want is to add a new “class”
Subsystem is really just a wrapper around a ksetstruct subsystem {
struct kset kset;
struct rw_semaphore rwsem; // used to serialize access
};
SubsystemsSubsystems
fs/char_dev.c, line 442subsystem_init(&cdev_subsys); //not public in sysfsdrivers/firmware/efivars.c, line 689subsystem_register(&vars_subsys); // Extensible Firmware Interface (EFI)drivers/pci/hotplug/pci_hotplug_core.c, line 672 subsystem_register(&pci_hotplug_slots_subsys);drivers/base/sys.c, line 392 subsystem_register(&system_subsys);//pseudo-bus for cpus, PICs, timers, etc…drivers/base/core.c, line 423 subsystem_register(&devices_subsys);drivers/base/bus.c: line 697 subsystem_register(&bus->subsys);drivers/base/bus.c: line 745 subsystem_register(&bus_subsys);drivers/block/genhd.c, line 307 subsystem_register(&block_subsys);
drivers/base/class.c: line 148 subsystem_register(&cls->subsys);drivers/base/class.c: line 567 subsystem_register(&class_subsys);fs/debugfs/inode.c, line 308 subsystem_register(&debug_subsys);kernel/power/main.c, line 259 subsystem_register(&power_subsys);kernel/params.c, line 690 subsystem_register(&module_subsys);kernel/ksysfs.c, line 49 subsystem_register(&kernel_subsys); //kernel sysfs attrsecurity/seclvl.c, line 655 subsystem_register(&seclvl_subsys)// BSD Secure Levels LSMdrivers/base/firmware.c: line 20 subsystem_register(s);drivers/base/firmware.c: line 30 subsystem_register(&firmware_subsys);
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
Low-level sysfs operationsLow-level sysfs operations
Every kobject exports attributes, in that its sysfs dir
#include <linux/sysfs.h>
Call kobject_add( ) to show up in sysfs
Default attributesstruct attribute {
char *name;
struct module *owner;
mode_t mode;
};
struct sysfs_ops {
ssize_t (*show)(*kobj, struct attribute *attr, char *buffer);
ssize_t (*store)(*kobj, struct attribute *attr, const char *buffer, size_t size);
};
(*release)( )
*sysfs_ops
**default_attrs
{ kfree();}
kobj_typekobj_type
PAGE_SIZE
*(show)
*(store)
sysfs_opssysfs_ops
{ snprintf();}
attributeattribute“version”
*S_IRUGO
Low-level sysfs operationsLow-level sysfs operations
Non default attributesAttributes can be added and removed at will
int sysfs_create_file(struct kobject *kobj, struct attribute *attr);int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);
The same show() and store() are calledBinary attributes
e.g., when a device is hot-plugged, a user-space program can be started via hot-plug mechanism and then passes the firmware code
struct bin_attribute { struct attribute attr; size_t size; ssize_t (*read)(struct kobject *kobj, char *buffer, loff_t pos, size_t size); ssize_t (*write)(struct kobject *kobj, char *buffer, loff_t pos, size_t size);};
int sysfs_create_bin_file(*kobj, struct bin_attribute *attr);int sysfs_remove_bin_file(*kobj, struct bin_attribute *attr);
Symbolic linksint sysfs_create_link(*kobj, struct kobject *target, char *name);void sysfs_remove_link(*kobj, char *name);
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
Hotplug event generationHotplug event generation
Hotplug event a notification to user space from the kernel that something has changed in the system’s configurationis generated whenever a kobject is created (kobject_add) or destroyed (kobject_del)e.g., a camera is plugged in USB cable, disk is repartitioned…
To invoke /sbin/hotplug/proc/sys/kernel/hotplug specifies hotplug program path
Operations in “hotplug_ops” of ksetSearch up via parent until finding a kset(*filter): to suppress hotplug event generation (*name): to pass the name of relevant subsystem for a parameter(*hotplug): to add useful environment variables for hotplug script
詳細運作容後再述
Hotplug operations’ sample codeHotplug operations’ sample code
Filter exampleUser space may want to react to the addition of a disk or a partition, but it does not normally care about request queues.
static int block_hotplug_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
return ((ktype = = &ktype_block) || (ktype = = &ktype_part));
}
The generation of hotplug events is usually handled by logic at the bus driver level
配著前面的block subsystem
圖
kobject_hotplug( )kobject_hotplug( )
Called by kobject_register( )kobject_hotplug( )
努力的往爸爸方向找 kset
呼叫 kset/subsystem 的 filter()
呼叫 kset/subsystem 的 name() 作為 /sbin/hotplug 參數 $1
return
呼叫 kset/subsystem 的 hotplug()建構環境變數
call_usermodehelper( )Setup a completion without wait
0 to skip
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
Buses, devices, and driversBuses, devices, and drivers
BusesChannel between the processor and one or more devices
Devices and device drivers
Once again, much of the material covered here will never be needed by many driver authors.
kobjectkobjectcorecore
DriverDrivercorecorebusbus
driverdriver
devicedevice
Functional view inside kernel
structdevice
structdevicedriver
structkobject
structldd_device
structldd_driver
Buses (0/2)Buses (0/2)
struct bus_type {
char *name;
struct subsystem subsys;
struct kset drivers;
struct kset devices;
int (*match)(struct device *dev, struct device_driver *drv);
struct device *(*add)(struct device * parent, char * bus_id);
int (*hotplug) (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
/* Some fields omitted */
};
Buses (1/2)Buses (1/2)
For example, lddbus in example.tgz
Bus registrationstruct bus_type ldd_bus_type = {
.name = "ldd",
.match = ldd_match, // 容後再述
.hotplug = ldd_hotplug, // 容後再述 };
int __init ldd_bus_init(void) {
ret = bus_register(&ldd_bus_type); //ret value must be checked
… // 在 bus subsystem 下 , /sys/bus/ldd
ret = device_register(&ldd_bus);
Deregistration void ldd_bus_exit(void){
device_unregister(&ldd_bus);
bus_unregister(&ldd_bus_type);
Buses (2/2)Buses (2/2)
Bus methodsint (*match)(struct device *device, struct device_driver *driver);
Called whenever a new device or driver is added for this busReturn a nonzero value if the device can be handled by driver
static int ldd_match(struct device *dev, struct device_driver *driver){
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));}
int (*hotplug) (struct device *device, char **envp, int num_envp, char *buffer, int buffer_size);
Allow the bus to add environment variables直接看範例程式 , LDDBUS_VERSION
Iterating over devices and driversbus_for_each_dev( ), bus_for_each_drv( )
Bus attributesstruct bus_attribute, (*show), (*store)BUS_ATTR(name, mode, show, store); declare “struct bus_attr_name”bus_create_file( ), bus_remove_file( ) 看 lddbus 的 BUS_ATTR(version
Devices (0/1)Devices (0/1)
struct device {
struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE];
struct bus_type *bus;
struct device_driver *driver;
void *driver_data;
void (*release)(struct device *dev);
/* Several fields omitted */
};
Must be set before registering
device->kobj->parent == &device->parent->kobj
kobject_unregister( )
kobject_del()kobject_hotplug() kobject_put()
kobject_release( )
kset’s release也就是 device_release( )
dev->release( )
Devices (1/1)Devices (1/1)
Device registrationint device_register(struct device *dev);
void device_unregister(struct device *dev);
An actual bus is a device and must be registered static void ldd_bus_release(struct device *dev)
{ printk(KERN_DEBUG "lddbus release\n"); }
struct device ldd_bus = {
.bus_id = "ldd0",
.release = ldd_bus_release
};
// device_register( ) & unregister( ) 在 ldd_bus_init( ) & exit( ) 被叫
// 在 devices subsystem 下 , /sys/devices/ldd0/
Device attributesstruct device_attribute, DEVICE_ATTR( ), device_create_file, …
Device structure embeddingDevice structure embeddingfor a specific bus (e.g., pci_dev, ldd_device)for a specific bus (e.g., pci_dev, ldd_device)
“struct device” contains the device core’s information
Most subsystems track other about the devices they host
As a result, “struct device” is usually embeddedlddbus creates its own device type for ldd devices
struct ldd_device {
char *name;
struct ldd_driver *driver;
struct device dev;
};
#define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);
sculld 多了 device register 之類動作 , 納入 sysfs, 理論上可以 hotplug; scullp 僅有 module 下有
Device driversDevice drivers
struct device_driver {
char *name;
struct bus_type *bus;
struct kobject kobj;
struct list_head devices;
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown) (struct device *dev);
};
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
ClassesClasses
net/core/net-sysfs.c, line 460 class_register(&net_class);
net/bluetooth/hci_sysfs.c, line 147 class_register(&bt_class);
drivers/pcmcia/cs.c, line 1892 class_register(&pcmcia_socket_class);
drivers/usb/core/file.c: line 90 class_register(&usb_class);
drivers/usb/core/hcd.c, line 649 class_register(&usb_host_class);
drivers/pci/probe.c, line 110 class_register(&pcibus_class);
還有很多
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
OutlinesOutlines
Base typeKobjects, Ksets, and Subsystems
Low-level sysfs operations
Derived type and interactionHotplug event generation
Buses, devices, and drivers
High level viewClasses
Put it all together
番外篇 – Dealing with Firmware