内核源码中提供了一个USB驱动的例子是drivers/usb/usb-skeleton.c,称为USB骨架程序。
一、USB骨架程序的usb_driver结构体定义
-
static struct usb_driver skel_driver = {
-
.name = "skeleton",//驱动名
-
.probe = skel_probe,//探测方法
-
.disconnect = skel_disconnect,//断开连接的方法
-
.suspend = skel_suspend,//挂起方法
-
.resume = skel_resume,//恢复方法
-
.pre_reset = skel_pre_reset,
-
.post_reset = skel_post_reset,//设备重置后调用
-
.id_table = skel_table,//驱动支持的设备ID列表
-
.supports_autosuspend = 1,//支持挂起
-
};
usb_driver的id_table成员指定了驱动支持的USB设备的列表,定义如下:
-
/* 定义这些值以匹配您的设备 */
-
#define USB_SKEL_VENDOR_ID 0xfff0
-
#define USB_SKEL_PRODUCT_ID 0xfff0
-
//驱动支持的设备ID列表
-
static const struct usb_device_id skel_table[] = {
-
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
-
{ } /* Terminating entry */
-
};
-
MODULE_DEVICE_TABLE(usb, skel_table);
二、驱动的加载和卸载方法
1、加载方法,将usb_driver结构注册到USB核心
-
static int __init usb_skel_init(void)
-
{
-
int result;
-
//注册一个USB驱动
-
result = usb_register(&skel_driver);
-
if (result)
-
err("usb_register failed. Error number %d", result);
-
return result;
-
}
2、卸载方法,将usb_driver结构注销
-
static void __exit usb_skel_exit(void)
-
{
-
//注销一个USB驱动
-
usb_deregister(&skel_driver);
-
}
三、USB的探测方法
探测方法,当USB设备插入时,USB核心检测到USB设备的属性和对应的USB驱动匹配时,会调用USB驱动的探测方法
-
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
-
{
-
struct usb_skel *dev;
-
struct usb_host_interface *iface_desc;
-
struct usb_endpoint_descriptor *endpoint;
-
size_t buffer_size;
-
int i;
-
int retval = -ENOMEM;
-
-
//分配私有数据usb_skel空间
-
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-
if (!dev) {
-
err("Out of memory");
-
goto error;
-
}
-
//初始化私有数据结构usb_skel
-
kref_init(&dev->kref);//初始化引用计数器
-
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);//初始化信号
-
mutex_init(&dev->io_mutex);//初始化互斥体
-
spin_lock_init(&dev->err_lock);//初始化错误自旋锁
-
init_usb_anchor(&dev->submitted);
-
init_completion(&dev->bulk_in_completion);//初始化批量输入端点的地址
-
//通过接口得到usb设备结构
-
dev->udev = usb_get_dev(interface_to_usbdev(interface));
-
dev->interface = interface;//初始化设备的接口
-
-
//设置端点信息
-
//仅使用第一个bulk-in和buil-out
-
iface_desc = interface->cur_altsetting;//获得当前激活的设置
-
//扫描接口中的每一个端点
-
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-
endpoint = &iface_desc->endpoint[i].desc;//获得一个端点
-
//比较端点是否为输入端点
-
if (!dev->bulk_in_endpointAddr &&
-
usb_endpoint_is_bulk_in(endpoint)) {
-
//找到一个批量的输入端点
-
buffer_size = le16_to_cpu(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;
-
}
-
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-
if (!dev->bulk_in_urb) {
-
err("Could not allocate bulk_in_urb");
-
goto error;
-
}
-
}
-
//比较端点是否为输出端点
-
if (!dev->bulk_out_endpointAddr &&
-
usb_endpoint_is_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;
-
}
-
-
/*在接口设备中保存数据指针 */
-
usb_set_intfdata(interface, dev);//将usb_skel结构作为接口的私有数据保存
-
-
/* 注册USB设备*/
-
retval = usb_register_dev(interface, &skel_class);
-
if (retval) {
-
/* something prevented us from registering this driver */
-
err("Not able to get a minor for this device.");
-
usb_set_intfdata(interface, NULL);
-
goto error;
-
}
-
-
/* let the user know what node this device is now attached to */
-
dev_info(&interface->dev,
-
"USB Skeleton device now attached to USBSkel-%d",
-
interface->minor);
-
return 0;
-
-
error:
-
if (dev)
-
/* this frees allocated memory */
-
kref_put(&dev->kref, skel_delete);
-
return retval;
-
}
四、私有数据结构
-
struct usb_skel {
-
struct usb_device *udev; /*这个设备的usb设备 */
-
struct usb_interface *interface; /* 这个设备的接口*/
-
struct semaphore limit_sem; /*限制写的数量 */
-
struct usb_anchor submitted; /* 以防我们需要收回我们的提交*/
-
struct urb *bulk_in_urb; /* 用于读取数据的URB*/
-
unsigned char *bulk_in_buffer; /*接收数据的缓冲区*/
-
size_t bulk_in_size; /* 接收缓冲区的大小 */
-
size_t bulk_in_filled; /*缓冲区的字节数*/
-
size_t bulk_in_copied; /* 已经复制到用户空间大小 */
-
__u8 bulk_in_endpointAddr; //批量输入端点的地址
-
__u8 bulk_out_endpointAddr; //批量输出端点的地址
-
int errors; /* the last request tanked */
-
int open_count; //打开USB设备的数量
-
bool ongoing_read; //是否在继续读数据
-
bool processed_urb; //确定是否有未处理的urb
-
spinlock_t err_lock; //错误自旋锁
-
struct kref kref;//引用计数器
-
struct mutex io_mutex; //用于断开连接的同步IO
-
struct completion bulk_in_completion; /* to wait for an ongoing read */
-
};
五、断开连接的方法
当USB设备拔出时,USB核心会调用USB驱动的断开连接方法
-
static void skel_disconnect(struct usb_interface *interface)
-
{
-
struct usb_skel *dev;
-
int minor = interface->minor;//获得次设备号
-
//获得接口的私有数据
-
dev = usb_get_intfdata(interface);
-
usb_set_intfdata(interface, NULL);//设置接口的私有数据位空
-
-
//注销USB设备,释放设备号
-
usb_deregister_dev(interface, &skel_class);
-
-
//阻止更多的IO动作
-
mutex_lock(&dev->io_mutex);
-
dev->interface = NULL;
-
mutex_unlock(&dev->io_mutex);
-
-
usb_kill_anchored_urbs(&dev->submitted);
-
-
//释放设备号
-
kref_put(&dev->kref, skel_delete);
-
-
dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
-
}
六、skel_class结构
注册USB驱动的时候需要传递一个usb_class_driver结构
-
static struct usb_class_driver skel_class = {
-
.name = "skel%d",
-
.fops = &skel_fops,//USB设备文件操作函数集合
-
.minor_base = USB_SKEL_MINOR_BASE,//usb次设备号基址
-
};
-
static const struct file_operations skel_fops = {
-
.owner = THIS_MODULE,
-
.read = skel_read,//读函数
-
.write = skel_write,//写函数
-
.open = skel_open,//打开
-
.release = skel_release,//关闭
-
.flush = skel_flush,//刷新
-
.llseek = noop_llseek,//重定位
-
};
七、打开函数
-
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) {
-
err("%s - error, can't find device for minor %d",
-
__func__, subminor);
-
retval = -ENODEV;
-
goto exit;
-
}
-
//得到接口的私有数据
-
dev = usb_get_intfdata(interface);
-
if (!dev) {
-
retval = -ENODEV;
-
goto exit;
-
}
-
-
//增加引用计数
-
kref_get(&dev->kref);
-
-
/* lock the device to allow correctly handling errors
-
* in resumption */
-
mutex_lock(&dev->io_mutex);
-
//增加打开次数
-
if (!dev->open_count++) {
-
retval = usb_autopm_get_interface(interface);
-
if (retval) {
-
dev->open_count--;
-
mutex_unlock(&dev->io_mutex);
-
kref_put(&dev->kref, skel_delete);
-
goto exit;
-
}
-
} /* else { //uncomment this block if you want exclusive open
-
retval = -EBUSY;
-
dev->open_count--;
-
mutex_unlock(&dev->io_mutex);
-
kref_put(&dev->kref, skel_delete);
-
goto exit;
-
} */
-
/* prevent the device from being autosuspended */
-
-
/* save our object in the file's private structure */
-
file->private_data = dev;//设置文件的私有数据
-
mutex_unlock(&dev->io_mutex);
-
-
exit:
-
return retval;
-
}
八、关闭方法
-
static int skel_release(struct inode *inode, struct file *file)
-
{
-
struct usb_skel *dev;
-
-
dev = file->private_data;//获得私有数据
-
if (dev == NULL)
-
return -ENODEV;
-
-
//减少打开次数
-
mutex_lock(&dev->io_mutex);
-
if (!--dev->open_count && dev->interface)
-
usb_autopm_put_interface(dev->interface);
-
mutex_unlock(&dev->io_mutex);
-
-
//减少引用次数
-
kref_put(&dev->kref, skel_delete);
-
return 0;
-
}
九、写方法
-
static ssize_t skel_write(struct file *file, const char *user_buffer,
-
size_t count, loff_t *ppos)
-
{
-
struct usb_skel *dev;
-
int retval = 0;
-
struct urb *urb = NULL;
-
char *buf = NULL;
-
size_t writesize = min(count, (size_t)MAX_TRANSFER);//计算写入大小
-
-
dev = file->private_data;//获得私有数据
-
-
/* verify that we actually have some data to write */
-
if (count == 0)//写入大小为0时退出
-
goto exit;
-
-
/*
-
* limit the number of URBs in flight to stop a user from using up all
-
* RAM
-
*/
-
//判断文件类型是否为阻塞的
-
if (!(file->f_flags & O_NONBLOCK)) {
-
//获得信号量
-
if (down_interruptible(&dev->limit_sem)) {
-
retval = -ERESTARTSYS;
-
goto exit;
-
}
-
} else {
-
//尝试获得信号量
-
if (down_trylock(&dev->limit_sem)) {
-
retval = -EAGAIN;
-
goto exit;
-
}
-
}
-
-
spin_lock_irq(&dev->err_lock);
-
retval = dev->errors;
-
if (retval < 0) {
-
/* any error is reported once */
-
dev->errors = 0;
-
/* to preserve notifications about reset */
-
retval = (retval == -EPIPE) ? retval : -EIO;
-
}
-
spin_unlock_irq(&dev->err_lock);
-
if (retval < 0)
-
goto error;
-
-
/* 创建一个urb,一个缓冲区,并将数据复制到urb */
-
urb = usb_alloc_urb(0, GFP_KERNEL);
-
if (!urb) {
-
retval = -ENOMEM;
-
goto error;
-
}
-
//分配一个缓冲区
-
buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
-
&urb->transfer_dma);
-
if (!buf) {
-
retval = -ENOMEM;
-
goto error;
-
}
-
//从用户控件复制数据到缓冲区
-
if (copy_from_user(buf, user_buffer, writesize)) {
-
retval = -EFAULT;
-
goto error;
-
}
-
-
/* this lock makes sure we don't submit URBs to gone devices */
-
mutex_lock(&dev->io_mutex);
-
if (!dev->interface) { /* disconnect() was called */
-
mutex_unlock(&dev->io_mutex);
-
retval = -ENODEV;
-
goto error;
-
}
-
-
//批量urb初始化
-
usb_fill_bulk_urb(urb, dev->udev,
-
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
-
buf, writesize, skel_write_bulk_callback, dev);
-
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
usb_anchor_urb(urb, &dev->submitted);
-
-
//提交urb到核心
-
retval = usb_submit_urb(urb, GFP_KERNEL);
-
mutex_unlock(&dev->io_mutex);
-
if (retval) {
-
err("%s - failed submitting write urb, error %d", __func__,
-
retval);
-
goto error_unanchor;
-
}
-
-
//释放urb
-
usb_free_urb(urb);
-
-
return writesize;
-
-
error_unanchor:
-
usb_unanchor_urb(urb);
-
error:
-
if (urb) {
-
usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
-
usb_free_urb(urb);
-
}
-
up(&dev->limit_sem);
-
-
exit:
-
return retval;
-
}
-
-
//写完成回调函数,当URB传输完成后调用
-
static void skel_write_bulk_callback(struct urb *urb)
-
{
-
struct usb_skel *dev;
-
-
dev = urb->context;
-
-
//判断urb状态
-
if (urb->status) {
-
if (!(urb->status == -ENOENT ||
-
urb->status == -ECONNRESET ||
-
urb->status == -ESHUTDOWN))
-
err("%s - nonzero write bulk status received: %d",
-
__func__, urb->status);
-
-
spin_lock(&dev->err_lock);
-
dev->errors = urb->status;
-
spin_unlock(&dev->err_lock);
-
}
-
-
/*释放我们的分配缓冲区*/
-
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
-
urb->transfer_buffer, urb->transfer_dma);
-
up(&dev->limit_sem);
-
}
十、读方法
-
static ssize_t skel_read(struct file *file, char *buffer, size_t count,
-
loff_t *ppos)
-
{
-
struct usb_skel *dev;
-
int rv;
-
bool ongoing_io;
-
-
dev = file->private_data;//获得私有数据
-
-
//判断读取的数量为0,或用于读取的URB未分配
-
if (!dev->bulk_in_urb || !count)
-
return 0;
-
-
//互斥体
-
rv = mutex_lock_interruptible(&dev->io_mutex);
-
if (rv < 0)
-
return rv;
-
//判断接口是否为空
-
if (!dev->interface) { /* disconnect() was called */
-
rv = -ENODEV;
-
goto exit;
-
}
-
-
/* if IO is under way, we must not touch things */
-
retry:
-
spin_lock_irq(&dev->err_lock);
-
ongoing_io = dev->ongoing_read;
-
spin_unlock_irq(&dev->err_lock);
-
//判断是否在进行IO操作
-
if (ongoing_io) {
-
/* 非阻塞IO不等待*/
-
if (file->f_flags & O_NONBLOCK) {
-
rv = -EAGAIN;
-
goto exit;
-
}
-
//如果是阻塞的,阻塞IO
-
rv = wait_for_completion_interruptible(&dev->bulk_in_completion);
-
if (rv < 0)
-
goto exit;
-
/*
-
* by waiting we also semiprocessed the urb
-
* we must finish now
-
*/
-
dev->bulk_in_copied = 0;
-
dev->processed_urb = 1;
-
}
-
//判断是否有未完成的urb
-
if (!dev->processed_urb) {
-
/*
-
* the URB hasn't been processed
-
* do it now
-
*/
-
wait_for_completion(&dev->bulk_in_completion);
-
dev->bulk_in_copied = 0;
-
dev->processed_urb = 1;
-
}
-
-
/* errors must be reported */
-
rv = dev->errors;
-
if (rv < 0) {
-
/* any error is reported once */
-
dev->errors = 0;
-
/* to preserve notifications about reset */
-
rv = (rv == -EPIPE) ? rv : -EIO;
-
/* no data to deliver */
-
dev->bulk_in_filled = 0;
-
/* report it */
-
goto exit;
-
}
-
-
/*
-
* if the buffer is filled we may satisfy the read
-
* else we need to start IO
-
*/
-
//判断缓冲区的字节数
-
if (dev->bulk_in_filled) {
-
//得到需要读取数据的大小
-
size_t available = dev->bulk_in_filled - dev->bulk_in_copied;
-
size_t chunk = min(available, count);
-
-
if (!available) {
-
/*
-
* all data has been used
-
* actual IO needs to be done
-
*/
-
rv = skel_do_read_io(dev, count);
-
if (rv < 0)
-
goto exit;
-
else
-
goto retry;
-
}
-
/*
-
* data is available
-
* chunk tells us how much shall be copied
-
*/
-
-
if (copy_to_user(buffer,
-
dev->bulk_in_buffer + dev->bulk_in_copied,
-
chunk))
-
rv = -EFAULT;
-
else
-
rv = chunk;
-
-
dev->bulk_in_copied += chunk;
-
-
/*
-
* if we are asked for more than we have,
-
* we start IO but don't wait
-
*/
-
if (available < count)
-
skel_do_read_io(dev, count - chunk);
-
} else {
-
/* no data in the buffer */
-
rv = skel_do_read_io(dev, count);
-
if (rv < 0)
-
goto exit;
-
else if (!(file->f_flags & O_NONBLOCK))
-
goto retry;
-
rv = -EAGAIN;
-
}
-
exit:
-
mutex_unlock(&dev->io_mutex);
-
return rv;
-
}
-
//读IO方法
-
static int skel_do_read_io(struct usb_skel *dev, size_t count)
-
{
-
int rv;
-
-
//批量urb初始化
-
usb_fill_bulk_urb(dev->bulk_in_urb,
-
dev->udev,
-
usb_rcvbulkpipe(dev->udev,
-
dev->bulk_in_endpointAddr),
-
dev->bulk_in_buffer,
-
min(dev->bulk_in_size, count),
-
skel_read_bulk_callback,
-
dev);
-
//设置IO操作标志
-
spin_lock_irq(&dev->err_lock);
-
dev->ongoing_read = 1;
-
spin_unlock_irq(&dev->err_lock);
-
-
//提交urb到核心
-
rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
-
if (rv < 0) {
-
err("%s - failed submitting read urb, error %d",
-
__func__, rv);
-
dev->bulk_in_filled = 0;
-
rv = (rv == -ENOMEM) ? rv : -EIO;
-
spin_lock_irq(&dev->err_lock);
-
dev->ongoing_read = 0;
-
spin_unlock_irq(&dev->err_lock);
-
}
-
-
return rv;
-
}
-
//读完成回调方法
-
static void skel_read_bulk_callback(struct urb *urb)
-
{
-
struct usb_skel *dev;
-
-
dev = urb->context;
-
-
spin_lock(&dev->err_lock);
-
//判断URB
-
if (urb->status) {
-
if (!(urb->status == -ENOENT ||
-
urb->status == -ECONNRESET ||
-
urb->status == -ESHUTDOWN))
-
err("%s - nonzero write bulk status received: %d",
-
__func__, urb->status);
-
-
dev->errors = urb->status;
-
} else {
-
dev->bulk_in_filled = urb->actual_length;
-
}
-
dev->ongoing_read = 0;
-
spin_unlock(&dev->err_lock);
-
-
complete(&dev->bulk_in_completion);
-
}
十一、USB驱动的模板
通过对USB骨架驱动的分析,可总结出USB模板
-
//驱动支持的设备ID列表
-
static const struct usb_device_id xxx_table[] = {
-
{ USB_DEVICE(USB_XXX_VENDOR_ID, USB_XXX_PRODUCT_ID) },
-
{ } /* Terminating entry */
-
};
-
MODULE_DEVICE_TABLE(usb, xxx_table);
-
-
//打开方法
-
static int xxx_open(struct inode *inode, struct file *file)
-
{
-
。。。
-
//增加引用计数
-
kref_get(&dev->kref);
-
-
file->private_data = dev;//设置文件的私有数据
-
。。。
-
}
-
//关闭方法
-
static int xxx_release(struct inode *inode, struct file *file)
-
{
-
dev = file->private_data;//获得私有数据
-
if (dev == NULL)
-
return -ENODEV;
-
-
//减少引用次数
-
kref_put(&dev->kref, xxx_delete);
-
。。。
-
}
-
-
//读完成回调方法
-
static void xxx_read_bulk_callback(struct urb *urb)
-
{
-
。。。
-
//判断URB
-
if (urb->status) {
-
。。。
-
}
-
complete(&dev->bulk_in_completion);
-
}
-
-
//读方法
-
static ssize_t skel_read(struct file *file, char *buffer, size_t count,
-
loff_t *ppos)
-
{
-
。。。
-
//批量urb初始化
-
usb_fill_bulk_urb(dev->bulk_in_urb,
-
dev->udev,
-
usb_rcvbulkpipe(dev->udev,
-
dev->bulk_in_endpointAddr),
-
dev->bulk_in_buffer,
-
min(dev->bulk_in_size, count),
-
xxx_read_bulk_callback,
-
dev);
-
//提交urb到核心
-
rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
-
-
copy_to_user(buffer,dev->bulk_in_buffer + dev->bulk_in_copied,chunk);
-
。。。
-
}
-
-
//写完成回调函数,当URB传输完成后调用
-
static void xxx_write_bulk_callback(struct urb *urb)
-
{
-
。。。
-
-
/*释放我们的分配缓冲区*/
-
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
-
urb->transfer_buffer, urb->transfer_dma);
-
。。。
-
}
-
//写方法
-
static ssize_t xxx_write(struct file *file, const char *user_buffer,
-
size_t count, loff_t *ppos)
-
{
-
。。。
-
/* 创建一个urb */
-
urb = usb_alloc_urb(0, GFP_KERNEL);
-
if (!urb) {
-
retval = -ENOMEM;
-
goto error;
-
}
-
//分配一个缓冲区
-
buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
-
&urb->transfer_dma);
-
if (!buf) {
-
retval = -ENOMEM;
-
goto error;
-
}
-
//从用户控件复制数据到缓冲区
-
if (copy_from_user(buf, user_buffer, writesize)) {
-
retval = -EFAULT;
-
goto error;
-
}
-
-
//批量urb初始化
-
usb_fill_bulk_urb(urb, dev->udev,
-
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
-
buf, writesize,xxx_write_bulk_callback, dev);
-
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
usb_anchor_urb(urb, &dev->submitted);
-
-
//提交urb到核心
-
retval = usb_submit_urb(urb, GFP_KERNEL);
-
mutex_unlock(&dev->io_mutex);
-
if (retval) {
-
err("%s - failed submitting write urb, error %d", __func__,
-
retval);
-
goto error_unanchor;
-
}
-
-
//释放urb
-
usb_free_urb(urb);
-
-
。。。
-
}
-
-
static const struct file_operations xxx_fops = {
-
.owner = THIS_MODULE,
-
.read = xxx_read,//读函数
-
.write = xxx_write,//写函数
-
.open = xxx_open,//打开
-
.release = xxx_release,//关闭
-
。。。
-
};
-
-
static struct usb_class_driver xxx_class = {
-
.name = "xxx%d",
-
.fops = &xxx_fops,//USB设备文件操作函数集合
-
.minor_base = USB_XXX_MINOR_BASE,//usb次设备号基址
-
};
-
-
//探测方法,当USB设备插入时,USB核心检测到USB设备的属性和对应的USB驱动匹配时,会调用USB驱动的探测方法
-
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
-
{
-
。。。
-
-
/* 注册USB设备*/
-
retval = usb_register_dev(interface, &xxx_class);
-
if (retval) {
-
/* something prevented us from registering this driver */
-
err("Not able to get a minor for this device.");
-
usb_set_intfdata(interface, NULL);
-
goto error;
-
}
-
。。。
-
}
-
-
//驱动结构体
-
static struct usb_driver xxx_driver = {
-
.name = "xxx",//驱动名
-
.probe = xxx_probe,//探测方法
-
.disconnect = xxx_disconnect,//断开连接的方法
-
.suspend = xxx_suspend,//挂起方法
-
.resume = xxx_resume,//恢复方法
-
.id_table = xxx_table,//驱动支持的设备ID列表
-
。。。
-
};
-
-
//驱动加载函数
-
static int __init usb_xxx_init(void)
-
{
-
int result;
-
-
//注册一个USB驱动
-
result = usb_register(&xxx_driver);
-
if (result)
-
err("usb_register failed. Error number %d", result);
-
-
return result;
-
}
-
-
//驱动卸载函数
-
static void __exit usb_xxx_exit(void)
-
{
-
//注销一个USB驱动
-
usb_deregister(&xxx_driver);
-
}
-
-
module_init(usb_xxx_init);
-
module_exit(usb_xxx_exit);
阅读(2467) | 评论(0) | 转发(0) |