Anda di halaman 1dari 36

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 systems 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 (


)
Abstract Data typing
Information hiding
Encapsulation

Inheritance

Kobject,
Kset
Bus, driver,
device,
partition

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
hotplug(), match(),

Dynamic binding

probe(), kobj_type

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 .

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)


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)


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.

overload
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 *);
sysfs
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);

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
kobjects 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

Kobjects hierarchy of block subsystem

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

Subsystems
fs/char_dev.c, line 442
subsystem_init(&cdev_subsys);
//not public in sysfs
drivers/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, 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);

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

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
kfree();
}

Default attributes
struct attribute {
char *name;
struct module *owner;
mode_t mode;
};

kobj_type
(*release)( )
*sysfs_ops
**default_attrs

sysfs_ops
*(show)
*(store)

{
snprintf();
}

attribute
version
*

struct sysfs_ops {
ssize_t (*show)(*kobj, struct attribute *attr, char *buffer);
S_IRUGO
ssize_t (*store)(*kobj, struct attribute *attr, const char *buffer, size_t size);
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 systems 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));
block subsystem
}

The generation of hotplug events is usually handled by logic at the


bus driver level

kobject_hotplug( )
Called by kobject_register( )
kobject_hotplug( )

kset
kset/subsystem filter()
kset/subsystem name()
/sbin/hotplug $1
kset/subsystem hotplug()

call_usermodehelper( )
Setup a completion without wait

0 to skip

return

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

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.
device

struct
device

struct
ldd_device

Driver kobject
core
core

bus
driver

struct
ldd_driver

struct
device
driver

Functional view inside kernel

struct
kobject

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 {
Must be set before registering
struct device *parent;
struct kobject kobj;
device->kobj->parent
char bus_id[BUS_ID_SIZE];
== &device->parent->kobj
struct bus_type *bus;
struct device_driver *driver;
kobject_unregister( )
void *driver_data;
void (*release)(struct device *dev);
/* Several fields omitted */ kobject_hotplug() kobject_del() kobject_put()
};
kobject_release( )

ksets 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 embedding


for a specific bus (e.g., pci_dev, ldd_device)
struct device contains the device cores 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

Anda mungkin juga menyukai