主机环境: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.binfile size : 3043392 bytes
Writing data...
100% 3043402 bytes Donwload 3043402 Bytes at 507233Bps
500K左右的速度,虽然比网络差远了。。还讲究用
把源嘛传百度文库
链接