usb驱动程序设计

    xiaoxiao2021-12-14  35

    驱动程序设计

    使用Linux命令mknod建立一个设备文件。比如输入mknod  /dev/my_disk b  42  0命令,说明要建立一个块设备文件,名字是my_disk,主设备号是42,次设备号是0。

    看看你是否成功的建立了这个文件。

     输入命令ls   -l   /dev/my_disk

    从我这里copy两个文件radimo.c和radimo.h

    不妨放在/root目录下

    •   编译这个程序:

    •   gcc  -c  -I/usr/src/linux-2.4.20-8/include       radimo.c

    •   编译生成一个模块radimo.o,就是我们的驱动程序。

    •   加载这个模块:insmod   radimo.o

    •    刚才我们已经创建了一个设备文件/dev/my_disk,在驱动程序没有加载之前,这个设备文件是无效的。加载驱动程序后,这个设备才有效。这是一个用内存虚拟的磁盘,容量2M。

    •   格式化这个磁盘,使用ext2格式:

    mke2fs   /dev/my_disk

    •   在系统中挂接这个磁盘:

    mount    /dev/my_disk    /mnt

    •   查看系统中已经挂接的磁盘:

    输入命令df,至少可以看到两个磁盘,一个是硬盘,一个是刚才挂接的虚拟磁盘。

    •   玩够了,就输入umount  /dev/my_disk卸载这个虚拟磁盘。

    •   最后输入rmmod   radimo卸载这个驱动程序。

    •   我们来一起分析radimo.c这个程序,看看驱动程序的工作原理。

    •   主要包含以下几个函数:

    – radimo_request

    – radimo_open

    – radimo_ioctl

    – radimo_release

    – init_module

    – cleanup_module

    – 

    init_module的流程

    •   函数的调用时机:模块加载时由内核调用。

    1.申请内存,注意要用内核函数vmalloc,而不是C库函数malloc

    2.向系统注册块设备,用内核函数register_blkdev(设备号,设备名,函数表)

    3.设定设备的读写函数,用内核函数blk_queue_make_request(设备号,读写函数)

    4.初始化其他要用的全局变量。

    5.在这个程序里面调用MSG宏相当于printk

    radimo_open的流程

    •      函数的调用时机:当系统准备使用你所负责的设备时,由内核调用。

    •      所做的唯一的事情:用MOD_INC_USE_COUNT增加引用计数,也就是说,从这个时候开始,驱动程序不能被随便卸载。

    •      还有一些关于定时器的语句,本程序中忽略。

    radimo_ioctl的流程

    •         用户程序在使用设备之前,会查询设备的属性,比如磁盘大小、速度等等。

    •      这些属性由radimo_ioctl函数提供。

    •      参数cmd表示要查询设备的哪个属性。我们只关心BLKGETSIZE,就是磁盘的大小。

    •      用put_user函数把一个数字写到用户地址空间。

    radimo_request的流程

    •         将在系统需要读写设备的时候被调用。

    •      1.计算要读写的地址。sbh->b_rsector表示要读写的扇区号,radimo_hard表示每个扇区的字节数。那么两者相乘就可以得到要读写的地址(以字节计算)。

    •   2.判断访问是否越界?越界的访问是不合法的

     

    •         3.判断是读还是写?

    –     如果是读,就把数据从驱动程序的缓冲区中搬到操作系统的缓冲区中。

    –     如果是写,就把数据从系统缓冲区中搬到驱动程序的缓冲区中。

    其他函数的流程

    •         radimo_release函数:

    –     在关闭设备的时候被调用

    –     减少引用计数,允许卸载本模块。

    •      cleanup_module函数:

    –     在模块卸载的时候被调用。

    做一些清理现场的工作

    你需要做的工作?

    •       仔细阅读radimo驱动程序的源代码。

    •      不懂的地方,可以参考我编写的实验教案。

    •      把这个程序修改成一个U盘的驱动程序。

    /*

     * My UDisk driver - 0.1

     *

     * TODO:

     *     -fix urb->status race condition in write sequence

     *     - moveminor_table to a dynamic list.

     *

     * History:

     *

     * 2008_01_9 - 0.1 - zero out dev in probefunction for devices that do

     *

     */

    #define__KERNEL__

    #define MODULE

    #include<linux/config.h>

    #include<linux/kernel.h>

    #include<linux/sched.h>

    #include <linux/signal.h>

    #include<linux/errno.h>

    #include<linux/poll.h>

    #include<linux/init.h>

    #include<linux/slab.h>

    #include<linux/fcntl.h>

    #include<linux/module.h>

    #include<linux/spinlock.h>

    #include<linux/list.h>

    #include<linux/smp_lock.h>

    #include <linux/devfs_fs_kernel.h>

    #include<linux/usb.h>

    #define MAJOR_NR            42          //定义主设备号

    #defineDEVICE_NAME              "myudisk"            // 定义设备名

    #defineDEVICE_NR(device)      (MINOR(device))       

    #defineDEVICE_ON(device)

    #defineDEVICE_OFF(device)

    #defineDEVICE_NO_RANDOM

    #include <linux/blk.h>

    #defineMYUDISK_SECTOR_BITS      9     /* 2**9 byte hardware sector */

    #defineMYUDISK_BLOCK_SIZE 1024      /* block size */    //定义了一个块的大小,以字节为单位

    #defineMYUDISK_TOTAL_SIZE 2048      /* size in blocks */     //定义了这个虚拟盘的容量,以块为单位

     

    /* the storagepool */

    //static char*myudisk_storage;              //这个指针是全局变量,指向用于虚拟盘的内存

     

    //static intmyudisk_sectorsize = 1 << MYUDISK_SECTOR_BITS;

    //static intmyudisk_blocksize = MYUDISK_BLOCK_SIZE;

    static intmyudisk_size ;

    static intmyudisk_readahead = 4;

    #defineCONFIG_USB_DEBUG

     

    #ifdefCONFIG_USB_DEBUG

      static int debug = 1;

    #else

      static int debug;

    #endif

     

    /* Use our owndbg macro */

    #undef dbg

    #definedbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ "(%s):" format "\n" , __FUNCTION__, ## arg); } while (0)

     

    /* VersionInformation */

    #defineDRIVER_VERSION "v0.1"

    #defineDRIVER_AUTHOR "Wen Yan Jun, yjwen@nudt.edu.cn"

    #defineDRIVER_DESC "My UDisk Driver"

     

    /* Moduleparamaters */

    MODULE_PARM(debug,"i");

    MODULE_PARM_DESC(debug,"Debug enabled or not");

     

    /* Define thesevalues to match your device */

    #defineMY_UDISK_VENDOR_ID      0x058f

    #defineMY_UDISK_PRODUCT_ID    0x6387

     

    /* table ofdevices that work with this driver */

    static structusb_device_id myudisk_table [] = {

      { USB_DEVICE(MY_UDISK_VENDOR_ID,MY_UDISK_PRODUCT_ID) },

      { }                                /*Terminating entry */

    };

     

    MODULE_DEVICE_TABLE(usb, myudisk_table);

     

    /* Get a minorrange for your devices from the usb maintainer */

    #defineMY_UDISK_MINOR_BASE   192

     

    /* we can have upto this number of device plugged in at once */

    #defineMAX_DEVICES              16

     

     

    /* Structure tohold all of our device specific stuff */

    struct my_udisk {

      struct usb_device *    udev;                   /*save off the usb device pointer */

      struct usb_interface *       interface;            /*the interface for this device */

      devfs_handle_t          devfs;                   /* devfs device node */

      unsigned char            minor;                 /* the starting minor numberfor this device */

      unsigned char            num_ports;          /* the number of ports this device has*/

      char                     num_interrupt_in;     /* number of interrupt in endpoints we have*/

      char                     num_bulk_in;             /* number of bulk in endpoints wehave */

      char                     num_bulk_out;           /* number of bulk out endpoints wehave */

     

      unsigned char *         bulk_in_buffer;          /*the buffer to receive data */

      int                 bulk_in_size;              /* the size of the receive buffer*/

      __u8                    bulk_in_endpointAddr;     /* the address of the bulk in endpoint */

     

      unsigned char *         bulk_out_buffer; /* thebuffer to send data */

      int                 bulk_out_size;            /* the size of the send buffer */

      struct urb *         write_urb;           /* the urb used to send data */

      __u8                    bulk_out_endpointAddr;   /* the address of the bulk out endpoint */

     

      struct tq_struct   tqueue;                /*task queue for line discipline waking up */

      int                 open_count;        /* number of times this port has beenopened */

      struct semaphore       sem;                    /*locks this structure */

    };

     

     

    /* the global usbdevfs handle */

    externdevfs_handle_t usb_devfs_handle;

    //

     

    #defineMAX_COMMAND_SIZE    16

    #defineMU_BULK_BUFFER_LEN      4096      /* if the blocksize is larger than thebuffer len, data transform will fail. */

     

    /* transportreturn codes */

    #defineMYUDISK_TRANSPORT_GOOD    0   /*Transport good, command good    */

    #defineMYUDISK_TRANSPORT_FAILED  1   /* Transport good, command failed   */

    #defineMYUDISK_TRANSPORT_ERROR   2   /* Transport bad (i.e. device dead) */

    #defineMYUDISK_TRANSPORT_ABORTED 3   /*Transport aborted                */

     

    #defineSCSI_DATA_UNKNOWN       0

    #defineSCSI_DATA_WRITE         1

    #defineSCSI_DATA_READ          2

    #defineSCSI_DATA_NONE          3

     

    static inlinevoid myudisk_debug_data (const char *function, int size, const unsigned char*data)

    {

      int i;

     

      if (!debug)

             return;

     

      printk (KERN_DEBUG __FILE__" [%s]: length= %d, data = << ",

             function, size);

      for (i = 0; i < size; ++i) {

             printk ("%.2x ", data[i]);

      }

      //printk (">>\n");

    }

     

    structcmnd_struct {   

      unsigned char           cmnd[MAX_COMMAND_SIZE];

      unsigned char           cmd_len;            

      unsigned char           sc_data_direction;     /* direction of data transfer */

      unsigned           data_payload_size;    /* data payload size */

      unsigned           data_payload_actualSize;/*data payload size actually xfered */

      __u32                  tag;               /* used for cbw */

    };

     

    #defineMYUDISK_TIMEOUT    HZ*10

    #defineMYUDISK_STRING_LEN      32

     

    #defineSUCCESS               0x2002

    #defineFAILED                 0x2003

     

    /* command blockwrapper */

    structbulk_cb_wrap {

      __u32    Signature;            /* contains 'USBC' */

      __u32    Tag;                     /* unique per command id */

      __u32    DataTransferLength;  /* size of data */

      __u8      Flags;                   /* direction in bit 0 */

      __u8      Lun;                     /* LUN normally 0 */

      __u8      Length;                /* of of the CDB */

      __u8      CDB[16];              /* max command */

    };

     

    #defineMU_BULK_CB_WRAP_LEN  31

    #defineMU_BULK_CB_SIGN            0x43425355 /*spells out USBC */

    #defineMU_BULK_FLAG_IN             1

    #defineMU_BULK_FLAG_OUT  0

     

    /* bulk-onlyclass specific requests */

    #defineMU_BULK_RESET_REQUEST      0xff

    #defineMU_BULK_GET_MAX_LUN 0xfe

     

    /* command statuswrapper */

    structbulk_cs_wrap {

      __u32    Signature;            /* should = 'USBS' */

      __u32    Tag;                     /* same as original command*/

      __u32    Residue;              /* amount not transferred */

      __u8      Status;                 /* see below */

      __u8      Filler[18];

    };

     

    #defineMU_BULK_CS_WRAP_LEN  13

    #defineMU_BULK_CS_SIGN             0x53425355 /* spells out 'USBS' */

    /* This is forOlympus Camedia digital cameras */

    #defineMU_BULK_CS_OLYMPUS_SIGN  0x55425355 /* spells out 'USBU' */

    #defineMU_BULK_STAT_OK            0

    #defineMU_BULK_STAT_FAIL   1

    #defineMU_BULK_STAT_PHASE      2

     

    /* bulk-onlyclass specific requests */

    #defineMU_BULK_RESET_REQUEST      0xff

    #defineMU_BULK_GET_MAX_LUN 0xfe

     

     

     

     

    __u32myudisk_soft ,SECTOR_num,BLOCK_num;

    unsigned longPARTION_offset;

     

    static intmyudisk_hard = 1 << MYUDISK_SECTOR_BITS;

    /***********************************************************************

     * USB mass storage device related functions

     ***********************************************************************/

     

    /

     

    /* local functionprototypes */

    static intmyudisk_ioctl              (struct inode*inode, struct file *file, unsigned int cmd, unsigned long arg);

    static intmyudisk_open             (struct inode*inode, struct file *file);

    static intmyudisk_release         (struct inode*inode, struct file *file);

     

    static void *myudisk_probe      (struct usb_device*dev, unsigned int ifnum, const struct usb_device_id *id);

    static voidmyudisk_disconnect (struct usb_device*dev, void *ptr);

     

    static voidmyudisk_write_bulk_callback       (structurb *urb);

     

    extern intmyudisk_Bulk_transport(struct usb_device *udev, struct usb_interface*interface,

                                      structcmnd_struct *cs,

                                      unsigned char*bulk_buffer, int bulk_size,

                                      __u8bulk_in_endpointAddr, __u8 bulk_out_endpointAddr);

     

    unsigned intmyudisk_transfer_length(struct cmnd_struct *ud);

    intmyudisk_Bulk_reset(struct usb_device *udev, struct usb_interface *interface,

                           __u8bulk_in_endpointAddr, __u8 bulk_out_endpointAddr);

    /* array ofpointers to our devices that are currently connected */

    static structmy_udisk         *minor_table[MAX_DEVICES];

     

    /* lock toprotect the minor_table structure */

    staticDECLARE_MUTEX (minor_table_mutex);

     

    /*

     * File operations needed when we register thisdriver.

     * This assumes that this driver NEEDS fileoperations,

     * of course, which means that the driver isexpected

     * to have a node in the /dev directory. If theUSB

     * device were for a network interface then thedriver

     * would use "struct net_driver"instead, and a serial

     * device would use "structtty_driver".

     */

    static struct block_device_operationsmyudisk_fops = {

      ioctl:             myudisk_ioctl,

      open:            myudisk_open,

      release: myudisk_release,

    };     

     

    /* usb specificobject needed to register this driver with the usb subsystem */

    static structusb_driver myudisk_driver = {

      name:           "myudisk",

      probe:           myudisk_probe,

      disconnect:   myudisk_disconnect,

      fops:             NULL,

      minor:          MY_UDISK_MINOR_BASE,

      id_table:       myudisk_table,

    };

     

     

     

    /**

     *     my_udisk_debug_data

     */

    static inlinevoid my_udisk_debug_data (const char *function, int size, const unsigned char*data)

    {

      int i;

     

      if (!debug)

             return;

     

      printk (KERN_DEBUG __FILE__": %s - length= %d, data = ",

             function, size);

      for (i = 0; i < size; ++i) {

             printk ("%.2x ", data[i]);

      }

      //printk ("\n");

    }

     

     

    /**

     *     myudisk_delete

     */

    static inlinevoid myudisk_delete (struct my_udisk *dev)

    {

      minor_table[dev->minor] = NULL;

      if (dev->bulk_in_buffer != NULL)

             kfree (dev->bulk_in_buffer);

      if (dev->bulk_out_buffer != NULL)

             kfree (dev->bulk_out_buffer);

      if (dev->write_urb != NULL)

             usb_free_urb (dev->write_urb);

      kfree (dev);

    }

     

     

    /**

     *     myudisk_open

     */

    static intmyudisk_open (struct inode *inode, struct file *file)

    {

      struct my_udisk *dev = NULL;

      int subminor;

      int retval = 0;

     

      dbg("myudisk_open()");

     

      subminor = MINOR (inode->i_rdev);           //- MY_UDISK_MINOR_BASE;

      if ((subminor < 0) ||

         (subminor >= MAX_DEVICES)) {

             return -ENODEV;

      }

     

      //MOD_INC_USE_COUNT;

     

      /* lock our minor table and get our local datafor this minor */

      down (&minor_table_mutex);

      dev = minor_table[subminor];

     

      dbg("minor: %d, dev:%p", subminor,dev);

     

      if (dev == NULL) {

             up (&minor_table_mutex);

    //             MOD_DEC_USE_COUNT;

             return -ENODEV;

      }

     

      /* lock this device */

      down (&dev->sem);

     

      /* unlock the minor table */

      up (&minor_table_mutex);

     

      /* increment our usage count for the driver */

      //++dev->open_count;

     

      /* save our object in the file's privatestructure */

      file->private_data = dev;

      dbg("file: %p, dev:%p", file, dev);

     

      /* unlock this device */

      up (&dev->sem);

      dbg("The dev is not NULL\n");

     

      return retval;

    }

     

     

    /**

     *     myudisk_release

     */

    static intmyudisk_release (struct inode *inode, struct file *file)

    {

      struct my_udisk *dev;

      int subminor;

      int retval = 0;

     

      dbg("inode: %p, file: %p", inode,file);

     

      subminor = MINOR (inode->i_rdev);           //- MY_UDISK_MINOR_BASE;

      if ((subminor < 0) ||

         (subminor >= MAX_DEVICES)) {

             return -ENODEV;

      }

      /* lock our minor table */

      down (&minor_table_mutex);

      dev = minor_table[subminor];

     

      if (dev == NULL) {

             up (&minor_table_mutex);

             dbg("object is NULL");

             return -ENODEV;

      }

     

      dbg("subminor= %d, dev=%p, dev->minor=%d", subminor, dev, dev->minor);

     

      /* lock our device */

      down (&dev->sem);

     

      if (0) { //dev->open_count <= 0) {

             dbg("device not opened");

             retval = -ENODEV;

             goto exit_not_opened;

      }

     

      if (dev->udev == NULL) {

             /* the device was unplugged before thefile was released */

             up (&dev->sem);

             myudisk_delete (dev);

             up (&minor_table_mutex);

    //             MOD_DEC_USE_COUNT;

             return 0;

      }

     

      /* decrement our usage count for the device */

    //      --dev->open_count;

      if (dev->open_count <= 0) {

             /* shutdown any bulk writes that mightbe going on */

             usb_unlink_urb (dev->write_urb);

             dev->open_count = 0;

      }

     

      /* decrement our usage count for the module */

    //      MOD_DEC_USE_COUNT;

     

    exit_not_opened:

      up (&dev->sem);

      up (&minor_table_mutex);

     

      return retval;

    }

     

     

    /**

     *     myudisk_ioctl

     */

    static intmyudisk_ioctl (struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg)

    {

      unsigned int minor;

     

      dbg("enter myudisk_ioctl()");

     

      if (!inode || !inode->i_rdev)  

             return -EINVAL;

     

      minor = MINOR(inode->i_rdev);

     

      switch (cmd) {

     

             case BLKFLSBUF: {      //将缓冲写回存储区的操作

                    /* flush buffers */

                    dbg("ioctl:BLKFLSBUF\n");

                    /* deny all but root */

                    if (!capable(CAP_SYS_ADMIN))

                           return -EACCES;

                    fsync_dev(inode->i_rdev);

                    invalidate_buffers(inode->i_rdev);

                    break;

             }

     

        case BLKGETSIZE: {      //得到设备容量的操作

                    /* return device size */

                    dbg("ioctl:BLKGETSIZE\n");

                    dbg("ioctl: BLKGETSIZE =%u\n",myudisk_size);

                    if (!arg)

                           return -EINVAL;

                    return put_user(SECTOR_num,(long *) arg);

             }

            

             case BLKRASET: { //设置设备预读值的操作

                    /* set read ahead value */

                    int tmp;

                    dbg("ioctl:BLKRASET\n");

                    if (get_user(tmp, (long *)arg))

                           return -EINVAL;

                    if (tmp > 0xff)

                           return -EINVAL;

                    read_ahead[MAJOR_NR] = tmp;

                    return 0;

             }

     

             case BLKRAGET: {       //得到设备预读值的操作

                    /* return read ahead value */

                    dbg("ioctl:BLKRAGET\n");

                    if (!arg)

                           return -EINVAL;

                    returnput_user(read_ahead[MAJOR_NR], (long *)arg);

             }

     

             case BLKSSZGET: {      //得到设备块大小的操作

                    /* return block size */

                    dbg("ioctl:BLKSSZGET\n");

                    if (!arg)

                           return -EINVAL;

                    return put_user(myudisk_hard,(long *)arg);

             }

     

             default: {             //其他操作

                    dbg("ioctl wanted%u\n", cmd);

                    return -ENOTTY;

             }

      }

     

      dbg(" exit myudisk_ioctl()");

      return 0;

     

     

      struct my_udisk *dev;

     

      dev = (struct my_udisk*)file->private_data;

     

      /* lock this object */

      down (&dev->sem);

     

      /* verify that the device wasn't unplugged */

      if (dev->udev == NULL) {

             up (&dev->sem);

             return -ENODEV;

      }

     

      dbg(" - minor %d, cmd 0x%.4x, arg%ld",

         dev->minor, cmd, arg);

     

     

      /* fill in your device specific stuff here */

     

      /* unlock the device */

      up (&dev->sem);

     

      /* return that we did not understand thisioctl call */

      return -ENOTTY; 

    }

     

     

    /**

     *     myudisk_write_bulk_callback

     */

    static voidmyudisk_write_bulk_callback (struct urb *urb)

    {

      struct my_udisk *dev = (struct my_udisk*)urb->context;

     

      dbg(" - minor %d", dev->minor);

     

      if ((urb->status != -ENOENT) &&

         (urb->status != -ECONNRESET)) {

             dbg(" - nonzero write bulk statusreceived: %d",

                urb->status);

             return;

      }

     

      return;

    }

     

    static intmyudisk_request(request_queue_t *request_queue, int rw, struct buffer_head*sbh)

    {

      unsigned long total;

     

     

      //int *make_oops = NULL;    // CR: access to this pointer will causeOops, for debug only.      

      //INIT_REQUEST;

     

      //devno = DEVICE_NR(CURRENT->rq_dev);

      /*if(devno>MAX_DEVICES);

      {

             printk("The device number is toolarage!!!\n");

             return 0;

      }*/

     

     

      //struct my_udisk *dev = CURRENT->rq_dev;

      struct my_udisk *dev = minor_table[0];

      int retval;

      if(dev == NULL)

             {

                    printk("Point to a unknowndevice !!! the dev is NULL\n");

                    return 0;

             }

      if (dev->udev == NULL) {

             printk("the dev->udev isNULL!!!\n");

             return -ENODEV;

      }

      dbg("%s sector rsector = %lu, blocknr =%lu\n",

                           rw == READ ?"read" : "write",

                           sbh->b_rsector,

                           sbh->b_blocknr);

     

      //offset = sbh->b_rsector *myudisk_sectorsize;

      total = (unsigned long)sbh->b_size;//计算需要访问的地址和大小

      __u32 nLUN  = (__u32)(PARTION_offset + sbh->b_rsector);

     

      /* access beyond end of the device */

      if (total+nLUN> myudisk_size) {

             dbg("Error: access beyond end ofthe device");

             /* error in request  */

             buffer_IO_error(sbh);

             return 0;

      }                                         //判断访问地址是否越界

     

      dbg("offset = %lu, total = %lu\n",nLUN, total);

      //printk("The request has to the readwrite function!!!\n");//singal of using for the debug!

     

      struct cmnd_struct *com;

      com = kmalloc (sizeof(structcmnd_struct),GFP_KERNEL);

      //**********************/

      if (rw == READ)

      {      //如果是读操作,从虚拟盘的内存中复制数据到缓冲区中

             //memcpy(bh_kmap(sbh),myudisk_storage+offset, total);

             dbg("To the Readrequest!!!\n");

                    memset(dev->bulk_in_buffer,0,dev->bulk_in_size);

                    com->cmnd[0] = 0x28;

                    com->cmnd[1] = 0;

                    com->cmnd[2] = ((unsignedchar)nLUN>>24) & 0xff;

                    com->cmnd[3] = ((unsignedchar)nLUN>>16) & 0xff;

                    com->cmnd[4] = ((unsignedchar)nLUN>>8) & 0xff;

                    com->cmnd[5] = ((unsignedchar)nLUN) & 0xff;

     

                   

                    com->cmnd[7] = (unsignedchar)((total/myudisk_soft)>>8) & 0xff;

                    com->cmnd[8] = (unsignedchar)(total/myudisk_soft) & 0xff;

                   

                    com->cmd_len = 12;

                    com->data_payload_size =(unsigned long)sbh->b_size;

                    com->sc_data_direction =SCSI_DATA_READ;

                    com->tag = 0x12345678;;

     

                    myudisk_Bulk_transport(dev->udev,dev->interface,com, dev->bulk_in_buffer, dev->bulk_in_size,dev->bulk_in_endpointAddr, dev->bulk_out_endpointAddr);

                    memcpy(bh_kmap(sbh),dev->bulk_in_buffer,sbh->b_size);

                    memset(dev->bulk_in_buffer,0,dev->bulk_in_size);

                    dbg("usb_bulk_msg hassuccessfully!!\n");

                    retval = (unsignedlong)sbh->b_size;

            

      }

      else if (rw == WRITE) //如果是写操作,从缓冲区中复制数据到虚拟盘的内存中

      {

             memset(dev->bulk_out_buffer,0,dev->bulk_out_size);

             memcpy(dev->bulk_out_buffer,bh_kmap(sbh), total);

             com->cmnd[0] = 0x2A;

             com->cmnd[1] = 0;

             com->data_payload_size = total;

             com->cmnd[2] = ((unsignedchar)nLUN>>24) & 0xff;

             com->cmnd[3] = ((unsignedchar)nLUN>>16) & 0xff;

             com->cmnd[4] = ((unsigned char)nLUN>>8)& 0xff;

             com->cmnd[5] = ((unsigned char)nLUN)& 0xff;

     

             com->cmnd[7] = (unsignedchar)((total/myudisk_soft)>>8) & 0xff;

             com->cmnd[8] = (unsignedchar)(total/myudisk_soft) & 0xff;             

            

             com->tag = 0x12345678;

             com->cmd_len = 12;

             com->sc_data_direction =SCSI_DATA_WRITE;

             myudisk_Bulk_transport(dev->udev,dev->interface,com, dev->bulk_out_buffer, dev->bulk_out_size,dev->bulk_in_endpointAddr, dev->bulk_out_endpointAddr);

             memset(dev->bulk_out_buffer,0,dev->bulk_out_size);

                   

      }

      else {     /*can't happen */

             dbg("cmd == %d is invalid\n",rw);

             }

      /* successful */

     

      sbh->b_end_io(sbh,1);      //结束读写操作

      kfree(com);

      return 0;

    }

     

    /**

     *     myudisk_probe

     *

     *     Calledby the usb core when a new device is connected that it thinks

     *     thisdriver might be interested in.

     */

    static void *myudisk_probe(struct usb_device *udev, unsigned int ifnum, const structusb_device_id *id)

    {

      struct my_udisk *dev = NULL;

      struct usb_interface *interface;

      struct usb_interface_descriptor *iface_desc;

      struct usb_endpoint_descriptor *endpoint;

      int minor;

      int buffer_size;

      int i;

      char name[10];

     

      dbg("myudisk_probe()");

     

      printk("The core has to here!!!!\n");

      /* See if the device offered us matches whatwe can accept */

      if ((udev->descriptor.idVendor != MY_UDISK_VENDOR_ID)||

         (udev->descriptor.idProduct != MY_UDISK_PRODUCT_ID)) {

             return NULL;

      }

     

      printk("drivers has successfully detectedthe device !!\n");

     

      /* select a "subminor" number (partof a minor number) */

      down (&minor_table_mutex);

      for (minor = 0; minor < MAX_DEVICES;++minor) {

             if (minor_table[minor] == NULL)

                    break;

      }

      if (minor >= MAX_DEVICES) {

             info ("Too many devices pluggedin, can not handle this device.\n");

             goto exit;

      }

     

      /* allocate memory for our device state and intializeit */

      dev = kmalloc (sizeof(struct my_udisk),GFP_KERNEL);

      if (dev == NULL) {

             err ("Out of memory");

             goto exit;

      }

      memset (dev, 0x00, sizeof (*dev));

      minor_table[minor] = dev;

      printk("The subminor is %d The device is %p\n",minor,minor_table[minor]);

     

      interface =&udev->actconfig->interface[ifnum];

     

      init_MUTEX (&dev->sem);

      dev->udev = udev;

      dev->interface = interface;

      dev->minor = minor;

     

      /* set up the endpoint information */

      /* check out the endpoints */

      iface_desc = &interface->altsetting[0];

      for (i = 0; i <iface_desc->bNumEndpoints; ++i) {

             endpoint =&iface_desc->endpoint[i];

     

             if ((endpoint->bEndpointAddress& 0x80) &&

                ((endpoint->bmAttributes & 3) == 0x02)) {

                    /* we found a bulk in endpoint*/

                    buffer_size= 4096;

                    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("Couldn'tallocate bulk_in_buffer");

                           gotoerror;

                    }

             }

            

             if (((endpoint->bEndpointAddress& 0x80) == 0x00) &&

                ((endpoint->bmAttributes & 3) == 0x02)) {

                    /* we found a bulk out endpoint*/

                    dev->write_urb =usb_alloc_urb(0);

                    if (!dev->write_urb) {

                           err("No free urbs available");

                           goto error;

                    }

                    buffer_size = 4096;

                    dev->bulk_out_size =buffer_size;

                    dev->bulk_out_endpointAddr =endpoint->bEndpointAddress;

                    dev->bulk_out_buffer =kmalloc (buffer_size, GFP_KERNEL);

                    if (!dev->bulk_out_buffer) {

                           err("Couldn'tallocate bulk_out_buffer");

                           goto error;

                    }

                    FILL_BULK_URB(dev->write_urb,udev,

                                 usb_sndbulkpipe(udev,

                                               endpoint->bEndpointAddress),

                                 dev->bulk_out_buffer, buffer_size,

                                 myudisk_write_bulk_callback, dev);

             }

      }

     

      /* initialize the devfs node for this deviceand register it */

      sprintf(name, "myudisk%d",dev->minor);

     

      dev->devfs = devfs_register(usb_devfs_handle, name,

                                DEVFS_FL_DEFAULT, USB_MAJOR,

                                MY_UDISK_MINOR_BASE + dev->minor,

                                S_IFCHR | S_IRUSR | S_IWUSR |

                                S_IRGRP | S_IWGRP | S_IROTH,

                                &myudisk_fops, NULL);

    ///Thispart is to read the flush's capicity and MBR information

    structcmnd_struct *com;

    com = kmalloc(sizeof(struct cmnd_struct),GFP_KERNEL);

    if(com == NULL)

    {

      dbg("The memory on the com is unavailable!");

      goto error;

    }

    memset(dev->bulk_in_buffer,0,dev->bulk_in_size);

    com->cmnd[0] =0x25;

    com->tag = 0;

    com ->sc_data_direction= SCSI_DATA_READ ;

    com->cmnd[1] =0;

    com->cmd_len =12;

    myudisk_Bulk_transport(dev->udev,dev->interface, com, dev->bulk_in_buffer, dev->bulk_in_size,dev->bulk_in_endpointAddr, dev->bulk_out_endpointAddr);//This is to sendthe command and receive data from device

     

    printk("Tothe after the read capity!");

    if(dev == NULL)

    {

      printk("The dev is NULL!\n");

      goto error;

    }

    BLOCK_num = (((dev->bulk_in_buffer[0] )<< 24) |((dev->bulk_in_buffer[1])<< 16) | ((dev->bulk_in_buffer[2])<< 8) | (dev->bulk_in_buffer[3]) ) + 1;//(__u32*)buffer;  block number LBN(n-1)

    myudisk_soft = (((dev->bulk_in_buffer[4]) << 24) | ((dev->bulk_in_buffer[5])<< 16) | ((dev->bulk_in_buffer[6]) << 8) |(dev->bulk_in_buffer[7]) );//(__u32*)buffer+4;block size.

    myudisk_size=  BLOCK_num * myudisk_soft;//device'scapicity by bites

    SECTOR_num =(myudisk_size/myudisk_hard);//device's sector number

     

    printk("Thesize is %u,The block size is %u,the num is%u",myudisk_size,myudisk_soft,BLOCK_num);

    memset(dev->bulk_in_buffer,0,dev->bulk_in_size);

    kfree(com);

    //***************************************************///thisis to read MBR information but still have some problem

      __u32 nrBlock = 0;//read from the zero sector

      unsigned long size = 512;//the read block sizethe first 512 bites is the MBR information

      struct cmnd_struct *cs;

      cs = kmalloc (sizeof(structcmnd_struct),GFP_KERNEL);

      if(cs == NULL)

      {

             dbg("The memory on the cs isunavailable !");

             goto error;

      }

     

      cs->cmnd[0] = 0x28;

      cs->cmnd[1] =0;

      cs->cmnd[2] = ((unsignedchar)nrBlock>>24) & 0xff;

      cs->cmnd[3] = ((unsignedchar)nrBlock>>16) & 0xff;

      cs->cmnd[4] = ((unsignedchar)nrBlock>>8) & 0xff;

      cs->cmnd[5] = ((unsigned char)nrBlock)& 0xff;

     

      cs->cmnd[7] = (unsigned char)((size/myudisk_soft)>>8)& 0xff;

      cs->cmnd[8] = (unsignedchar)(size/myudisk_soft) & 0xff;

      cs ->tag = 0x12345678;

      cs->cmd_len = 12;

      cs->sc_data_direction = SCSI_DATA_READ;

      cs->data_payload_size = 512;

      myudisk_Bulk_transport(dev->udev,dev->interface, cs, dev->bulk_in_buffer, dev->bulk_in_size,dev->bulk_in_endpointAddr, dev->bulk_out_endpointAddr);

     

      __u32 startSector,sectorsNum;

      startSector = 0;

      sectorsNum = 0;

     

      for(i = 3; i>=1; i--)//computer the startersector and the offset of the device

      {

            startSector += dev->bulk_in_buffer[0x01c6+ i];

             sectorsNum  += dev->bulk_in_buffer[0x01ca + i];

             startSector <<= 8;

             sectorsNum  <<= 8;

      }

      startSector += dev->bulk_in_buffer[0x01c6];

      sectorsNum += dev->bulk_in_buffer[0x01ca];

     

      dbg("The disk started at sector%X.\n",startSector);

      dbg("The disk has %Xsectors.\n",sectorsNum);

     

      PARTION_offset = startSector;

     

      dbg("The disk offset with %Xsectors.",PARTION_offset);

     

      printk("Next is the disk MBR and DPTinformation.\n");

     

      for(i = 0; i < 512; i++){

      printk("%X    ",dev->bulk_in_buffer[i]);

      if(i ==445)the first 445 bites is the prebootinformation  the last is the partationinformation

             printk("\nNow is the partitiontable.\n");

      if(i%8 == 0)

             printk("\n");

      }

      kfree(cs);

     

     

     

     

    //

      /* let the user know what node this device isnow attached to */

      info ("My UDisk device now attached tomyudisk%d", dev->minor);

      goto exit;

     

    error:

      myudisk_delete (dev);

      dev = NULL;

     

    exit:

      up (&minor_table_mutex);

      return dev;

    }

     

     

    /**

     *     myudisk_disconnect

     *

     *     Calledby the usb core when the device is removed from the system.

     */

    /***********************************************************************

     * Helper routines

     ***********************************************************************/

     

    /* Calculate thelength of the data transfer (not the command) for any

     * given SCSI command (adapted fromusb__stor_transfer_length())

     */

    unsigned intmyudisk_transfer_length(struct cmnd_struct *cs)

    {

      int doDefault = 0;

      unsigned int len = 0;

     

      /* This table tells us:

         X =command not supported

         L =return length in cmnd[4] (8 bits).

         M =return length in cmnd[8] (8 bits).

         G =return length in cmnd[3] and cmnd[4] (16 bits)

         H =return length in cmnd[7] and cmnd[8] (16 bits)

         I =return length in cmnd[8] and cmnd[9] (16 bits)

         C =return length in cmnd[2] to cmnd[5] (32 bits)

         D =return length in cmnd[6] to cmnd[9] (32 bits)

         B =return length in blocksize so we use buff_len

         R =return length in cmnd[2] to cmnd[4] (24 bits)

         S =return length in cmnd[3] to cmnd[5] (24 bits)

         T =return length in cmnd[6] to cmnd[8] (24 bits)

         U =return length in cmnd[7] to cmnd[9] (24 bits)

         0-9 =fixed return length

         V =20 bytes

         W =24 bytes

         Z =return length is mode dependant or not in command, use buff_len

      */

     

      static char *lengths =

     

            /*0123456789ABCDEF   0123456789ABCDEF */

     

             "00XLZ6XZBXBBXXXB""00LBBLG0R0L0GG0X"  /* 00-1F */

             "XXXXT8XXB4B0BBBB""ZZZ0B00HCSSZTBHH"  /* 20-3F */

             "M0HHB0X000H0HH0X""XHH0HHXX0TH0H0XX"  /* 40-5F */

             "XXXXXXXXXXXXXXXX""XXXXXXXXXXXXXXXX"  /* 60-7F */

             "XXXXXXXXXXXXXXXX""XXXXXXXXXXXXXXXX"  /* 80-9F */

             "X0XXX00XB0BXBXBB""ZZZ0XUIDU000XHBX"  /* A0-BF */

             "XXXXXXXXXXXXXXXX""XXXXXXXXXXXXXXXX"  /* C0-DF */

             "XDXXXXXXXXXXXXXX""XXW00HXXXXXXXXXX"; /* E0-FF */

     

      /* Commands checked in table:

     

        CHANGE_DEFINITION 40

        COMPARE 39

         COPY18

        COPY_AND_VERIFY 3a

         ERASE19

        ERASE_10 2c

        ERASE_12 ac

        EXCHANGE_MEDIUM a6

        FORMAT_UNIT 04

        GET_DATA_BUFFER_STATUS 34

        GET_MESSAGE_10 28

        GET_MESSAGE_12 a8

        GET_WINDOW 25   !!! Has more datathan READ_CAPACITY, need to fix table

        INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len

        INQUIRY 12

        LOAD_UNLOAD 1b

        LOCATE 2b

        LOCK_UNLOCK_CACHE 36

        LOG_SELECT 4c

        LOG_SENSE 4d

        MEDIUM_SCAN 38     !!! This was M

        MODE_SELECT6 15

        MODE_SELECT_10 55

        MODE_SENSE_6 1a

        MODE_SENSE_10 5a

        MOVE_MEDIUM a5

        OBJECT_POSITION 31  !!! Same asSEARCH_DATA_EQUAL

        PAUSE_RESUME 4b

        PLAY_AUDIO_10 45

        PLAY_AUDIO_12 a5

        PLAY_AUDIO_MSF 47

        PLAY_AUDIO_TRACK_INDEX 48

             PLAY_AUDIO_TRACK_RELATIVE_10 49

        PLAY_AUDIO_TRACK_RELATIVE_12 a9

        POSITION_TO_ELEMENT 2b

                 PRE-FETCH 34

        PREVENT_ALLOW_MEDIUM_REMOVAL 1e

         PRINT0a             !!! Same as WRITE_6 but isalways in bytes

        READ_6 08

        READ_10 28

        READ_12 a8

        READ_BLOCK_LIMITS 05

        READ_BUFFER 3c

        READ_CAPACITY 25

        READ_CDROM_CAPACITY 25

        READ_DEFECT_DATA 37

        READ_DEFECT_DATA_12 b7

         READ_ELEMENT_STATUS b8 !!! Think this is inbytes

        READ_GENERATION 29 !!! Could also be M?

        READ_HEADER 44     !!! This was L

        READ_LONG 3e

        READ_POSITION 34   !!! This shouldbe V but conflicts with PRE-FETCH

        READ_REVERSE 0f

        READ_SUB-CHANNEL 42 !!! Is this in bytes?

        READ_TOC 43         !!! Is this inbytes?

        READ_UPDATED_BLOCK 2d

        REASSIGN_BLOCKS 07

        RECEIVE 08        !!! Same asREAD_6 probably in bytes though

        RECEIVE_DIAGNOSTIC_RESULTS 1c

        RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes

        RELEASE_UNIT 17

        REQUEST_SENSE 03

        REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes

        RESERVE_UNIT 16

        REWIND 01

        REZERO_UNIT 01

         SCAN1b          !!! Conflicts with variouscommands, should be L

        SEARCH_DATA_EQUAL 31

        SEARCH_DATA_EQUAL_12 b1

        SEARCH_DATA_LOW 30

        SEARCH_DATA_LOW_12 b0

        SEARCH_DATA_HIGH 32

        SEARCH_DATA_HIGH_12 b2

        SEEK_6 0b         !!! Conflictswith SLEW_AND_PRINT

        SEEK_10 2b

         SEND0a           !!! Same as WRITE_6,probably in bytes though

         SEND2a           !!! Similar to WRITE_10 butfor scanners

        SEND_DIAGNOSTIC 1d

        SEND_MESSAGE_6 0a   !!! Same asWRITE_6 - is in bytes

         SEND_MESSAGE_102a  !!! Same as WRITE_10 - is in bytes

        SEND_MESSAGE_12 aa  !!! Same asWRITE_12 - is in bytes

        SEND_OPC 54

        SEND_VOLUME_TAG b6 !!! Think this is in bytes

        SET_LIMITS 33

        SET_LIMITS_12 b3

        SET_WINDOW 24

        SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6

         SPACE11

        START_STOP_UNIT 1b

        STOP_PRINT 1b

        SYNCHRONIZE_BUFFER 10

        SYNCHRONIZE_CACHE 35

        TEST_UNIT_READY 00

        UPDATE_BLOCK 3d

        VERIFY 13

        VERIFY 2f

        VERIFY_12 af

        WRITE_6 0a

        WRITE_10 2a

        WRITE_12 aa

        WRITE_AND_VERIFY 2e

        WRITE_AND_VERIFY_12 ae

        WRITE_BUFFER 3b

        WRITE_FILEMARKS 10

        WRITE_LONG 3f

        WRITE_SAME 41

      */

     

      if (cs->sc_data_direction ==SCSI_DATA_WRITE) {

             doDefault = 1;

      }

      else

             switch (lengths[cs->cmnd[0]]) {

                    case 'L':

                           len = cs->cmnd[4];

                           break;

     

                    case 'M':

                           len = cs->cmnd[8];

                           break;

     

                    case '0':

                    case '1':

                    case '2':

                    case '3':

                    case '4':

                    case '5':

                    case '6':

                    case '7':

                    case '8':

                    case '9':

                           len = lengths[cs->cmnd[0]]-'0';

                           break;

     

                    case 'G':

                           len = (((unsignedint)cs->cmnd[3])<<8) |

                                  cs->cmnd[4];

                           break;

     

                    case 'H':

                           len = (((unsignedint)cs->cmnd[7])<<8) |

                                  cs->cmnd[8];

                           break;

     

                    case 'I':

                           len = (((unsignedint)cs->cmnd[8])<<8) |

                                  cs->cmnd[9];

                           break;

     

                    case 'R':

                           len = (((unsignedint)cs->cmnd[2])<<16) |

                                  (((unsignedint)cs->cmnd[3])<<8) |

                                  cs->cmnd[4];

                           break;

     

                    case 'S':

                           len = (((unsignedint)cs->cmnd[3])<<16) |

                                  (((unsignedint)cs->cmnd[4])<<8) |

                                  cs->cmnd[5];

                           break;

     

                    case 'T':

                           len = (((unsignedint)cs->cmnd[6])<<16) |

                                  (((unsignedint)cs->cmnd[7])<<8) |

                                  cs->cmnd[8];

                           break;

     

                    case 'U':

                           len = (((unsignedint)cs->cmnd[7])<<16) |

                                  (((unsignedint)cs->cmnd[8])<<8) |

                                  cs->cmnd[9];

                           break;

     

                    case 'C':

                           len = (((unsignedint)cs->cmnd[2])<<24) |

                                  (((unsignedint)cs->cmnd[3])<<16) |

                                  (((unsignedint)cs->cmnd[4])<<8) |

                                  cs->cmnd[5];

                           break;

     

                    case 'D':

                           len = (((unsignedint)cs->cmnd[6])<<24) |

                                  (((unsignedint)cs->cmnd[7])<<16) |

                                  (((unsignedint)cs->cmnd[8])<<8) |

                                  cs->cmnd[9];

                           break;

     

                    case 'V':

                           len = 20;

                           break;

     

                    case 'W':

                           len = 24;

                           break;

     

                    case 'B':

                           /* Use buffer size due todifferent block sizes */

                           doDefault = 1;

                           break;

     

                    case 'X':

                           dbg("Error:UNSUPPORTED COMMAND X\n",

                                         cs->cmnd[0]);

                           doDefault = 1;

                           break;

     

                    case 'Z':

                           /* Use buffer size due tomode dependence */

                           doDefault = 1;

                           break;

     

                    default:

                           dbg("Error: COMMANDX out of range or table inconsistent (%c).\n",

                                  cs->cmnd[0],lengths[cs->cmnd[0]] );

                           doDefault = 1;

             }

        

      if ( doDefault == 1 ) {

             len = cs->data_payload_size;

      }

     

      dbg("doDefault %d, data length %u",doDefault, len);

      return len;

    }

    //reset

     

     

     

    /* This issues aBulk-only Reset to the device in question, including

     * clearing the subsequent endpoint halts thatmay occur.

     */

    intmyudisk_Bulk_reset(struct usb_device *udev, struct usb_interface *interface,

                           __u8bulk_in_endpointAddr, __u8 bulk_out_endpointAddr)

    {

      int result;

     

      dbg("Bulk reset requested\n");

     

      /* if the device was removed, then we'realready reset */

      if (!udev)

             return SUCCESS;

     

      result = usb_control_msg(udev,

                            usb_sndctrlpipe(udev,0),

                            MU_BULK_RESET_REQUEST,

                            USB_TYPE_CLASS | USB_RECIP_INTERFACE,

                            0,

                            interface->altsetting[0].bInterfaceNumber,

                            NULL, 0, HZ*5);

     

      if (result < 0) {

             dbg("Bulk soft reset failed%d\n", result);

             return FAILED;

      }

     

      /* long wait for reset */

      set_current_state(TASK_UNINTERRUPTIBLE);

      schedule_timeout(HZ*6);

      set_current_state(TASK_RUNNING);

     

      usb_clear_halt(udev, usb_rcvbulkpipe(udev,bulk_in_endpointAddr));

      usb_clear_halt(udev, usb_sndbulkpipe(udev,bulk_out_endpointAddr));

      dbg("Bulk soft reset completed\n");

      return SUCCESS;

    }

     

     

     

    //

    //

    intmyudisk_Bulk_transport(struct usb_device *udev, struct usb_interface*interface,

                               struct cmnd_struct*cs,

                               unsigned char *bulk_buffer,int bulk_size,

                               __u8bulk_in_endpointAddr, __u8 bulk_out_endpointAddr)

    {

      struct bulk_cb_wrap *bcb;

      struct bulk_cs_wrap *bcs;

      int result;

      int pipe;

      int partial;

      char *buf;

      unsigned int transfer_amount;

      int ret = MYUDISK_TRANSPORT_ERROR;

     

      bcb = kmalloc(sizeof *bcb, in_interrupt() ?GFP_ATOMIC : GFP_NOIO);

      if (!bcb) {

             return MYUDISK_TRANSPORT_ERROR;

      }

      bcs = kmalloc(sizeof *bcs, in_interrupt() ?GFP_ATOMIC : GFP_NOIO);

      if (!bcs) {

             kfree(bcb);

             return MYUDISK_TRANSPORT_ERROR;

      }

     

      /* set up the command wrapper */

      bcb->Signature =cpu_to_le32(MU_BULK_CB_SIGN);

      transfer_amount = myudisk_transfer_length(cs);

      bcb->DataTransferLength =cpu_to_le32(transfer_amount);

      bcb->Flags = cs->sc_data_direction == SCSI_DATA_READ? 1 << 7 : 0;

      bcb->Tag = ++(cs->tag);

      bcb->Lun = cs->cmnd[1] >> 5;

      bcb->Length = cs->cmd_len;

     

      /* construct the pipe handle */

      pipe = usb_sndbulkpipe(udev,bulk_out_endpointAddr);

     

      /* copy the command payload */

      memset(bcb->CDB, 0, sizeof(bcb->CDB));

      memcpy(bcb->CDB, cs->cmnd,bcb->Length);

     

      /* send it to out endpoint */

      myudisk_debug_data ("command tosend", MU_BULK_CB_WRAP_LEN, (unsigned char *)bcb);

      dbg("Bulk command S 0x%x T 0x%x Trg %dLUN %d L %d F %d CL %d",

              le32_to_cpu(bcb->Signature), bcb->Tag,

              (bcb->Lun >> 4), (bcb->Lun & 0x0F),

              bcb->DataTransferLength, bcb->Flags, bcb->Length);

      result = usb_bulk_msg(udev,

                          pipe,

                          bcb, MU_BULK_CB_WRAP_LEN,

                          &partial, MYUDISK_TIMEOUT);

      dbg("Bulk command transfer result=%d,xferred %d/%d",

         result, partial, MU_BULK_CB_WRAP_LEN);

     

      /* if the command was aborted, indicate that*/

      if (result == -ECONNRESET) {

             ret = MYUDISK_TRANSPORT_ABORTED;

             goto out;

      }

     

      /* if we stall, we need to clear it before wego on */

      if (result == -EPIPE) {

             dbg("clearing endpoint halt forpipe 0x%x", pipe);

             result = usb_clear_halt(udev, pipe);

     

             /* if the command was aborted, indicatethat */

             if (result == -ECONNRESET) {

                    ret = MYUDISK_TRANSPORT_ABORTED;

                    goto out;

             }

             result = -EPIPE;

      } else if (result) {

             /* unknown error -- we've got a problem*/

             ret = MYUDISK_TRANSPORT_ERROR;

             goto out;

      }

      dbg("----cmnd end\n");

     

      /* if the command transfered well, then we goto the data stage */

      if (result == 0) {

             /* send/receive data payload, if thereis any */

             if (bcb->DataTransferLength) {

                    /* calculate the appropriatepipe and buffer information */

                    if (cs->sc_data_direction ==SCSI_DATA_READ) {

                           pipe =usb_rcvbulkpipe(udev, bulk_in_endpointAddr);

                           buf = bulk_buffer;

                           if (transfer_amount >bulk_size) {

                                  dbg("illegalDataTransferLength!");

                                  transfer_amount =bulk_size;

                           }

                    } else {

                           pipe =usb_sndbulkpipe(udev, bulk_out_endpointAddr);

                           buf = bulk_buffer;

                           if (transfer_amount >bulk_size) {

                                  dbg("illegalDataTransferLength!");

                                  transfer_amount =bulk_size;

                           }

                    }

            

                    /* transfer the data */

                    dbg("xfer %d bytesdata", transfer_amount);

                    result = usb_bulk_msg(udev,

                                  pipe,

                                  buf, transfer_amount,

                                  &partial,MYUDISK_TIMEOUT);

                    cs->data_payload_actualSize =partial;

                    dbg("Bulk data transferresult: %d, xferred %d/%d",

                             result, partial, transfer_amount);

    //                    myudisk_debug_data("data transfered", partial, buf);

            

                    /* if we stall, we need to clearit before we go on */

                    if (result == -EPIPE) {

                           dbg("clearingendpoint halt for pipe 0x%x", pipe);

                           usb_clear_halt(udev,pipe);

                    }

     

                    /* if it was aborted, we need toindicate that */

                    if (result) {

                           ret = MYUDISK_TRANSPORT_ABORTED;

                           goto out;

                    }

             }

      }

      dbg("----data end\n");

     

      /* See flow chart on pg 15 of the Bulk OnlyTransport spec for

       * anexplanation of how this code works.

       */

     

      /* construct the pipe handle */

      pipe = usb_rcvbulkpipe(udev, bulk_in_endpointAddr);

     

      /* get CSW for device status */

      dbg("Attempting to get CSW...");

      result = usb_bulk_msg(udev,

                    pipe,

                    bcs, MU_BULK_CS_WRAP_LEN,

                    &partial, MYUDISK_TIMEOUT);

     

      dbg("Bulk status transfer result = %d,xferred %d/%d", result, partial, MU_BULK_CS_WRAP_LEN);

      /* if the command was aborted, indicate that*/

      if (result == -ECONNRESET) {

             ret = MYUDISK_TRANSPORT_ABORTED;

             goto out;

      }

     

      /* did the attempt to read the CSW fail? */

      if (result == -EPIPE) {

             dbg("clearing endpoint halt forpipe 0x%x", pipe);

             result = usb_clear_halt(udev, pipe);

     

             /* if the command was aborted, indicatethat */

             if (result == -ECONNRESET) {

                    ret = MYUDISK_TRANSPORT_ABORTED;

                    goto out;

             }

     

             /* get the status again */

             dbg("Attempting to get CSW (2ndtry)...");

             result = usb_bulk_msg(udev,

                           pipe,

                           bcs, MU_BULK_CS_WRAP_LEN,

                           &partial,MYUDISK_TIMEOUT);

     

             /* if the command was aborted, indicatethat */

             if (result == -ECONNRESET) {

                    ret = MYUDISK_TRANSPORT_ABORTED;

                    goto out;

             }

     

             /* if it fails again, we need a resetand return an error*/

             if (result == -EPIPE) {

                    dbg("clearing halt for pipe0x%x", pipe);

                    result = usb_clear_halt(udev,pipe);

     

                    /* if the command was aborted,indicate that */

                    if (result == -ECONNRESET) {

                           ret =MYUDISK_TRANSPORT_ABORTED;

                    } else {

                           ret =MYUDISK_TRANSPORT_ERROR;

                    }

                    goto out;

             }

      }

     

      /* if we still have a failure at this point,we're in trouble */

      if (result) {

             ret = MYUDISK_TRANSPORT_ERROR;

             goto out;

      }

     

      /* check bulk status */

      myudisk_debug_data ("status datarecerived", partial, (unsigned char *)bcs);

      dbg("Bulk status Sig 0x%x T 0x%x R %dStat 0x%x",

         le32_to_cpu(bcs->Signature), bcs->Tag, bcs->Residue,bcs->Status);

      if ((bcs->Signature != cpu_to_le32(MU_BULK_CS_SIGN)&& bcs->Signature != cpu_to_le32(MU_BULK_CS_OLYMPUS_SIGN)) ||

         bcs->Tag != bcb->Tag ||

         bcs->Status > MU_BULK_STAT_PHASE ||

         partial != 13) {

             dbg("Bulk logical error");

             ret = MYUDISK_TRANSPORT_ERROR;

             goto out;

      }

     

      /* based on the status code, we report good orbad */

      switch (bcs->Status) {

             case MU_BULK_STAT_OK:

                    /* command good -- note thatdata could be short */

                    ret = MYUDISK_TRANSPORT_GOOD;

                    goto out;

     

             case MU_BULK_STAT_FAIL:

                    /* command failed */

                    ret = MYUDISK_TRANSPORT_FAILED;

                    goto out;

     

             case MU_BULK_STAT_PHASE:

                    /* phase error -- note that atransport reset will be

                     * invoked by the invoke_transport() function

                     */

                    ret = MYUDISK_TRANSPORT_ERROR;

                    goto out;

      }

     

      /* we should never get here, but if we do,we're in trouble */

      dbg("we should never get here.");

     out:

      if (ret == MYUDISK_TRANSPORT_GOOD) {

             dbg("transport indicates commandwas successful\n");

      } else if (ret == MYUDISK_TRANSPORT_ABORTED ||

                ret == MYUDISK_TRANSPORT_ERROR) {

             myudisk_Bulk_reset(udev, interface,

                                bulk_in_endpointAddr,bulk_out_endpointAddr);

             dbg("transport indicates commandwas aborted\n");

      }

      kfree(bcb);

      kfree(bcs);

      return ret;

    }

     

     

     

    //

     

     

     

     

    static voidmyudisk_disconnect(struct usb_device *udev, void *ptr)

    {

      struct my_udisk *dev;

      int minor;

     

      dev = (struct my_udisk *)ptr;

     

      down (&minor_table_mutex);

      down (&dev->sem);

            

      minor = dev->minor;

     

      /* remove our devfs node */

      devfs_unregister(dev->devfs);

     

      /* if the device is not opened, then we cleanup right now */

      if (!dev->open_count) {

             up (&dev->sem);

             myudisk_delete (dev);

      } else {

             dev->udev = NULL;

             up (&dev->sem);

      }

     

      info("My UDisk #%d nowdisconnected", minor);

      up (&minor_table_mutex);

    }

     

     

     

    /**

     *     my_udisk_init

     */

    static int __initmy_udisk_init(void)

    {

      int result;

     

      /* register this driver with the USB subsystem*/

      result = usb_register(&myudisk_driver);

      if (result < 0) {

             err("usb_register failed for the"__FILE__" driver. Error number %d",

                result);

             return -1;

      }

     

      info(DRIVER_DESC " "DRIVER_VERSION);

     

      /* 块大小必须是扇区大小的整数倍 */

      /*if (myudisk_blocksize & ((1 << MYUDISK_SECTOR_BITS)-1)){

             dbg("Block size not a multiple ofsector size\n");

             return -EINVAL;

      }*/

     

      /* 分配存储空间 */

      /*myudisk_storage = (char *)vmalloc(1024*myudisk_size);

      if (myudisk_storage == NULL) {

             dbg("Not enough memory. Try asmaller size.\n");

             return -ENOMEM;

      }*/

      //memset(myudisk_storage, 0,1024*myudisk_size);

     

      /* 【重要】向系统注册块设备 */

      result = register_blkdev(MAJOR_NR,DEVICE_NAME, &myudisk_fops);

      if (result) {

             dbg("couldn't register blockdevice\n");

             return result;

      }

     

      /* 在系统中注册块的大小、存储容量等参数 */

      hardsect_size[MAJOR_NR] = &myudisk_hard;

      blksize_size[MAJOR_NR] = &myudisk_soft;

      blk_size[MAJOR_NR] = &myudisk_size;

     

      /* 在系统中注册响应读写请求的函数 */

      blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR),&myudisk_request);

      read_ahead[MAJOR_NR] = myudisk_readahead;

            

      return 0;

    }

    /**

     *     my_udisk_exit

     */

    static void__exit my_udisk_exit(void)

    {

      /* deregister this driver with the USBsubsystem */

      usb_deregister(&myudisk_driver);

     

      unregister_blkdev(MAJOR_NR, DEVICE_NAME);

     

      invalidate_buffers(MKDEV(MAJOR_NR,0));

     

      /* remove our request function */

      blk_dev[MAJOR_NR].request_queue.request_fn =0;             

    }

    module_init(my_udisk_init);

    module_exit(my_udisk_exit);

    MODULE_AUTHOR(DRIVER_AUTHOR);

    MODULE_DESCRIPTION(DRIVER_DESC);

    MODULE_LICENSE("GPL");

     

    •      请特别留意内核函数usb_bulk_msg的用法和SCSI接口规范,以及磁盘分区表结构。

    •      可能需要读一些英文原版资料。

    •      检查时,你需要当场独立完成以下操作:

    –  用lsmod命令查询系统中是否已经加载usb-storage的模块,这是Linux系统自带的U盘驱动程序。如果已经加载,则用rmmod命令卸载这个模块。

    查看U盘出厂信息

    –  编译改装后的radimo程序,要求能编译通过,允许出现编译警告。

    –  用insmod命令加载改装后的radimo程序。

    –  插入U盘。要求在用dmesg查看系统日志时,能够看到改装的radimo程序发现了U盘。允许你的程序只认识一种或者有限的几种U盘,不要求能够认出市面上所有U盘。

    –  能够在系统日志中显示出U盘的容量。

    –  用mknod命令建立设备文件,并用mount命令挂接这个U盘的文件系统到/mnt。你的U盘可以预先用Windows格式化好。

    –  用df命令应该能够看到已经挂接好的U盘。

    –  用ls  /mnt命令应该能够看到U盘中的内容。用cp命令能够将U盘中的任意文件复制到硬盘上。

    –  用umount命令和rmmod命令清理现场。

    转载请注明原文地址: https://ju.6miu.com/read-962099.html

    最新回复(0)