drivers/usb/中的文件usb-skeleton.c,usb-skeleton是usb驱动的框架,可以通过修改一下部分代码就可一轻松的实现一个简单的设备驱驱动
/*
* USB Skeleton driver - 2.2
*
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
* but has been rewritten to be easier to read and use.
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
/*内核所用到的头文件都保存在include/目录下。为了方便使用和兼容性,Linus在编制内核程序头文件时所使用的命名方式与标准C库头文件的命名方式相似,在一个Linux系统中,它们与标准库的头文件并存。通常的做法是将这些头文件放置在标准库头文件目录中的子目录下,以让需要用到内核数据结构或常数的程序使用。在Linux系统中,asm/、linux/和sys/三个子目录下的内核头文件通常需要复制到标准C库头文件所在的目录(/usr/include)中,而其他一些文件若与标准库的头文件没有冲突则可以直接放到标准库头文件目录下,或者改放到这里的三个子目录中*/
/* Define these values to match your devices */
//设备的厂商ID
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0
/* table of devices that work with this driver */
//使用本驱动的设备列表
static const struct usb_device_id skel_table[] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
/* USB_DEVICE 宏利用厂商ID 和设备ID 提供了设备的唯一标识。当系统插入一个与ID匹配的USB设备到USB总线时,驱动会在USB core 中注册。, */
{ } /* Terminating entry */
};
//描述特定驱动支持的设备
MODULE_DEVICE_TABLE(usb, skel_table);
/* MODULE_DEVICE_TABLE的第一个参数是设备的类型,如果是USB设备,那自然是usb(如果是PCI设备,那将是pci,这两个子系统用同一个宏来注册所支持的设备。这涉及PCI设备的驱动了,在此先不深究)。后面一个参数是设备表,这个设备表的最后一个元素是空的,用于标识结束。代码定义了USB_SKEL_VENDOR_ID是0xfff0,USB_SKEL_PRODUCT_ID是0xfff0,也就是说,当有一个设备接到集线器时,usb子系统就会检查这个设备的vendor ID和product ID,如果它们的值是0xfff0时,那么子系统就会调用这个skeleton模块作为设备的驱动。*/
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
/* our private defines. if this grows any larger, use your own .h file */
#define MAX_TRANSFER (PAGE_SIZE - 512)
/* MAX_TRANSFER is chosen so that the VM is not stressed by
allocations > PAGE_SIZE and the number of packets in a page
is an integer 512 is the largest possible packet on EHCI */
#define WRITES_IN_FLIGHT 8
/* arbitrarily chosen */
/* Structure to hold all of our device specific stuff */
//定义了设备的数据结构,后面会对该数据结构进行初始化以及赋值调用。
//sub_skel 结构存储的信息是本驱动所拥有的所有资源及状态
struct usb_skel {
struct usb_device *udev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
struct usb_anchor submitted; /* in case we need to retract our submissions */
struct urb *bulk_in_urb; /* the urb to read data with */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
size_t bulk_in_filled; /* number of bytes in the buffer */
size_t bulk_in_copied; /* already copied to user space */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
int errors; /* the last request tanked */
bool ongoing_read; /* a read is going on */
spinlock_t err_lock; /* lock for errors */
struct kref kref;
struct mutex io_mutex; /* synchronize I/O with disconnect */
wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
static struct usb_driver skel_driver;
static void skel_draw_down(struct usb_skel *dev);
static void skel_delete(struct kref *kref)
{
struct usb_skel *dev = to_skel_dev(kref);
usb_free_urb(dev->bulk_in_urb);
usb_put_dev(dev->udev);
kfree(dev->bulk_in_buffer);
kfree(dev);
}
/*由于只是一个象征性的骨架程序,open()成员函数的实现非常简单,它根据usb_driver和次设备号通过 usb_find_interface()获得USB接口,之后通过usb_get_intfdata()获得接口的私有数据并赋予file-> private_data*/
static int skel_open(struct inode *inode, struct file *file)
{
struct usb_skel *dev;
struct usb_interface *interface;
int subminor;
int retval = 0;
//得到次设备号
subminor = iminor(inode);
//通过次设备号寻找接口
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
pr_err("%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV;
goto exit;
}
//得到,则用usb_get_intfdata保存的设备
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
}
retval = usb_autopm_get_interface(interface);
if (retval)
goto exit;
/* increment our usage count for the device */
//增加引用计数
kref_get(&dev->kref);
/* save our object in the file's private structure */
//保存设备到文件私有数据
file->private_data = dev;
exit:
return retval;
}
/*由于在open()函数中并没有申请任何软件和硬件资源,因此与open()函数对应的release()函数不用进行资源的释放,它会减少在open()中增加的引用计数*/
static int skel_release(struct inode *inode, struct file *file)
{
struct usb_skel *dev;
dev = file->private_data;
if (dev == NULL)
return -ENODEV;
/* allow the device to be autosuspended */
//允许设备自动挂起
mutex_lock(&dev->io_mutex);
if (dev->interface)
usb_autopm_put_interface(dev->interface);
mutex_unlock(&dev->io_mutex);
/* decrement the count on our device */
//减少引用计数
kref_put(&dev->kref, skel_delete);
return 0;
}
static int skel_flush(struct file *file, fl_owner_t id)
{
struct usb_skel *dev;
int res;
//从私有数据中获得设备信息
dev = file->private_data;
if (dev == NULL)
return -ENODEV;
/* wait for io to stop */
mutex_lock(&dev->io_mutex);
skel_draw_down(dev);
/* read out errors, leave subsequent opens a clean slate */
spin_lock_irq(&dev->err_lock);
res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0;
dev->errors = 0;
spin_unlock_irq(&dev->err_lock);
mutex_unlock(&dev->io_mutex);
return res;
}
static void skel_read_bulk_callback(struct urb *urb)
{
struct usb_skel *dev;
dev = urb->context;
spin_lock(&dev->err_lock);
/* sync/async unlink faults aren't errors */
if (urb->status) {
if (!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
dev_err(&dev->interface->dev,
"%s - nonzero write bulk status received: %d\n",
__func__, urb->status);
dev->errors = urb->status;
} else {
dev->bulk_in_filled = urb->actual_length;
}
dev->ongoing_read = 0;
spin_unlock(&dev->err_lock);
wake_up_interruptible(&dev->bulk_in_wait);
}
static int skel_do_read_io(struct usb_skel *dev, size_t count)
{
int rv;
/* p