免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-08-07 00:11 |只看该作者 |倒序浏览
给DP-1581开发版写了个Linux下的USB驱动

    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开发,对原始固件修改如下:
  1. kernel.c中
  2. 94行改为read_endpoint(4,8,Endpt_FIFO);
  3. 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章(附件中带)。

                                     图1
      内核为USB驱动的开发提供了一个框架\drivers\usb\usb-skeleton.c。里面使用批量传输,不用修改即可使用,本文里已知固件里的端点信息,对驱动的probe函数做了简化。代码如下:
  1. /*isp1581.c
  2. * based on  USB Skeleton driver - 2.0 by xdkui
  3. *
  4. *
  5. * This driver is based on the 2.6.3 version of drivers/usb/usb-isp1581eton.c
  6. * but has been rewritten to be easy to read and use, as no locks are now
  7. * needed anymore.
  8. *
  9. */

  10. #include <linux/config.h>
  11. #include <linux/kernel.h>
  12. #include <linux/errno.h>
  13. #include <linux/init.h>
  14. #include <linux/slab.h>
  15. #include <linux/module.h>
  16. #include <linux/kref.h>
  17. #include <asm/uaccess.h>
  18. #include <linux/usb.h>


  19. #define USB_SKEL_VENDOR_ID        0x04cc  //厂商ID
  20. #define USB_SKEL_PRODUCT_ID        0x1b49  //产品ID

  21. static struct usb_device_id isp1581_table [] = {
  22.         { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
  23.         { }                                       
  24. };
  25. MODULE_DEVICE_TABLE (usb, isp1581_table);


  26. /* Get a minor range for your devices from the usb maintainer */
  27. #define USB_ISP1581_MINOR_BASE        192  //USB次设备号,每个驱动分配16个次设备号

  28. /* Structure to hold all of our device specific stuff */
  29. struct usb_isp1581 {
  30.         struct usb_device *        udev;                        /* the usb device for this device */
  31.         struct usb_interface *        interface;                /* the interface for this device */
  32.         unsigned char *                bulk_in_buffer;                /* the buffer to receive data */
  33.         size_t                        bulk_in_size;                /* the size of the receive buffer */
  34.         __u8                        bulk_in_endpointAddr;        /* the address of the bulk in endpoint */
  35.         __u8                        bulk_out_endpointAddr;        /* the address of the bulk out endpoint */
  36.         struct kref                kref;
  37. };
  38. #define to_isp1581_dev(d) container_of(d, struct usb_isp1581, kref)

  39. static struct usb_driver isp1581_driver;

  40. static void isp1581_delete(struct kref *kref)
  41. {       
  42.         struct usb_isp1581 *dev = to_isp1581_dev(kref);

  43.         usb_put_dev(dev->udev);
  44.         kfree (dev->bulk_in_buffer);
  45.         kfree (dev);
  46. }

  47. static int isp1581_open(struct inode *inode, struct file *file)
  48. {
  49.         struct usb_isp1581 *dev;
  50.         struct usb_interface *interface;
  51.         int subminor;
  52.         int retval = 0;

  53.         subminor = iminor(inode);

  54.         interface = usb_find_interface(&isp1581_driver, subminor);
  55.         if (!interface) {
  56.                 err ("%s - error, can't find device for minor %d",
  57.                      __FUNCTION__, subminor);
  58.                 retval = -ENODEV;
  59.                 goto exit;
  60.         }
  61.         dev = usb_get_intfdata(interface);
  62.         if (!dev) {
  63.                 retval = -ENODEV;
  64.                 goto exit;
  65.         }

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

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

  70. exit:
  71.         return retval;
  72. }

  73. static int isp1581_release(struct inode *inode, struct file *file)
  74. {
  75.         struct usb_isp1581 *dev;

  76.         dev = (struct usb_isp1581 *)file->private_data;
  77.         if (dev == NULL)
  78.                 return -ENODEV;

  79.         kref_put(&dev->kref, isp1581_delete);
  80.         return 0;
  81. }

  82. static ssize_t isp1581_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
  83. //通过批量传输读取开发板上的按键
  84. {
  85.         struct usb_isp1581 *dev;
  86.         int retval = 0;
  87.         int bytes_read;

  88.         printk(KERN_ERR "enter isp1581_read\n");
  89.         dev = (struct usb_isp1581 *)file->private_data;
  90.        
  91.         /* do a blocking bulk read to get data from the device */
  92.         retval = usb_bulk_msg(dev->udev,
  93.                               usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
  94.                               dev->bulk_in_buffer,
  95.                               min(dev->bulk_in_size, count),
  96.                               &bytes_read, 5*HZ);

  97.         if (!retval) {
  98.                 if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
  99.                         retval = -EFAULT;
  100.                 else
  101.                         retval = bytes_read;
  102.         }


  103.         return retval;
  104. }

  105. static void isp1581_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
  106. //写操作的回掉函数,在中断环境下被调用
  107. {
  108.         struct usb_isp1581 *dev;

  109.         dev = (struct usb_isp1581 *)urb->context;

  110.         /* sync/async unlink faults aren't errors */
  111.         if (urb->status &&
  112.             !(urb->status == -ENOENT ||
  113.               urb->status == -ECONNRESET ||
  114.               urb->status == -ESHUTDOWN)) {
  115.                 dbg("%s - nonzero write bulk status received: %d",
  116.                     __FUNCTION__, urb->status);
  117.         }

  118.         /* free up our allocated buffer */
  119.         usb_buffer_free(urb->dev, urb->transfer_buffer_length,
  120.                         urb->transfer_buffer, urb->transfer_dma);
  121. }

  122. static ssize_t isp1581_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
  123. //分配urb,填充并提交给USB core
  124. {
  125.         struct usb_isp1581 *dev;
  126.         int retval = 0;
  127.         struct urb *urb = NULL;
  128.         char *buf = NULL;

  129.         dev = (struct usb_isp1581 *)file->private_data;

  130.         if (count == 0)
  131.                 goto exit;

  132.         /* create a urb, and a buffer for it, and copy the data to the urb */
  133.         urb = usb_alloc_urb(0, GFP_KERNEL);
  134.         if (!urb) {
  135.                 retval = -ENOMEM;
  136.                 goto error;
  137.         }

  138.         buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
  139.         if (!buf) {
  140.                 retval = -ENOMEM;
  141.                 goto error;
  142.         }

  143.         if (copy_from_user(buf, user_buffer, count)) {
  144.                 retval = -EFAULT;
  145.                 goto error;
  146.         }

  147.         /* initialize the urb properly */
  148.         usb_fill_bulk_urb(urb, dev->udev,
  149.                           usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
  150.                           buf, count, isp1581_write_bulk_callback, dev);
  151.         urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

  152.         /* send the data out the bulk port */
  153.         retval = usb_submit_urb(urb, GFP_KERNEL);
  154.         if (retval) {
  155.                 err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
  156.                 goto error;
  157.         }

  158.         /* release our reference to this urb, the USB core will eventually free it entirely */
  159.         usb_free_urb(urb);

  160. exit:
  161.         return count;

  162. error:
  163.         usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
  164.         usb_free_urb(urb);
  165.         return retval;
  166. }

  167. static struct file_operations isp1581_fops = {
  168.         .owner =        THIS_MODULE,
  169.         .read =                isp1581_read,
  170.         .write =        isp1581_write,
  171.         .open =                isp1581_open,
  172.         .release =        isp1581_release,
  173. };

  174. /*
  175. * usb class driver info in order to get a minor number from the usb core,
  176. * and to have the device registered with devfs and the driver core
  177. */
  178. static struct usb_class_driver isp1581_class = {
  179.         .name =                "isp1581",
  180.         .fops =                &isp1581_fops,
  181.         .mode =                S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
  182.         .minor_base =        USB_ISP1581_MINOR_BASE,
  183. };

  184. static int isp1581_probe(struct usb_interface *interface, const struct usb_device_id *id)
  185. //当有厂商ID,产品ID和USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID匹配的时//候本函数被USB Core调用
  186. {
  187.         struct usb_isp1581 *dev = NULL;
  188.         /*struct usb_host_interface *iface_desc;
  189.         struct usb_endpoint_descriptor *endpoint;
  190.         size_t buffer_size;
  191.         int i;*/
  192.         int retval = -ENOMEM;

  193.         /* allocate memory for our device state and initialize it */
  194.         dev = kmalloc(sizeof(*dev), GFP_KERNEL);
  195.         if (dev == NULL) {
  196.                 err("Out of memory");
  197.                 goto error;
  198.         }
  199.         memset(dev, 0x00, sizeof(*dev));
  200.         kref_init(&dev->kref);

  201.         dev->udev = usb_get_dev(interface_to_usbdev(interface));
  202.         dev->interface = interface;

  203.         /* set up the endpoint information */
  204.         /* use only the first bulk-in and bulk-out endpoints */
  205.         //do not search, i know the bulk addr, see Keil C program...
  206.         dev->bulk_in_endpointAddr=0x82;//批量输入端点
  207.         dev->bulk_out_endpointAddr=0x02;//批量输出端点
  208.         dev->bulk_in_size = 64;
  209.         dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL);
  210.         if (!dev->bulk_in_buffer) {
  211.                 err("Could not allocate bulk_in_buffer");
  212.                 goto error;
  213.         }
  214.         /* save our data pointer in this interface device */
  215.         usb_set_intfdata(interface, dev);

  216.         /* we can register the device now, as it is ready */
  217.         retval = usb_register_dev(interface, &isp1581_class);
  218.         if (retval) {
  219.                 /* something prevented us from registering this driver */
  220.                 err("Not able to get a minor for this device.");
  221.                 usb_set_intfdata(interface, NULL);
  222.                 goto error;
  223.         }

  224.         /* let the user know what node this device is now attached to */
  225.         info("USB ISP1581 device now attached to -%d", interface->minor);
  226.         return 0;

  227. error:
  228.         if (dev)
  229.                 kref_put(&dev->kref, isp1581_delete);
  230.         return retval;
  231. }

  232. static void isp1581_disconnect(struct usb_interface *interface)
  233. //设备断开时被调用
  234. {
  235.         struct usb_isp1581 *dev;
  236.         int minor = interface->minor;

  237.         /* prevent isp1581_open() from racing isp1581_disconnect() */
  238.         lock_kernel();

  239.         dev = usb_get_intfdata(interface);
  240.         usb_set_intfdata(interface, NULL);

  241.         /* give back our minor */
  242.         usb_deregister_dev(interface, &isp1581_class);

  243.         unlock_kernel();

  244.         /* decrement our usage count */
  245.         kref_put(&dev->kref, isp1581_delete);

  246.         info("ISP1581 #%d now disconnected", minor);
  247. }

  248. static struct usb_driver isp1581_driver = {
  249.         .owner =        THIS_MODULE,
  250.         .name =                "isp1581",
  251.         .probe =        isp1581_probe,
  252.         .disconnect =        isp1581_disconnect,
  253.         .id_table =        isp1581_table,
  254. };

  255. static int __init usb_isp1581_init(void)
  256. {
  257.         int result;

  258.         /* register this driver with the USB subsystem */
  259.         result = usb_register(&isp1581_driver);
  260.         if (result)
  261.                 err("usb_register failed. Error number %d", result);

  262.         return result;
  263. }

  264. static void __exit usb_isp1581_exit(void)
  265. {
  266.         /* deregister this driver with the USB subsystem */
  267.         usb_deregister(&isp1581_driver);
  268. }

  269. module_init (usb_isp1581_init);
  270. module_exit (usb_isp1581_exit);

  271. MODULE_LICENSE("GPL");
复制代码

3 用户态测试程序
    首先建立设备文件mknod /dev/usb/isp1581 c 180 192。然后运行本程序通过USB读写数据。如:
  1. #test r   读取开发板的按键信息并显示
  2. #test w 12345678   则写8个数字到开发板并显示在LED。
复制代码

代码如下:
  1. /*user mode program for test isp1581 driver
  2. *first make a dev node
  3. * #mknod /dev/usb/isp1581 c 180 192
  4. */

  5. #include <stdio.h>
  6. #include <strings.h>
  7. #include <fcntl.h>
  8. void usage(char * name)
  9. {
  10.         printf("Usage:%s {r|w num}\n",name);
  11.         printf("\tr\tread 8 bytes from isp1581\n");
  12.         printf("\tw\twrite 8 bytes(num) to isp1581\n");
  13. }

  14. void str2num(char * str,char * num,int n)
  15. {
  16.         int i=0;
  17.         bzero(num,n);
  18.         while(n && *str)
  19.         {
  20.                 char c=*str;
  21.                 if(c<='9' && c>='0')
  22.                         num[i]=c-'0';
  23.                 else if(c<='f' && c>='a')
  24.                         num[i]=c-'a'+10;
  25.                 else if(c<='F' && c>='A')
  26.                         num[i]=c-'A'+10;
  27.                 else
  28.                         num[i]=0;

  29.                 n--;
  30.                 str++;
  31.                 i++;
  32.         }
  33. }

  34. int main(int argc,char **argv)
  35. {
  36.         int fd=0;
  37.         unsigned char buf[8];
  38.         int i,len=0;

  39.         if(argc<2)
  40.         {
  41.                 usage(argv[0]);
  42.                 return 0;
  43.         }

  44.         fd=open("/dev/usb/isp1581",O_RDWR);
  45.         if(fd==-1)
  46.         {
  47.                 perror("open error");
  48.                 return -1;
  49.         }

  50.         if(argv[1][0]=='r' && argc==2)
  51.         {       
  52.                 bzero(buf,sizeof(buf));
  53.                 len=read(fd,buf,sizeof(buf));
  54.                 if(len==-1)
  55.                         perror("read error");
  56.                 else
  57.                 {
  58.                         printf("readed %d bytes:",len);
  59.                         for(i=0;i<len;i++)
  60.                                 printf("%X\t",buf[i]);
  61.                         printf("\n");
  62.                 }
  63.         }
  64.         else if(argv[1][0]=='w' && argc==3)
  65.         {
  66.                 str2num(argv[2],buf,sizeof(buf));
  67.                 len=write(fd,buf,sizeof(buf));
  68.                 if(len==-1)
  69.                         perror("write error");
  70.                 else
  71.                         printf("wrote %d bytes\n",len);
  72.         }
  73.         else
  74.                 usage(argv[0]);

  75.         if(fd)
  76.                 close(fd);

  77.         return 0;


  78. }
复制代码


4 Makefile
Makefile如下:
  1. obj-m        := isp1581.o

  2. KERNELDIR ?=/usr/src/linux-2.6.13
  3. PWD       := $(shell pwd)

  4. all:
  5.         $(MAKE) -C $(KERNELDIR) M=$(PWD)
  6.         $(CC) -o test test.c

  7. clean:
  8.         rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions test
复制代码

    make后生成isp1581.ko和test。安装模块,插入DP-1581开发板,运行test程序即可。

5 附件
    附件里包括单片机固件,isp1581_linux目录包括驱动和测试程序,Linux下USB驱动开发教程。这几天正在写一个中断传输的驱动,完了再传上来。如有任何指点,感激不尽。

[ 本帖最后由 xdkui 于 2006-8-7 00:23 编辑 ]

usb.part1.rar

195.31 KB, 下载次数: 392

usb.part2.rar

195.31 KB, 下载次数: 342

usb.part3.rar

195.31 KB, 下载次数: 342

usb.part4.rar

195.31 KB, 下载次数: 357

usb.part5.rar

80.87 KB, 下载次数: 283

论坛徽章:
0
2 [报告]
发表于 2006-08-07 13:26 |只看该作者

先顶一个

偶最近也在看USB,顶一个先

论坛徽章:
0
3 [报告]
发表于 2006-08-07 16:43 |只看该作者
不错,支持一下,虽然现在没在做USB。,

论坛徽章:
0
4 [报告]
发表于 2008-08-22 11:23 |只看该作者

谢谢

太好了,非常感谢

论坛徽章:
8
2015年辞旧岁徽章
日期:2015-03-03 16:54:15午马
日期:2015-02-04 12:00:07羊年新春福章
日期:2015-02-04 11:57:56双子座
日期:2014-12-02 11:44:59金牛座
日期:2014-10-08 16:47:08狮子座
日期:2014-08-29 13:37:46巳蛇
日期:2014-08-26 17:32:29NBA常规赛纪念章
日期:2015-05-04 22:32:03
5 [报告]
发表于 2008-09-23 08:45 |只看该作者

回复 #1 xdkui 的帖子

支持 哈哈 好东西啊

论坛徽章:
0
6 [报告]
发表于 2008-09-23 10:32 |只看该作者

论坛徽章:
0
7 [报告]
发表于 2008-09-23 11:20 |只看该作者
支持楼主,学习中。。。

论坛徽章:
0
8 [报告]
发表于 2008-09-23 19:20 |只看该作者
51也跑linux了。不过还是学习了。

论坛徽章:
0
9 [报告]
发表于 2009-07-15 08:52 |只看该作者
学习了一下

论坛徽章:
0
10 [报告]
发表于 2009-07-15 09:00 |只看该作者

回复 #8 idreload 的帖子

谁说51跑Linux?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP