星闪夜空 发表于 2012-11-28 20:58

有关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

本帖最后由 done_and_todo 于 2012-12-04 23:12 编辑

你这个程序应该还不能实现U盘功能吧,你说的问题我也不是很清楚,你可以去看一下叫“linux那些事之我是U盘“

星闪夜空 发表于 2012-12-16 10:37

回复 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

本帖最后由 done_and_todo 于 2012-12-18 22:44 编辑

回复 3# 星闪夜空


    你在插入U盘前,应该将系统的原驱动先卸载了。还有那个信息可能不打在终端上,你可以用dmesg | tail -10看下。

星闪夜空 发表于 2012-12-20 14:42

回复 4# done_and_todo

    嗯, 我在加载驱动程序的时候并没有将原U盘驱动卸载,可能问题是出在这里吧,我再去实验一下,谢谢你的帮助!!!


   

javon123456 发表于 2013-03-28 14:29

应该是先插入U盘,卸载掉usb-storage驱动再insmod自己的驱动

星闪夜空 发表于 2013-06-15 20:26

问题终于解决了,确实是没有将之前的USB Mass Storage 驱动卸载的原因。
页: [1]
查看完整版本: 有关Linux USB驱动之U盘问题