Documente Academic
Documente Profesional
Documente Cultură
Michael Mitchell
COP 5641 / CIS 4930
USB Device Basics
Universal Serial Bus (USB) connects between
a computer and peripheral devices
Created to replace various slow buses
(parallel, serial, and keyboard connections)
USB 2.0: up to 480Mb/s (35 MB/s)
USB 3.0: up to 6Gb/s (625 MB/s)
USB Device Basics
A USB device can never start sending data
without first being asked by the host controller
Single-master implementation
Host polls various devices
A device can request a fixed bandwidth (for audio
and video I/O)
Universal Serial Bus is a misnomer…
Actually a tree built out of point-to-point links
Links are four-wire cables (ground, power, and two
signal wires)
USB Device Basics – The Protocol
USB protocol defines a set of standards that
any device can follow
No need to write a driver for a device that is in
a predefined class and follows that standard,
Predefined classes: storage devices,
keyboards, mice, joysticks, network devices,
and modems
No defined standard for video devices and
USB-to-serial devices
A driver is needed for every device
USB Device Basics – Driver Types
Linux supports two types of USB drivers
Drivers on a host system
Control the USB devices that are plugged into it
Drivers on a device (USB gadget drivers)
Control how that single device looks to the host
computer as a USB device
Different
kernel
subsystems
An interface for
USB drivers to
access HW
USB Device Basics
root_hub-hub_port:configuration.interface
USB and Sysfs
For a two-level USB connection, the device
name is in the following format
root_hub-hub_port-hub_port:configuration.interface
Creation
Submitted Transfered
yes to the USB core to the device
can be Notification at
reused? transfer completion
no
Deletion
struct urb
Important fields
/* destination USB device */
/* must be initialized by the USB driver before the urb can be
sent to the USB core */
struct usb_device *dev;
struct usb_iso_packet_descriptor {
unsigned int offset; /* byte into the transfer buffer */
unsigned int length; /* length of the transfer buffer */
if (!dev->bulk_in_endpointAddr &&
(endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
Probe and Disconnect in Detail
/* we found a bulk in endpoint */
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
err("Could not allocate bulk_in_buffer");
goto error;
}
}
if (!dev->bulk_out_endpointAddr &&
!(endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk out endpoint */
Probe and Disconnect in Detail
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
}
if (!(dev->bulk_in_endpointAddr &&
dev->bulk_out_endpointAddr)) {
err("Could not find both bulk-in and bulk-out endpoints");
goto error;
}
Use usb_get_intfdata(interface)
to retrieve dev
Probe and Disconnect in Detail
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &skel_class);
if (retval) {
err(“Not able to get a minor for this device.”);
usb_set_intfdata(interface, NULL);
goto error; Need to call
} usb_register_dev()
return 0; instead of
error: usb_register() for
if (dev) input, tty, video USB
kref_put(&dev->kref, skel_delete); devices that are not
associated with
return retval;
predefined types
}
Call usb_put_dev(),
free bulk_in_buffer
and dev
Probe and Disconnect in Detail
The definition of skel_class
static struct usb_class_driver skel_class = {
.name = "usb/skel%d",
.fops = &skel_fops,
.mode = S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH,
.minor_base = USB_SKEL_MINOR_BASE,
};
The start of the
The definition of skel_fops assigned minor
static struct file_operations skel_fops = { range for this
.owner = THIS_MODULE, driver
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
};
Probe and Disconnect in Detail
The disconnect function
static void skel_disconnect(struct usb_interface *interface) {
struct usb_skel *dev;
int minor = interface->minor;
/* create a urb and its buffer; copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}
Submitting and Controlling an Urb
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL,
&urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
if (copy_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}
exit:
return count;
Submitting and Controlling an Urb
error:
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb);
kfree(buf);
return retval;
}
Probe and Disconnect in Detail
The callback (complete) function
static void skel_write_bulk_callback(struct urb *urb,
struct pt_regs *regs) {
/* in interrupt context */
/* sync/async unlink faults aren't errors */
if (urb->status && !(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}
timeout
in jiffies
Set to 0 to wait until the message to complete
USB Transfers Without Urbs
Exceptions:
Cannot be called from within interrupt context
Cannot be called with a spinlock held
Cannot be cancelled by any other function
The disconnect call needs to wait for
usb_bulk_msg to complete before allowing
itself to be unloaded
USB Transfers Without Urbs
Example
static ssize_t skel_read(struct file *file,
char __user *buffer, size_t count,
loff_t *ppos) {
struct usb_skel *dev;
int retval = 0;