有关Linux USB驱动之U盘问题
前提:可以确定USB驱动程序已经成功注册。将USB驱动程序编译成模块加载进Linux系统中,然后将U盘插入Linux系统中,结果并没有打印出skel_probe()函数中调试信息,
驱动程序如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h> /*kmalloc*/
#include <linux/kref.h> /*kref*/
#include <linux/usb.h>
#include <asm/uaccess.h> /*copy_to_user()*/
#include <linux/smp_lock.h>/*lock_kernel()*/
#define USB_SKEL_VENDOR_ID0x058f//定义制造商ID
#define USB_SKEL_PRODUCT_ID 0x6387//定义产品ID
//该驱动程序支持的设备列表
static struct usb_device_id skel_table[]={
/*根据制造商ID、产品ID生成usb_device_id结构体实例*/
{USB_DEVICE(USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE(usb,skel_table);//导出到用户空间
#define USB_SKEL_MINOR_BASE 192//定义次设备号
struct usb_skel{
struct usb_device *udev;
struct usb_interface *interface; //设备的接口
unsigned char *bulk_in_buffer; //接收数据的缓冲区
size_t bulk_in_size; //缓冲区的大小
__u8bulk_in_endpointAddr; //输入端点
__u8bulk_out_endpointAddr; //输出端点
struct krefkref; //urb引用计数
};
#define to_skel_dev(d) container_of(d,struct usb_skel,kref)
static struct usb_driver skel_driver; //定义USB设备驱动
static void skel_delete(struct kref *kref)
{
struct usb_skel *dev=to_skel_dev(kref);
usb_put_dev(dev->udev); //减小usb_device的引用计数
kfree(dev->bulk_in_buffer); //释放数据的缓冲区
kfree(dev);
}
static int skel_open(struct inode *inode,struct file *file)
{
struct usb_skel *dev;
struct usb_interface *interface;
int subminor; //定义设备文件的次设备号
subminor=iminor(inode);//得到次设备号
//遍历USB驱动,找到与subminor相匹配的设备驱动
interface=usb_find_interface(&skel_driver,subminor);
if(!interface)
{
err("%s-error,can't find device for minor %d",__FUNCTION__,subminor);
return -ENODEV;
}
dev=usb_get_intfdata(interface);//获取数据
if(!dev)
return -ENODEV;
kref_get(&dev->kref); //将refcount加1
file->private_data=dev;//将dev保存在private_data中
return 0;
}
static int skel_release(struct inode *inode,struct file *file)
{
struct usb_skel *dev;
dev=(struct usb_skel *)file->private_data;//得到usb_skel
if(dev==NULL)
return -ENODEV;
kref_put(&dev->kref,skel_delete);
return 0;
}
static ssize_t skel_read(struct file *file,char __user *buffer,size_t count,loff_t *ppos)
{
struct usb_skel *dev;
int retval=0;
dev=(struct usb_skel *)file->private_data;//得到usb_skel
/*进行阻塞的批量读以从设备获取数据*/
//usb_rcvbulkpipe:把指定USB设备的指定端点号设置为一个批量IN端点
retval=usb_bulk_msg(dev->udev,usb_rcvbulkpipe(dev->udev,dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,min(dev->bulk_in_size,count),&count,HZ*10);
if(!retval)
{
//如果读成功,复制数据到用户空间
if(copy_to_user(buffer,dev->bulk_in_buffer,count))
retval=-EFAULT;
else
retval=count;
}
return retval;
}
static void skel_write_bulk_callback(struct urb *urb,struct pt_regs *regs)
{
if(urb->status && !(urb->status==-ENOENT||urb->status==-ECONNRESET||urb->status==-ESHUTDOWN))
/*未能正确的传输*/
dbg("%s-nonzero write bulk status received: %d\n",__FUNCTION__,urb->status);
usb_buffer_free(urb->dev,urb->transfer_buffer_length,urb->transfer_buffer,urb->transfer_dma);
}
static ssize_t skel_write(struct file *file,const char __user *user_buffer,size_t count,loff_t *ppos)
{
struct usb_skel *dev;
int retval=0;
struct urb *urb=NULL;
char *buf=NULL;
dev=(struct usb_skel *)file->private_data;
if(count==0)
return count;
/*创建URB结构体*/
//0:表示不创建等时数据包
urb=usb_alloc_urb(0,GFP_KERNEL);
if(!urb)
{
return -ENOMEM;
}
buf=usb_buffer_alloc(dev->udev,count,GFP_KERNEL,&urb->transfer_dma);/*申请内存空间*/
if(!buf)
{
retval=-ENOMEM;
goto fail_buffer_alloc;
}
if(copy_from_user(buf,user_buffer,count))
{
retval=-EFAULT;
goto fail_copy;
}
/*正确地初始化urb*/
usb_fill_bulk_urb(urb,dev->udev,usb_sndbulkpipe(dev->udev,dev->bulk_out_endpointAddr),
buf,count,skel_write_bulk_callback,dev);
urb->transfer_flags |=URB_NO_TRANSFER_DMA_MAP; //即将传输DMA缓冲区
retval=usb_submit_urb(urb,GFP_KERNEL); //提交给USB核心
if(retval)
{
err("%s-failed submitting write urb,error %d",__FUNCTION__,retval);
goto fail_copy;
}
usb_free_urb(urb);
return count;
fail_copy:
usb_buffer_free(dev->udev,count,buf,urb->transfer_dma);//释放内存
kfree(buf);
fail_buffer_alloc:
usb_free_urb(urb);//释放分配的结构体
return retval;
}
static struct file_operations skel_fops={
.owner = THIS_MODULE,
.open = skel_open,
.release = skel_release,
.read = skel_read,
.write = skel_write,
};
static struct usb_class_driver skel_class={
.name = "usb/skel%d", //sysfs中用来描述设备名
.fops = &skel_fops, //文件操作结构体指针
.mode = S_IRUSR | S_IWUSR, //只提供了设备文件属主的读和写访问权限
.minor_base = USB_SKEL_MINOR_BASE, //开始次设备号
};
static int skel_probe(struct usb_interface *interface,const struct usb_device_id *id)
{
struct usb_skel *dev=NULL; //定义usb_skel
struct usb_host_interface *iface_desc; //表示设置
struct usb_endpoint_descriptor *endpoint; //表示端点描述
size_t buffer_size; //定义最大信息包的大小
int i;
int retval=-ENOMEM;
dev=kmalloc(sizeof(struct usb_skel),GFP_KERNEL); /*分配内存空间*/
if(dev==NULL)
{
err("Out of memory\n");
return -ENOMEM;
}
memset(dev,0x00,sizeof(*dev));//将分配的内存空间清0
/*初始化usb_skel结构体*/
kref_init(&dev->kref); //初始化refcount为1
/*
*interface_to_usbdev:转换为usb_device结构体
*usb_get_dev:增加usb_device的引用计数
*/
dev->udev=usb_get_dev(interface_to_usbdev(interface));
dev->interface=interface;
/*设置端点信息*/
iface_desc=interface->cur_altsetting;//初始化该接口的当前活动设置
for(i=0;i<iface_desc->desc.bNumEndpoints;++i)
{
endpoint=&iface_desc->endpoint.desc; //初始化端点描述
if(!dev->bulk_in_endpointAddr&&(endpoint->bEndpointAddress&USB_DIR_IN)&&
((endpoint->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_BULK))
{
/*得到正确的端点类型*/
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:\n");
goto error;
}
}
if(!dev->bulk_out_endpointAddr&&(endpoint->bEndpointAddress&USB_DIR_OUT)&&
((endpoint->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_BULK))
{
//初始化输出端口
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:\n");
goto error;
}
usb_set_intfdata(interface,dev); /*把数据指针保存到这个接口设备中*/
/*现在可以注册设备*/
retval=usb_register_dev(interface,&skel_class);
if(retval)
{
err("Not able to get a minor for this device.\n");
usb_set_intfdata(interface,NULL);
goto error;
}
printk(KERN_DEBUG"USB Skeleton device now attached to USB Skel-%d\n",interface->minor);
return 0;
error:
if(dev)
//skel_delete:函数指针,指向一个清理函数,不能为空
kref_put(&dev->kref,skel_delete);//将refcount减1
return retval;
}
static void skel_disconnect(struct usb_interface *interface)
{
struct usb_skel *dev;
int minor=interface->minor;//得到次设备号
lock_kernel();//内核锁,相当于P操作
dev=usb_get_intfdata(interface);//访问dev
usb_set_intfdata(interface,NULL); //设置数据指针为NULL
unlock_kernel();//相当于V操作
kref_put(&dev->kref,skel_delete);
info("USB Skeleton #%d now disconnected",minor);
}
static struct usb_driver skel_driver={
.name = "skeleton",
.id_table= skel_table,
.probe = skel_probe,
.disconnect= skel_disconnect,
};
//模块加载函数
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;
}
//模块卸载函数
static void __exit usb_skel_exit(void)
{
/*把该驱动程序从USB子系统注销*/
usb_deregister(&skel_driver);
}
module_init(usb_skel_init);
module_exit(usb_skel_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("chenqi");
不知道问题出在哪里,希望好心人能帮助我解决这个问题,在此谢谢了!!!
本帖最后由 done_and_todo 于 2012-12-04 23:12 编辑
你这个程序应该还不能实现U盘功能吧,你说的问题我也不是很清楚,你可以去看一下叫“linux那些事之我是U盘“ 回复 2# done_and_todo
首先感谢你的帮助,嗯,你说的是对的,这个确实没有实现U盘的功能,我只是把USB的骨架程序修改一下,添加了我的U盘的制造商ID和产品ID,我自己的想法是:当系统插入一个与ID匹配的USB设备到USB总线时,驱动会在USB core中注册。驱动程序中的probe函数也就会被调用,那么应该会打印出我在probe函数中的
printk(KERN_DEBUG"USB Skeleton device now attached to USB Skel-%d\n",interface->minor);这条语句。
但是我实验的结果却没有打印出这条语句,所以我不知道自己的问题出在哪里了???
本帖最后由 done_and_todo 于 2012-12-18 22:44 编辑
回复 3# 星闪夜空
你在插入U盘前,应该将系统的原驱动先卸载了。还有那个信息可能不打在终端上,你可以用dmesg | tail -10看下。 回复 4# done_and_todo
嗯, 我在加载驱动程序的时候并没有将原U盘驱动卸载,可能问题是出在这里吧,我再去实验一下,谢谢你的帮助!!!
应该是先插入U盘,卸载掉usb-storage驱动再insmod自己的驱动 问题终于解决了,确实是没有将之前的USB Mass Storage 驱动卸载的原因。
页:
[1]