36
Chapter 14 Chapter 14 The Linux Device Model The Linux Device Model 潘潘潘 CCU EE&COMM

14_LinuxDeviceModel

Embed Size (px)

DESCRIPTION

A brief introduction to linux device model.

Citation preview

  • Chapter 14The Linux Device ModelCCU EE&COMM

  • The 2.6 device modelThe model provides abstraction, which supports:Power management and system shutdownUnderstanding of the systems structureRight order to shutdownCommunication with user spaceSysfsKnobs for changing operating parametersHot-pluggable devicesDevice classesDescribe devices at a functional levelObject lifecyclesReference count

  • Device model treeSysfs (tree /sys ?)/proc, /dev, /sysfs

    Authors can ignore the model, and trust itUnderstanding device model is good, if struct leaksEx. the generic DMA code works with struct deviceAdvanced material that need not be read

  • Object oriented programming ()Abstract Data typingInformation hidingEncapsulationInheritanceDerive more specialized classes from a common classPolymorphismRefers to the object's ability to respond in an individual manner to the same messageDynamic bindingRefers to the mechanism that resolves a virtual function call at runtimeYou can derive modified action that override the old one even after the code is compiled .Kobject, KsetBus, driver, device, partitionhotplug(), match(), probe(), kobj_type

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together

  • Kobject, Ksets, and Subsystemsstruct kobject supportsReference counting of objectsTracking the lifecycleSysfs representationA visible representationData structure glueMade up of multiple hierarchies with numerous linksHotplug event handlingNotify 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 kobjectsA common type embedded in other structuresA top-level, abstract class from which other classes are derivedEx. 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)InitializationSet the entire kobject to 0, memset()Set up some of fields with kobject_init(), ex. reference count to 1Set the name by kobject_set_name(kobj, char *format, )Set up the other field, such as ktype, kset and parentReference countstruct kobject *kobject_get(struct kobject *kobj); //++void kobject_put(struct kobject *kobj); //--, 0 to cleanupstruct 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 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 itselfkobject 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, ksetThe parent pointer and ksetsparent points to another kobject, representing the next level upkset is a collection of kobjectskset are always represented in sysfsEvery kobject that is a member of a kset is represented in sysfs

  • ksetsAdding a kobject to a ksetkobjects kset must be pointed at the kset of interestCall 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 subsystem

  • Subsystems Representation for a high-level portion of the kernelUsually show up at the top of the sysfsBlock devices, block_subsys, /sys/blockCore device hierarchy, devices_subsys, /sys/devicesEvery bus type known to the kernelDriver authors almost never needs to create oneProbably want is to add a new classSubsystem is really just a wrapper around a ksetstruct subsystem { struct kset kset; struct rw_semaphore rwsem; // used to serialize access};

  • Subsystemsfs/char_dev.c, line 442 subsystem_init(&cdev_subsys); //not public in sysfsdrivers/firmware/efivars.c, line 689 subsystem_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, etcdrivers/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);

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together

  • Low-level sysfs operationsEvery kobject exports attributes, in that its sysfs dir#include 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);};

    { kfree();}kobj_typePAGE_SIZEsysfs_ops{ snprintf();}attribute

  • Low-level sysfs operationsNon default attributesAttributes can be added and removed at willint 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 attributese.g., when a device is hot-plugged, a user-space program can be started via hot-plug mechanism and then passes the firmware codestruct 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);

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together

  • Hotplug event generationHotplug event a notification to user space from the kernel that something has changed in the systems configurationis generated whenever a kobject is created (kobject_add) or destroyed (kobject_del)e.g., a camera is plugged in USB cable, disk is repartitionedTo invoke /sbin/hotplug/proc/sys/kernel/hotplug specifies hotplug program pathOperations 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 codeFilter 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 levelblock subsystem

  • kobject_hotplug( )Called by kobject_register( )kobject_hotplug( )ksetkset/subsystemfilter()kset/subsystemname() /sbin/hotplug $1returnkset/subsystemhotplug()call_usermodehelper( )Setup a completion without wait0 to skip

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together

  • Buses, devices, and driversBusesChannel between the processor and one or more devicesDevices and device driversOnce again, much of the material covered here will never be needed by many driver authors.kobjectcoreDrivercorebusdriverFunctional view inside kernel structdevicestructdevicedriverstructkobjectstructldd_devicestructldd_driver

  • 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.tgzBus 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/lddret = device_register(&ldd_bus);Deregistration void ldd_bus_exit(void){device_unregister(&ldd_bus);bus_unregister(&ldd_bus_type);

  • 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 driverstatic 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_VERSIONIterating 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_namebus_create_file( ), bus_remove_file( ) lddbusBUS_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 registeringdevice->kobj->parent == &device->parent->kobjkobject_unregister( )kobject_del()kobject_hotplug()kobject_put()kobject_release( )ksets releasedevice_release( )dev->release( )

  • 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 embeddingfor a specific bus (e.g., pci_dev, ldd_device)struct device contains the device cores information Most subsystems track other about the devices they hostAs a result, struct device is usually embeddedlddbus creates its own device type for ldd devicesstruct 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; scullpmodule

  • Device driversstruct 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);};

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together

  • Classesnet/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);

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together

  • OutlinesBase typeKobjects, Ksets, and SubsystemsLow-level sysfs operationsDerived type and interactionHotplug event generationBuses, devices, and driversHigh level viewClassesPut it all together Dealing with Firmware