当前位置:   article > 正文

USB驱动程序设计(5)—USB下载线驱动设计_usb设备驱动设计 教程

usb设备驱动设计 教程

1.模块代码的初始化函数和退出函数

  1. static struct usb_driver dnw_driver =
  2. {
  3. .name = "dnw", /* 驱动名 */
  4. .probe = dnw_probe, /* 捕获函数 */
  5. .disconnect = dnw_disconnect, /* 卸载函数 */
  6. .id_table = dnw_id_table, /* 设备列表 */
  7. };
  8. int dnw_init()
  9. {
  10. usb_register(&dnw_driver);
  11. return 0;
  12. }
  13. void dnw_exit()
  14. {
  15. usb_deregister(&dnw_driver);
  16. }
  17. module_init(dnw_init);
  18. module_exit(dnw_exit);
  19. MODULE_LICENSE("GPL");
  • 初始化函数里面注册一个USB驱动,退出函数里面注销一个USB驱动。

2.实现id_table

  • 接下来实现最简单的id_table,首先我们需要知道USB设备的2个ID,把USB设备插入到PC机中,然后使用lsusb可以查看到所有的USB设备的ID。找到和当前设备对应的即可。
  1. static struct usb_device_id dnw_id_table [] =
  2. {
  3. { USB_DEVICE(0x5345, 0x1234) },
  4. { }
  5. };

3.probe函数

  • 对于之前我们分析的鼠标驱动程序,它是围绕URB和输入设备来展开。我们这里的下载器,显然也需要URB,但它是一个什么样的设备呢?其实它是一个字符类设备,我么需要在操作系统里面实现读和写的代码。而对于URB的初始化函数,不同的传输需要用不同的初始化函数,我们这里的下载器显然就是一个批量传输的设备了。
  • 对于一个批量传输的设备,它的URB创建、初始化、提交可以通过一个函数来完成,就是usb_bulk_msg这个函数。那么这个函数在哪实现了?一般是放在写函数里面实现的,因为作为一个USB下载器来讲,只有当真正要下载东西,写数据的时候,才有必要提交这么一个URB。
  • 所以probe函数里面只需要完成字符设备的初始化,对于字符设备的初始化可以使用cdev来实现。对于USB的字符设备,内核还提供了这么一个函数来实现,就是usb_register_dev函数,我们可以在内核里面搜索这个函数学习它的用法。它的原型是这个样子的:
  1. int usb_register_dev(struct usb_interface *intf,
  2. struct usb_class_driver *class_driver)
  • 它的第一个参数是USB设备的接口,我们可以通过probe的参数来拿到,第二个参数是class_driver,它里面包含了字符设备的名字,函数操作集等等:
  1. static struct usb_class_driver dnw_class =
  2. {
  3. .name = "dnw%d", // 设备文件名字
  4. .fops = &dnw_ops, // 函数操作集
  5. .minor_base = 100, // 次设备号,字符设备的主设备号为固定的180
  6. };
  • 接下来实现dnw_ops,即操作函数集,因为它不需要读,因此实现写即可。
  1. static const struct file_operations dnw_fops =
  2. {
  3. .owner = THIS_MODULE,
  4. .write = dnw_write,
  5. .open = dnw_open,
  6. .release = dnw_release,
  7. };
  • 这些打开,写操作函数我们可能不知道它的函数原型,怎么办呢?当然是从Linux代码中找呀。
  • 先来构思dnw_write函数,之前提到的usb_bulk_msg函数,不仅实现URB操作,它还能把用户的数据写入USB设备中。
  1. #define BULKOUT_BUFFER_SIZE 512
  2. char *bulkout_buffer;
  3. static int dnw_open(struct inode* inode, struct file *file)
  4. {
  5. // 为这个buffer分配空间,大小为512个字节
  6. bulkout_buffer = kmalloc(BULKOUT_BUFFER_SIZE,GFP_KERNEL);
  7. return 0;
  8. }
  9. static int dnw_release (struct inode* inode, struct file *file)
  10. {
  11. // 这里面释放buffer的空间
  12. kfree(bulkout_buffer);
  13. return 0;
  14. }
  15. static ssize_t dnw_write(struct file *file, const char __user *buf, size_t len, loff_t *pos)
  16. {
  17. size_t to_write;
  18. size_t total_write = 0;
  19. size_t act_len;
  20. while(len>0)
  21. {
  22. // 计算这次需要拷贝的数据量
  23. to_write = min(len,(size_t)BULKOUT_BUFFER_SIZE);
  24. /* 把用户空间的数据分批拷贝到内核中
  25. * buffer的内存分配可以在open函数中完成
  26. * buffer的释放在release中完成
  27. */
  28. copy_from_user(bulkout_buffer,buf+total_write,to_write);
  29. // 提交URB
  30. usb_bulk_msg(udev,usb_sndbulkpipe(udev,bulk_out_endaddr),bulkout_buffer,to_write,&act_len,3*HZ);
  31. // 更新数据量
  32. len -= to_write;
  33. total_write += to_write;
  34. }
  35. return total_write;
  36. }

4.源代码

  • 驱动代码
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/usb.h>
  4. #include <linux/fs.h>
  5. #include <linux/uaccess.h>
  6. #include <linux/slab.h>
  7. #define BULKOUT_BUFFER_SIZE 512
  8. char *bulkout_buffer;
  9. struct usb_device *udev;
  10. __u8 bulk_out_endaddr;
  11. static struct usb_device_id dnw_id_table [] =
  12. {
  13. { USB_DEVICE(0x5345, 0x1234) },
  14. { }
  15. };
  16. static int dnw_open(struct inode* inode, struct file *file)
  17. {
  18. // 为这个buffer分配空间,大小为512个字节
  19. bulkout_buffer = kmalloc(BULKOUT_BUFFER_SIZE, GFP_KERNEL);
  20. return 0;
  21. }
  22. static int dnw_release(struct inode* inode, struct file *file)
  23. {
  24. // 这里面释放buffer的空间
  25. kfree(bulkout_buffer);
  26. return 0;
  27. }
  28. static ssize_t dnw_write(struct file *file, const char __user *buf, size_t len, loff_t *pos)
  29. {
  30. size_t to_write;
  31. size_t total_write = 0; // 已经发送的数据量
  32. size_t act_len;
  33. while (len > 0)
  34. {
  35. // 计算这次需要拷贝的数据量
  36. to_write = min(len, (size_t)BULKOUT_BUFFER_SIZE);
  37. /* 把用户空间的数据分批拷贝到内核中
  38. * buffer的内存分配可以在open函数中完成
  39. * buffer的释放在release中完成
  40. */
  41. copy_from_user(bulkout_buffer, buf + total_write, to_write);
  42. // 提交URB
  43. usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_endaddr), bulkout_buffer, to_write, &act_len, 3 * HZ);
  44. // 更新数据量
  45. len -= to_write;
  46. total_write += to_write;
  47. }
  48. return total_write;
  49. }
  50. static const struct file_operations dnw_fops =
  51. {
  52. .owner = THIS_MODULE,
  53. .write = dnw_write,
  54. .open = dnw_open,
  55. .release = dnw_release,
  56. };
  57. static struct usb_class_driver dnw_class =
  58. {
  59. .name = "dnw%d", // 设备文件名字
  60. .fops = &dnw_ops, // 函数操作集
  61. .minor_base = 100, // 次设备号,字符设备的主设备号为固定的180
  62. };
  63. static int dnw_probe(struct usb_interface *intf, const struct usb_device_id *id)
  64. {
  65. /* 接口设置描述 */
  66. struct usb_host_interface *interface;
  67. struct usb_endpoint_descriptor *endpoint;
  68. int i;
  69. // 获取当前的接口设置
  70. interface = intf->cur_altsetting;
  71. for (i = 0; i < interface->desc.bNumEndpoints; i++)
  72. {
  73. endpoint = &interface->endpoint[i].desc;
  74. if (usb_endpoint_is_bulk_out(endpoint))
  75. {
  76. bulk_out_endaddr = endpoint->bEndpointAddress;
  77. break;
  78. }
  79. }
  80. usb_register_dev(intf, &dnw_class);
  81. udev = usb_get_dev(interface_to_usbdev(intf));
  82. return 0;
  83. }
  84. static void dnw_disconnect(struct usb_interface *intf)
  85. {
  86. usb_deregister_dev(intf,&dnw_class);
  87. }
  88. static struct usb_driver dnw_driver =
  89. {
  90. .name = "dnw", /* 驱动名 */
  91. .probe = dnw_probe, /* 捕获函数 */
  92. .disconnect = dnw_disconnect, /* 卸载函数 */
  93. .id_table = dnw_id_table, /* 设备列表 */
  94. };
  95. int dnw_init()
  96. {
  97. usb_register(&dnw_driver);
  98. return 0;
  99. }
  100. void dnw_exit()
  101. {
  102. usb_deregister(&dnw_driver);
  103. }
  104. module_init(dnw_init);
  105. module_exit(dnw_exit);
  106. MODULE_LICENSE("GPL");
  • 测试代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <malloc.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <string.h>
  9. const char* dev = "/dev/dnw0";
  10. int main(int argc, char* argv[])
  11. {
  12. unsigned char* file_buffer = NULL;
  13. long int addr = 0;
  14. if( 3 != argc )
  15. {
  16. printf("Usage: dwn <filename> address\n");
  17. return 1;
  18. }
  19. int fd = open(argv[1], O_RDONLY);
  20. if(-1 == fd)
  21. {
  22. printf("Can not open file - %s\n", argv[1]);
  23. return 1;
  24. }
  25. addr = strtol((char *) argv[2] ,NULL, 16);
  26. printf("addr = %x \n", addr);
  27. // get file size
  28. struct stat file_stat;
  29. if( -1 == fstat(fd, &file_stat) )
  30. {
  31. printf("Get file size filed!\n");
  32. return 1;
  33. }
  34. file_buffer = (unsigned char*)malloc(file_stat.st_size+10);
  35. if(NULL == file_buffer)
  36. {
  37. printf("malloc failed!\n");
  38. goto error;
  39. }
  40. //memset(file_buffer, '\0', sizeof(file_buffer)); // bad code ! corrected by Qulory
  41. memset(file_buffer, '\0', sizeof(char)*(file_stat.st_size+10));
  42. // the first 8 bytes in the file_buffer is reserved, the last 2 bytes also;
  43. if( file_stat.st_size != read(fd, file_buffer+8, file_stat.st_size))
  44. {
  45. printf("Read file failed!\n");
  46. goto error;
  47. }
  48. printf("File name : %s\n", argv[1]);
  49. printf("File size : %ld bytes\n", file_stat.st_size);// off_t is long int
  50. int fd_dev = open(dev, O_WRONLY);
  51. if( -1 == fd_dev) {
  52. printf("Can not open %s\n", dev);
  53. goto error;
  54. }
  55. /*
  56. * Note: the first 4 bytes store the dest addr ;
  57. * the following 4 bytes store the file size ;
  58. * and the last 2 bytes store the sum of each bytes of the file ;
  59. */
  60. *((unsigned long*)file_buffer) = addr; //load address
  61. *((unsigned long*)file_buffer+1) = file_stat.st_size+10; //file size
  62. unsigned short sum = 0;
  63. int i;
  64. for(i=8; i<file_stat.st_size+8; i++)
  65. {
  66. sum += file_buffer[i];
  67. }
  68. *((unsigned short*)(file_buffer+8+file_stat.st_size)) = sum;
  69. printf("Start Sending data...\n");
  70. size_t remain_size = file_stat.st_size+10;
  71. size_t block_size = 512;
  72. size_t written = 0;
  73. while(remain_size > 0)
  74. {
  75. size_t to_write = remain_size > block_size ? block_size:remain_size;
  76. size_t real_write = write(fd_dev, file_buffer+written, to_write);
  77. if( to_write != real_write)
  78. {
  79. printf(" write /dev/secbulk0 failed! to_write = %u real_write = %u \n" , to_write ,real_write );
  80. return 1;
  81. }
  82. remain_size -= to_write;
  83. written += to_write;
  84. printf("\rSent %lu%% \t %u bytes !", written*100/(file_stat.st_size+10), written);
  85. fflush(stdout);
  86. }
  87. printf("OK\n");
  88. return 0;
  89. error:
  90. if(-1 != fd_dev)
  91. {
  92. close(fd_dev);
  93. }
  94. if(fd != -1)
  95. {
  96. close(fd);
  97. }
  98. if( NULL != file_buffer )
  99. {
  100. free(file_buffer);
  101. }
  102. return -1;
  103. }
  • Makefile
  1. KDIR = /lib/modules/`uname -r`/build
  2. PWD := $(shell pwd)
  3. obj-m := dnw_usb.o
  4. all:
  5. make -C $(KDIR) M=$(PWD) modules
  6. clean:
  7. rm -rf *.o *.ko *.ko.unsigned *.mod.c *.order *.symvers
  • 编译之后安装这个模块,然后编译应用代码,执行下载操作,查看是否下载成功。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/246902
推荐阅读
相关标签
  

闽ICP备14008679号