400 likes | 652 Views
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
E N D
Chapter 14The 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 • Knobs for changing operating parameters • Hot-pluggable devices • Device classes • Describe devices at a functional level • Object lifecycles • Reference count
Device model tree • Sysfs (跑個tree /sys 吧?) • /proc, /dev, /sysfs • Authors can ignore the model, and trust it • Understanding 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 (插個花) Kobject, Kset • Abstract Data typing • Information hiding • Encapsulation • Inheritance • Derive more specialized classes from a common class • Polymorphism • Refers to the object's ability to respond in an individual manner to the same message • Dynamic binding • Refers 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 . Bus, driver, device, partition… hotplug(), match(), probe(), kobj_type
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together
Kobject, Ksets, and Subsystems • struct kobject supports • Reference counting of objects • Tracking the lifecycle • Sysfs representation • A visible representation • Data structure glue • Made up of multiple hierarchies with numerous links • Hotplug event handling • Notify user space about the comings and goings of hardware • $(KERNELDIR)/lib/kobject*.c
Kobject basics (0/3) • struct kobject { • const char * k_name; • char name[KOBJ_NAME_LEN]; • struct kref kref; • struct list_head entry; • struct kobject * parent; • struct kset * kset; • struct kobj_type * ktype; • struct dentry * dentry; • }; • struct kset { • struct subsystem * subsys; • struct kobj_type * ktype; • struct list_head list; • spinlock_t list_lock; • struct kobject kobj; • struct kset_hotplug_ops * hotplug_ops; • }; Directory entry, maybe for sysfs
Kobject basics (1/3) • Embedded kobjects • A 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) • Initialization • Set 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 count • struct 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) • Release functions • Even 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_type struct kobj_type { void (*release)(struct kobject *); struct sysfs_ops * sysfs_ops; struct attribute ** default_attrs; }; • The kobject contains a field, pointer ktype • If kobject is a member of kset, the pointer provided by kset • struct kobj_type *get_ktype(struct kobject*kobj); 也許因為 擴充或overload方便 跟sysfs有關
Kobject 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
ksets • Adding a kobject to a kset • kobject’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 kset • kobject_del( ) • kobject_del( ) + kobject_put( ) kobject_unregister( ) • Operation on ksets • void 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
Subsystems • Representation for a high-level portion of the kernel • Usually show up at the top of the sysfs • Block 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 one • Probably want is to add a new “class” • Subsystem is really just a wrapper around a kset struct subsystem { struct kset kset; struct rw_semaphore rwsem; // used to serialize access };
fs/char_dev.c, line 442subsystem_init(&cdev_subsys); //not public in sysfs drivers/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 attr security/seclvl.c, line 655 subsystem_register(&seclvl_subsys)// BSD Secure Levels LSM drivers/base/firmware.c: line 20 subsystem_register(s); drivers/base/firmware.c: line 30 subsystem_register(&firmware_subsys); Subsystems
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together
*(show) (*release)( ) *(store) *sysfs_ops **default_attrs “version” * S_IRUGO Low-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 attributes struct 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); }; { kfree(); } kobj_type sysfs_ops { snprintf(); } attribute PAGE_SIZE
Low-level sysfs operations • Non default attributes • Attributes 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 called • Binary 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 links • int sysfs_create_link(*kobj, struct kobject *target, char *name); • void sysfs_remove_link(*kobj, char *name);
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together
Hotplug event generation • Hotplug event • a notification to user space from the kernel that something has changed in the system’s configuration • is 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 kset • Search 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 code • Filter example • User 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( ) • Called by kobject_register( ) kobject_hotplug( ) 努力的往爸爸方向找kset 0 to skip return 呼叫kset/subsystem的filter() 呼叫kset/subsystem的name() 作為/sbin/hotplug 參數$1 呼叫kset/subsystem的hotplug() 建構環境變數 call_usermodehelper( ) Setup a completion without wait
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together
device Buses, devices, and drivers • Buses • Channel 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. bus struct device Driver core kobject core struct ldd_device driver struct device driver struct ldd_driver struct kobject Functional view inside kernel
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) • For example, lddbus in example.tgz • Bus registration • struct 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) • Bus methods • int (*match)(struct device *device, struct device_driver *driver); • Called whenever a new device or driver is added for this bus • Return 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 drivers • bus_for_each_dev( ), bus_for_each_drv( ) • Bus attributes • struct 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) 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_hotplug() kobject_del() kobject_put() kobject_release( ) kset’s release 也就是device_release( ) dev->release( )
Devices (1/1) • Device registration • int 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 attributes • struct device_attribute, DEVICE_ATTR( ), device_create_file, …
Device structure embeddingfor 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 embedded • lddbus 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 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); };
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together
Classes • 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); • 還有很多
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together
Outlines • Base type • Kobjects, Ksets, and Subsystems • Low-level sysfs operations • Derived type and interaction • Hotplug event generation • Buses, devices, and drivers • High level view • Classes • Put it all together • 番外篇 – Dealing with Firmware