PPTX Slides

advertisement
Dr A Sahu
Dept of Comp Sc & Engg.
IIT Guwahati
•
•
•
•
USB Drivers Overview
URB (USB request Block)
Writing a USB Driver
Linux Device Model
– Kobjects, Ksets and Subsystem
– Hot plug event generation
– Bus, Device, Driver and Class
– Dealing with Firmwire
• Last/Next Class Agenda
– Summery after mid semester, Question
pattern, Assignments
• USB drivers lives between
different kernel subsystem
(blk,net,char..) and USB HW
controller
• USB core provide an
interface to access for USB
drivers to use to access and
control USB hw
• Connect without worrying
the different types of USB
hardware controller that
are present in the system
USER
VFS
layer
Blok Net Char TTY
layer Layer Layer Layer
USB device driver
USB Core
USB host controller
Hardware
….
kernel
• USB device is complex
thing
• Linux kernel provides a
subsystem USB Core to
handle most of the
complexity
• USB device consist of
configuration, interface,
endpoints
• USB device bind to USB
interfaces not to entire
USB devices
Device
Interface
Config
Endpoint
Endpoint
Endpoint
USB
Drivers
Interface
Endpoint
Endpoint
Endpoint
USB
Drivers
• USB endpoint can carry data in only one direction either
host to dev (OUT endpoint) or host to dev (IN endpoint)
• Endpoints are 4 types: that describe how data is
transmitted
– Control: allow access to diff parts of USB dev. Used for conf
dev, retrieve info, send cmd, retrieve status. This is small
size end points call endpoint 0
– Interrupt:small amount of data at fixed rate: keyborad/mice
– BULK:Large data with no loss : printer, storage, network
– ISOCHRONOUS: large data, not guaranteed, stream
audio/video
• Struct usb_host_endpoint: address, bitmask attaributes,
Maxpacket size that point can handle , Intr Interval
• USB end points are bundled up with interfaces
• One interface handle one type of logical
connection (a kbd,mice or a audio)
• Some USB can handle multiple interfaces USB
speaker with kbd for buttons and USB audio
stream
• USB interfaces may have alternate setting
which are diff choices for param of the
interface
• Struct usb_interface: array of altsetting,
num_altsetting, cur_altsetting, minor
• USB interface are themselves bundle up with
configurations
• A USB device can have multiple conf and might
switch between them inorder to change the state
of device
• A single conf is activated at a time
• Summery:
–
–
–
–
Device: one or more Conf
Conf : one or more Interface
Interface: one or more setting
Interface: one or more end points
• /sys/dev/pci0000:00/000:9:0/usb2/2-1
• Long device path
• First USB device is a root hub: USB controller
usually connected in a PCI device
• Whole USB bus connect to root hub
• Every USB device take number of root hub as
first number in its name, followed by character
and then the number of port that device
connected.
• Root_hub-hub_port:config.interface
• Linux kernel communicated with all USB device with
URBS
• Urb is used to send/receive data from a specific USB
endpoints on a specific usb device in async manner
• Every end point can handle queue of urbs
• Lifecycle of urb
–
–
–
–
–
Created by USB dev driver
Assigned to specific endpoints of a USB dev
Submitted to a USB core by USB driver
Submitted to USB host Controller by USB core
Processed by the USB Host Controller that makes a USB
transfer to the device
– When urbb is completed, USB host controller notify the
dev driver
• The user plugs a device into USB port.
• Hub detects the device
•
• Host learns of new device
• Hub resets the device.
• Hub establishes a single path between
device and a bus.
10 of 24
• USB device drivers are registered and
deregistered at the subsystem.
• A driver must register 2 entry points and its
name.
• For certain USB devices, a driver registers file
operation and minor number.
11 of 24
struct usb_driver {
const char *name;
void * (*probe)(struct usb_device *, unsigned int,
const struct usb_device_id *id_table);
void (*disconnect)(struct usb_device *, void *);
struct list_head driver_list;
struct file_operations *fops;
int minor;
struct semaphore serialize;
int (*ioctl) (struct usb_device *dev, unsigned int code,
void *buf);
const struct usb_device_id *id_table;
};
12 of 24
USB driver has two entry points to normal
drivers :• void *probe ( struct usb device *dev, unsigned
int interface, const struct usb_device_id *id table) –
-This entry point is called whenever a new device is attached to the
bus.
void disconnect ( struct usb device *dev,
void *drv context)
- This function is called whenever a device is disconnected.
13 of 24
• We register our USB driver with USB
subsystem using
usb_register (struct usb_driver *u_drv)
:- This is usually invoked in our init_module().
• Un-registering of the USB driver is usually
performed using :-
usb_deregister (struct usb_driver *drv)
:-This is usually invoked in our cleanup_module().
14 of 24
static struct usb_device_id skel_table [ ] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID,
USB_SKEL_PRODUCT_ID)
},
{}
/* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table);
• A USB device when attached will be
enumerated.
• Enumeration means assigning the device a
unique number.
• The unique number must range from 1-127.
• A descriptor is basically a structure containing
information about the device and its properties.
• A driver passes messages to the USB subsystem
using URB
• A URB consists of relevant information for
executing a USB transaction.
• It delivers the data and status back.
• Execution of an URB is an asynchronous
operation. Ongoing transfer for a particular
URB can be cancelled at any time.
• Each URB has a completion handler.
• URB’s can be linked.
• 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
• Sysfs : /proc, /dev, /sysfs
bus
usb
drivers
Usbhid
device
devices
class
pci0
Inp dev
Dev0:10
mice
usb2
port1
Dev1-10
• 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
• 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
• Dynamic binding
hotplug(), match(),
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 .
• 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
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
• 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);
• 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);
• 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()
• 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
• 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
• 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
};
• Every kobject exports attributes, in that its sysfs dir
• #include <linux/sysfs.h>
• Call kobject_add( ) to show up in sysfs
• Default attributes
kobj_type
(*release)( )
struct attribute {
char *name;
*sysfs_ops
struct module *owner; **default_attrs
mode_t mode;
};
kfree();
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);
};
• 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);
• 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
• 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
core
bus
driver
struct
ldd_driver
kobject
core
struct
device
driver
Functional view inside kernel
struct
kobject
• 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
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 */
};
• 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);
• 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)
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;
Must be set before registering
device->kobj->parent
== &device->parent->kobj
kobject_unregister( )
kobject_hotplug() kobject_del() kobject_put()
void (*release)(struct device *dev);
/* Several fields omitted */
};
kobject_release( )
kset’s release
evice_release( )
dev->release( )
• 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( )
// evices subsystem, /sys/devices/ldd0/
• Device attributes
– struct device_attribute, DEVICE_ATTR( ),
device_create_file, …
• “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);
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);
};
• 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);
Download