免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1385 | 回复: 0
打印 上一主题 下一主题

给DP-1581开发板写了个Linux下的USB驱动 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-08-27 19:06 |只看该作者 |倒序浏览
    DP-1581是一款USB2.0开发开发套件,处理器为Philips的增强型51单片机P89C61x2,USB接口芯片为Philips的ISP1581。板子的相关资料见
http://www.zlgmcu.com/tools/kaifaban/dp-1581.asp

1 固件部分
    固件是USB客户端设备上工作的程序,一般运行在单片机上,控制USB接口芯片实现USB协议第9章规定的各种标准和厂商请求以及传输数据。这里使用开发板自带的一个固件程序“USB按键、时钟演示程序”,本固件里除了控制端点外提供了4个usb端点,中断IN和OUT以及批量IN和OUT端点,读取板子上的按键并通过中断IN端点usb传给主机,读取中断OUT端点数据并输出到LED显示。本文中修改为都是用批量传输。固件工程使用Keil C开发,对原始固件修改如下:
CODE:
kernel.c中
94行改为read_endpoint(4,8,Endpt_FIFO);
107行改为write_endpoint(5,4,Endpt_FIFO);编译后下载进单片机即可。
2 驱动部分
    驱动基于2.6.13内核。内核存在一个叫做USB Core的子系统,提供一组API支持USB主控制器和设备,见图1(来自Programming Guide for Linux USB Device Drivers)。具体API及USB设备驱动开发参考LDD3第13章(附件中带)。


图片附件
: [USB Core API]
未命名.JPG
(2006-8-7 00:13, 11.75 K)

                                     图1
    内核为USB驱动的开发提供了一个框架\drivers\usb\usb-skeleton.c。里面使用批量传输,不用修改即可使用,本文里已知固件里的端点信息,对驱动的probe函数做了简化。代码如下:
CODE:
/*isp1581.c
* based on  USB Skeleton driver - 2.0 by xdkui
*
*
* This driver is based on the 2.6.3 version of drivers/usb/usb-isp1581eton.c
* but has been rewritten to be easy to read and use, as no locks are now
* needed anymore.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define USB_SKEL_VENDOR_ID        0x04cc  //厂商ID
#define USB_SKEL_PRODUCT_ID        0x1b49  //产品ID
static struct usb_device_id isp1581_table [] = {
        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
        { }                                       
};
MODULE_DEVICE_TABLE (usb, isp1581_table);
/* Get a minor range for your devices from the usb maintainer */
#define USB_ISP1581_MINOR_BASE        192  //USB次设备号,每个驱动分配16个次设备号
/* Structure to hold all of our device specific stuff */
struct usb_isp1581 {
        struct usb_device *        udev;                        /* the usb device for this device */
        struct usb_interface *        interface;                /* the interface for this device */
        unsigned char *                bulk_in_buffer;                /* the buffer to receive data */
        size_t                        bulk_in_size;                /* the size of the receive buffer */
        __u8                        bulk_in_endpointAddr;        /* the address of the bulk in endpoint */
        __u8                        bulk_out_endpointAddr;        /* the address of the bulk out endpoint */
        struct kref                kref;
};
#define to_isp1581_dev(d) container_of(d, struct usb_isp1581, kref)
static struct usb_driver isp1581_driver;
static void isp1581_delete(struct kref *kref)
{        
        struct usb_isp1581 *dev = to_isp1581_dev(kref);
        usb_put_dev(dev->udev);
        kfree (dev->bulk_in_buffer);
        kfree (dev);
}
static int isp1581_open(struct inode *inode, struct file *file)
{
        struct usb_isp1581 *dev;
        struct usb_interface *interface;
        int subminor;
        int retval = 0;
        subminor = iminor(inode);
        interface = usb_find_interface(&isp1581_driver, subminor);
        if (!interface) {
                err ("%s - error, can't find device for minor %d",
                     __FUNCTION__, 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);
        /* save our object in the file's private structure */
        file->private_data = dev;
exit:
        return retval;
}
static int isp1581_release(struct inode *inode, struct file *file)
{
        struct usb_isp1581 *dev;
        dev = (struct usb_isp1581 *)file->private_data;
        if (dev == NULL)
                return -ENODEV;
        kref_put(&dev->kref, isp1581_delete);
        return 0;
}
static ssize_t isp1581_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
//通过批量传输读取开发板上的按键
{
        struct usb_isp1581 *dev;
        int retval = 0;
        int bytes_read;
        printk(KERN_ERR "enter isp1581_read\n");
        dev = (struct usb_isp1581 *)file->private_data;
        
        /* do a blocking bulk read to get data from the device */
        retval = usb_bulk_msg(dev->udev,
                              usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
                              dev->bulk_in_buffer,
                              min(dev->bulk_in_size, count),
                              &bytes_read, 5*HZ);
        if (!retval) {
                if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
                        retval = -EFAULT;
                else
                        retval = bytes_read;
        }
        return retval;
}
static void isp1581_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
//写操作的回掉函数,在中断环境下被调用
{
        struct usb_isp1581 *dev;
        dev = (struct usb_isp1581 *)urb->context;
        /* sync/async unlink faults aren't errors */
        if (urb->status &&
            !(urb->status == -ENOENT ||
              urb->status == -ECONNRESET ||
              urb->status == -ESHUTDOWN)) {
                dbg("%s - nonzero write bulk status received: %d",
                    __FUNCTION__, urb->status);
        }
        /* free up our allocated buffer */
        usb_buffer_free(urb->dev, urb->transfer_buffer_length,
                        urb->transfer_buffer, urb->transfer_dma);
}
static ssize_t isp1581_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
//分配urb,填充并提交给USB core
{
        struct usb_isp1581 *dev;
        int retval = 0;
        struct urb *urb = NULL;
        char *buf = NULL;
        dev = (struct usb_isp1581 *)file->private_data;
        if (count == 0)
                goto exit;
        /* 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;
        }
        buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
        if (!buf) {
                retval = -ENOMEM;
                goto error;
        }
        if (copy_from_user(buf, user_buffer, count)) {
                retval = -EFAULT;
                goto error;
        }
        /* initialize the urb properly */
        usb_fill_bulk_urb(urb, dev->udev,
                          usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
                          buf, count, isp1581_write_bulk_callback, dev);
        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        /* send the data out the bulk port */
        retval = usb_submit_urb(urb, GFP_KERNEL);
        if (retval) {
                err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
                goto error;
        }
        /* release our reference to this urb, the USB core will eventually free it entirely */
        usb_free_urb(urb);
exit:
        return count;
error:
        usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
        usb_free_urb(urb);
        return retval;
}
static struct file_operations isp1581_fops = {
        .owner =        THIS_MODULE,
        .read =                isp1581_read,
        .write =        isp1581_write,
        .open =                isp1581_open,
        .release =        isp1581_release,
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with devfs and the driver core
*/
static struct usb_class_driver isp1581_class = {
        .name =                "isp1581",
        .fops =                &isp1581_fops,
        .mode =                S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
        .minor_base =        USB_ISP1581_MINOR_BASE,
};
static int isp1581_probe(struct usb_interface *interface, const struct usb_device_id *id)
//当有厂商ID,产品ID和USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID匹配的时//候本函数被USB Core调用
{
        struct usb_isp1581 *dev = NULL;
        /*struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
        size_t buffer_size;
        int i;*/
        int retval = -ENOMEM;
        /* allocate memory for our device state and initialize it */
        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                err("Out of memory");
                goto error;
        }
        memset(dev, 0x00, sizeof(*dev));
        kref_init(&dev->kref);
        dev->udev = usb_get_dev(interface_to_usbdev(interface));
        dev->interface = interface;
        /* set up the endpoint information */
        /* use only the first bulk-in and bulk-out endpoints */
        //do not search, i know the bulk addr, see Keil C program...
        dev->bulk_in_endpointAddr=0x82;//批量输入端点
        dev->bulk_out_endpointAddr=0x02;//批量输出端点
        dev->bulk_in_size = 64;
        dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL);
        if (!dev->bulk_in_buffer) {
                err("Could not allocate bulk_in_buffer");
                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, &isp1581_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 */
        info("USB ISP1581 device now attached to -%d", interface->minor);
        return 0;
error:
        if (dev)
                kref_put(&dev->kref, isp1581_delete);
        return retval;
}
static void isp1581_disconnect(struct usb_interface *interface)
//设备断开时被调用
{
        struct usb_isp1581 *dev;
        int minor = interface->minor;
        /* prevent isp1581_open() from racing isp1581_disconnect() */
        lock_kernel();
        dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
        /* give back our minor */
        usb_deregister_dev(interface, &isp1581_class);
        unlock_kernel();
        /* decrement our usage count */
        kref_put(&dev->kref, isp1581_delete);
        info("ISP1581 #%d now disconnected", minor);
}
static struct usb_driver isp1581_driver = {
        .owner =        THIS_MODULE,
        .name =                "isp1581",
        .probe =        isp1581_probe,
        .disconnect =        isp1581_disconnect,
        .id_table =        isp1581_table,
};
static int __init usb_isp1581_init(void)
{
        int result;
        /* register this driver with the USB subsystem */
        result = usb_register(&isp1581_driver);
        if (result)
                err("usb_register failed. Error number %d", result);
        return result;
}
static void __exit usb_isp1581_exit(void)
{
        /* deregister this driver with the USB subsystem */
        usb_deregister(&isp1581_driver);
}
module_init (usb_isp1581_init);
module_exit (usb_isp1581_exit);
MODULE_LICENSE("GPL");3 用户态测试程序
    首先建立设备文件mknod /dev/usb/isp1581 c 180 192。然后运行本程序通过USB读写数据。如:
CODE:
#test r   读取开发板的按键信息并显示
#test w 12345678   则写8个数字到开发板并显示在LED。代码如下:
CODE:
/*user mode program for test isp1581 driver
*first make a dev node
* #mknod /dev/usb/isp1581 c 180 192
*/
#include
#include
#include
void usage(char * name)
{
        printf("Usage:%s {r|w num}\n",name);
        printf("\tr\tread 8 bytes from isp1581\n");
        printf("\tw\twrite 8 bytes(num) to isp1581\n");
}
void str2num(char * str,char * num,int n)
{
        int i=0;
        bzero(num,n);
        while(n && *str)
        {
                char c=*str;
                if(c='0')
                        num=c-'0';
                else if(c='a')
                        num=c-'a'+10;
                else if(c='A')
                        num=c-'A'+10;
                else
                        num=0;
                n--;
                str++;
                i++;
        }
}
int main(int argc,char **argv)
{
        int fd=0;
        unsigned char buf[8];
        int i,len=0;
        if(argc4 Makefile
Makefile如下:
CODE:
obj-m        := isp1581.o
KERNELDIR ?=/usr/src/linux-2.6.13
PWD       := $(shell pwd)
all:
        $(MAKE) -C $(KERNELDIR) M=$(PWD)
        $(CC) -o test test.c
clean:
        rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions testmake后生成isp1581.ko和test。安装模块,插入DP-1581开发板,运行test程序即可。
5 附件
    附件里包括单片机固件,isp1581_linux目录包括驱动和测试程序,Linux下USB驱动开发教程。如有任何指点,感激不尽。

文件:
isp1581.rar
大小:
861KB
下载:
下载


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/3130/showart_161224.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP