linux下USB DNW功能实现

主机环境:ubuntu 11.10

编译器:   arm-linux-gcc 4.3.3

实验开发板: TQ2440

由于ubuntu 11.10的kernel比较新 是 3.0.0,有些函数名有变化

直接贴源码,编译可直接使用

以下是驱动,省略读函数,写函数采用URB传输:

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/usb.h>

/* Define these values to match your devices */
#define USB_VM_VENDOR_ID    0x5345
#define USB_VM_PRODUCT_ID    0x1234

/* table of devices that work with this driver */
static struct usb_device_id dnw_table[] = {
    { USB_DEVICE(USB_VM_VENDOR_ID, USB_VM_PRODUCT_ID) },
    { }                    /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dnw_table);

/* Get a minor range for your devices from the usb maintainer */
#define USB_VM_MINOR_BASE    200

/* our private defines. if this grows any larger, use your own .h file */
#define DNW_BULK_SIZE        (PAGE_SIZE - 512)
/* MAX_TRANSFER is chosen so that the DNW is not stressed by
   allocations > PAGE_SIZE and the number of packets in a page
   is an integer 512 is the largest possible packet on EHCI */



/* Structure to hold all of our device specific stuff */
struct usb_dnw{
    struct usb_device    *udev;            /* the usb device for this device */
    struct usb_interface    *interface;        /* the interface for this device */
    struct semaphore    limit_sem;        /* limiting the number of writes in progress */
    struct usb_anchor    submitted;        /* in case we need to retract our submissions */
    unsigned char        *bulk_out_buffer;   
    __u8            bulk_out_endpointAddr;    /* the address of the bulk out endpoint */
    int            open_count;        /* count the number of openers */
    struct kref        kref;
    struct mutex        io_mutex;        /* synchronize I/O with disconnect */
    struct completion    write_completion;    /* to wait for an ongoing read */
};

#define to_skel_dev(d) container_of(d, struct usb_dnw, kref)

/*local function prototypes */

static struct usb_driver dnw_driver;

static void dnw_delete(struct kref *kref)
{
    struct usb_dnw *dev = to_skel_dev(kref);

    usb_put_dev(dev->udev);
    kfree(dev);
}

static int dnw_open(struct inode *inode, struct file *file)
{
    struct usb_dnw *dev = NULL;
    struct usb_interface *interface;
    int subminor;
    int retval = 0;

    subminor = iminor(inode);
    
    interface = usb_find_interface(&dnw_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;
    }

    /* increment our usage count for the device */
    kref_get(&dev->kref);

    /* lock the device to allow correctly handling errors
     * in rensumption */
    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, dnw_delete);
                goto exit;
            }
    }

    /* save our object in the file's private structure */
    file->private_data = dev;

    mutex_unlock(&dev->io_mutex);

exit:
    return retval;
}

static int dnw_release(struct inode *inode, struct file *file)
{
    struct usb_dnw *dev;

    dev = (struct usb_dnw *)file->private_data;
    if (dev == NULL)
        return -ENODEV;

    /* allow the device to be autosuspended */
    mutex_lock(&dev->io_mutex);

    if (!--dev->open_count && dev->interface)
        usb_autopm_put_interface(dev->interface);
    
    mutex_unlock(&dev->io_mutex);

    /* decrement the count on our device */
    kref_put(&dev->kref, dnw_delete);
    return 0;
}


static ssize_t dnw_read (struct file *file, char *buffer, size_t count, loff_t *ppos)
{
       return -EPERM;                                                           
}



static void dnw_write_bulk_callback(struct urb *urb)
{
    struct usb_dnw *dev;

    dev = urb->context;
    complete(&dev->write_completion);
}

static ssize_t dnw_write(struct file *file, const char *user_buffer,
              size_t count, loff_t *ppos)
{
    struct usb_dnw *dev;
    int retval = 0;
    size_t  writesize, wcount = 0;
    struct urb *urb = NULL;
    int err = 0, rv = 0;
    dev = (struct usb_dnw *)file->private_data;

    /* verify that we actually have some data to write */
    if (count == 0)
        goto exit;

    /*
     * limit the number of URBs in flight to stop a user from using up all
     * RAM
     */
    down(&dev->limit_sem);
    /* create a urb, and a buffer for it, and copy the data to the urb */
    
    urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!urb) {
         retval = -ENOMEM;
         goto error;
     }

    /*create a urb buffer*/
    dev->bulk_out_buffer = usb_alloc_coherent(dev->udev, DNW_BULK_SIZE, GFP_KERNEL,
                               &urb->transfer_dma);
    if (!dev->bulk_out_buffer) {
        retval = -ENOMEM;
        goto error;
    }
    
    while( count > 0 ) {
        
    init_completion(&dev->write_completion);
    
    memset(dev->bulk_out_buffer, 0, DNW_BULK_SIZE);
    
    writesize = min(count, (size_t)DNW_BULK_SIZE);
    
    if (copy_from_user(dev->bulk_out_buffer, user_buffer, writesize)) {
        retval = -EFAULT;
        err++;
        break;
    }

    /* 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;
        err++;
        break;
    }

    /* initialize the urb properly */
    usb_fill_bulk_urb(urb, dev->udev,
              usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
              dev->bulk_out_buffer, writesize, dnw_write_bulk_callback, dev);
    
    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    usb_anchor_urb(urb, &dev->submitted);

    /* send the data out the bulk port */
    retval = usb_submit_urb(urb, GFP_KERNEL);
    
    if (retval) {
        err("%s - failed submitting write urb, error %d", __func__,
            retval);
        rv = -1;
        break;

    }

    wait_for_completion(&dev->write_completion);
    
    mutex_unlock(&dev->io_mutex);
    
    /*
     * release our reference to this urb, the USB core will eventually free
     * it entirely
     */
    user_buffer += writesize;
    count -= writesize;
     wcount += writesize;
     }

    if (err)
        goto error;
    if (rv)
        goto error_unanchor;

    if (dev->bulk_out_buffer != NULL) {
        usb_free_coherent(urb->dev, DNW_BULK_SIZE,
                            dev->bulk_out_buffer, urb->transfer_dma);
    }

    usb_free_urb(urb);
    up(&dev->limit_sem);
    
    return wcount;

error_unanchor:
    usb_unanchor_urb(urb);
error:
    if (urb) {
         if (dev->bulk_out_buffer != NULL){
             usb_free_coherent(urb->dev, DNW_BULK_SIZE,
                         dev->bulk_out_buffer, urb->transfer_dma);
        }
        usb_free_urb(urb);
    }
    up(&dev->limit_sem);

exit:
    return retval;
}
static const struct file_operations dnw_fops = {
    .owner =    THIS_MODULE,
    .read =        dnw_read,
    .write =    dnw_write,
    .open =        dnw_open,
    .release =    dnw_release,
};

/*
 * usb class driver info in order to get a minor number from the usb core,
 * and to have the device registered with the driver core
 */
static struct usb_class_driver dnw_class = {
    .name =        "dnw%d",
    .fops =        &dnw_fops,
    .minor_base =    USB_VM_MINOR_BASE,
};

static int dnw_probe(struct usb_interface *interface,
              const struct usb_device_id *id)
{
    struct usb_dnw *dev;
    struct usb_host_interface *iface_desc;
    struct usb_endpoint_descriptor *endpoint;
    int i;
    int retval = -ENOMEM;

    /* allocate memory for our device state and initialize it */
    dev = kzalloc(sizeof(struct usb_dnw), GFP_KERNEL);
    if (dev == NULL) {
        err("Out of memory");
        goto error;
    }
    kref_init(&dev->kref);
    sema_init(&dev->limit_sem, 8);
    mutex_init(&dev->io_mutex);
    init_usb_anchor(&dev->submitted);

    dev->udev = usb_get_dev(interface_to_usbdev(interface));
    dev->interface = interface;

    /* set up the endpoint information */
    /* use only the first bulk-out endpoints */
    iface_desc = interface->cur_altsetting;
    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
        endpoint = &iface_desc->endpoint[i].desc;

        if (usb_endpoint_is_bulk_out(endpoint)) {
            /* we found a bulk out endpoint */
                        dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
        }


          }
    if (!dev->bulk_out_endpointAddr) {
        err("Could not find both bulk-out endpoints");
        goto error;
}
    /* save our data pointer in this interface device */
    usb_set_intfdata(interface, dev);

    /* we can register the device now, as it is ready */
    retval = usb_register_dev(interface, &dnw_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 TQ2440 device now attached to DNW-%d",
         interface->minor);

    return 0;

error:
    if (dev)
        /* this frees allocated memory */
        kref_put(&dev->kref, dnw_delete);
    return retval;
}

static void dnw_disconnect(struct usb_interface *interface)
{
    struct usb_dnw *dev;
    int minor = interface->minor;

    dev = usb_get_intfdata(interface);
    usb_set_intfdata(interface, NULL);

    /* give back our minor */
    usb_deregister_dev(interface, &dnw_class);

    /* prevent more I/O from starting */
    mutex_lock(&dev->io_mutex);
    dev->interface = NULL;
    mutex_unlock(&dev->io_mutex);

    usb_kill_anchored_urbs(&dev->submitted);

    /* decrement our usage count */
    kref_put(&dev->kref, dnw_delete);

    dev_info(&interface->dev, "USB DNW  #%d now disconnected", minor);
}

static struct usb_driver dnw_driver = {
    .name =        "dnw",
    .probe =    dnw_probe,
    .disconnect =    dnw_disconnect,
    .id_table =    dnw_table,
    .supports_autosuspend = 1,

};

static int __init usb_dnw_init(void)
{
    int result;

    /* register this driver with the USB subsystem */
    result = usb_register(&dnw_driver);
    printk(KERN_ALERT"usb dnw init\n");
    if (result)
        err("usb_register failed. Error number %d", result);
    return result;
}

static void __exit usb_dnw_exit(void)
{
    /* deregister this driver with the USB subsystem */
    usb_deregister(&dnw_driver);
    printk(KERN_ALERT"usb dnw exit\n");
}

module_init(usb_dnw_init);
module_exit(usb_dnw_exit);

MODULE_LICENSE("GPL");

 

以下是下载的应用程序:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
const char* dev = "/dev/dnw0";


int main(int argc, char* argv[])
{
    time_t tm1,tm2;
    unsigned char* file_buffer = NULL;
    if( 2 != argc )
    {
        printf("Usage: dwn <filename>\n");
        return 1;
    }

    int fd = open(argv[1], O_RDONLY);
    if(-1 == fd)
    {
        printf("Can not open file - %s\n", argv[1]);
        return 1;
    }

    struct stat file_stat;
    if( -1 == fstat(fd, &file_stat) )
    {
        printf("Get file size filed!\n");
        return 1;
    }    
    
    file_buffer = (char*)malloc(file_stat.st_size+10);
    if(NULL == file_buffer)
    {
        printf("malloc failed!\n");
        goto error;
    }
    if( file_stat.st_size !=  read(fd, file_buffer+8, file_stat.st_size))
    {
        printf("Read file failed!\n");
        goto error;
    }

    printf("file name : %s\n", argv[1]);
    printf("file size : %d bytes\n", file_stat.st_size);

    int fd_dev = open(dev, O_WRONLY);
    if( -1 == fd_dev)
    {
        printf("Can not open %s\n", dev);
        goto error;
    }
    
    *((unsigned long*)file_buffer) = 0x30000000;     //load address
    *((unsigned long*)file_buffer+1) = file_stat.st_size+10;    //file size
    unsigned short sum = 0;
    int i;
    for(i=8; i<file_stat.st_size+8; i++)
    {
        sum += file_buffer[i];
    }
    
    printf("Writing data...\n");
    size_t remain_size = file_stat.st_size+10;
    size_t block_size = remain_size / 100;
    size_t writed = 0;
    time(&tm1);
    while(remain_size>0)
    {
        size_t to_write = remain_size > block_size ? block_size:remain_size;
        if( to_write != write(fd_dev, file_buffer+writed, to_write))
        {
            printf("failed!\n");
            return 1;
        }
        remain_size -= to_write;
        writed += to_write;
        printf("\r%d%\t %d bytes     ", writed*100/(file_stat.st_size+10), writed);
        fflush(stdout);
        
    }    
    time(&tm2);
    if (tm2-tm1 > 0)
        printf("Donwload %d Bytes at %dBps\n",writed,writed/(tm2-tm1));
    return 0;

error:
    if(-1!=fd_dev) close(fd_dev);
    if(fd != -1) close(fd);
    if( NULL!=file_buffer )
        free(file_buffer);
    return -1;

}

 

gcc -o dnw dnw.c

将dnw 复制到/usr/bin/目录下

source /etc/envirment

实测效果:

root@xzwang-mei:opt# dnw romfs.bin

file name : romfs.bin
file size : 3043392 bytes
Writing data...
100%     3043402 bytes     Donwload 3043402 Bytes at 507233Bps

500K左右的速度,虽然比网络差远了。。还讲究用

把源嘛传百度文库

链接

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值