Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1851126
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2388
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-21 22:26
个人简介

90后空巢老码农

文章分类

全部博文(184)

文章存档

2021年(26)

2020年(56)

2019年(54)

2018年(47)

2017年(1)

我的朋友

分类: LINUX

2018-04-07 16:34:01

Linux中驱动程序位于操作系统和硬件之间,是连接操作系统与硬件之间的纽带,今天我们就来向Linux中添加一个简单的FPGA字符驱动程序。

I. Linux字符驱动程序简介

在Linux中驱动程序分为字符驱动,块设备驱动,网络设备驱动三种,字符设备驱动是其中比较简单的一种。字符设备是指只能一个字节一个字节进行读写操作的设备,不能随机读取设备中的某一数据、读取数据要按照先后数据。

II.添加字符驱动程序的步骤


1. 获取字符设备号

在linux中我们通过cat /proc/devices 命令即可查看到各种设备以及其对应的设备编号。在内核中,我们通常用如下两个函数来获取设备编号


点击(此处)折叠或打开

  1. int register_chrdev_region(dev_t first, unsigned int count, char *name);
  2. /* 参数:
  3.     dev_t first - 要申请的设备号(起始)
  4.     unsigned int count - 要申请的设备号数量
  5.     const char *name - 设备名
  6.    返回值:
  7.     成功:0
  8.     失败:负数
  9.    需要事先知道哪个设备号没有被占用!!!
  10. */

点击(此处)折叠或打开

  1. int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
  2. /* 参数:
  3.     dev_t *dev - 用于保存分配到的第一个设备号(起始)
  4.     unsigned int firstminor - 起始次设备号
  5.     unsigned int count - 要分配设备号的数量
  6.     char *name - 设备名
  7.    返回值:
  8.     成功:0
  9.     失败:负数(绝对值是错误码)
  10.    不需要事先知道哪个设备号被占用,系统会根据实际情况自行分配
  11. */



2. 向cdev结构体注册文件操作

在Linux内核代码中,字符设备的描述通常是由struct cdev来完成的,其中有一个成员是一个指向file_operations的指针,我们将来想要像操作普通文件一样操作硬件设备,就需要完成file_operations中的.open, .read, .write, .release, .llseek函数,将它们映射成具体的硬件设备操作,如下代码所示


点击(此处)折叠或打开

  1. static const struct file_operations fpga_fops = {
  2.     .read        = fpga_read,
  3.     .write        = fpga_write,
  4.     .llseek = fpga_llseek,
  5.     .open        = fpga_open,
  6.     .release    = fpga_release,
  7. };
定义完文件操作之后,就需要将文件操作注册到cdev结构体之后就需要向内核注册设备驱动,代码如下:


点击(此处)折叠或打开

  1. cdev_init(&fpga_dev, &fpga_fops); /* initialize your device settings */

  2. ret = cdev_add(&fpga_dev, fpga_no, 1); /* register your device to the kernel */

III. FPGA地址映射以及读写通信

在我写的这个字符驱动程序中,我是用的ioremap()函数来实现地址映射,这里需要注意的是:要根据自己核心板的FPGA使能引脚和地址引脚来确定实际地址切不可盲目拷贝;copy_to_user()和copy_from_user()函数来实现FPGA的读写操作,具体见代码:


点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/fs.h>
  3. #include <linux/kernel.h>
  4. #include <linux/module.h>
  5. #include <linux/cdev.h>
  6. #include <linux/errno.h>
  7. #include <linux/device.h>

  8. #include <asm/io.h>
  9. #include <asm/uaccess.h>


  10. #define FPGA_BASE_ADDR 0xF0000000
  11. #define FPGA_SIZE 0x4000000
  12. #define DEV_NAME "fpga"

  13. struct cdev fpga_dev;
  14. dev_t fpga_no;
  15. struct class *fpga_class;


  16. static char *fpga_addr = NULL;

  17. static int fpga_open(struct inode *ino, struct file *filp);
  18. static int fpga_release(struct inode *ino, struct file *filp);
  19. static loff_t fpga_llseek(struct file *, loff_t, int);
  20. static ssize_t fpga_read(struct file *, char __user *, size_t, loff_t *);
  21. static ssize_t fpga_write(struct file *, const char __user *, size_t, loff_t *);

  22. static const struct file_operations fpga_fops = {
  23.     .read        = fpga_read,
  24.     .write        = fpga_write,
  25.     .llseek = fpga_llseek,
  26.     .open        = fpga_open,
  27.     .release    = fpga_release,
  28. };


  29. static int fpga_open(struct inode *ino, struct file *filp)
  30. {
  31.     return 0;
  32. }
  33. static int fpga_release(struct inode *ino, struct file *filp)
  34. {
  35.     return 0;
  36. }
  37. static loff_t fpga_llseek(struct file *file, loff_t off, int whence)
  38. {
  39.     if(fpga_addr)
  40.         iounmap(fpga_addr);
  41.     if(off <= FPGA_SIZE)
  42.         fpga_addr=ioremap(FPGA_BASE_ADDR+off,FPGA_SIZE-off);
  43.     return off;
  44. }
  45. static ssize_t fpga_read(struct file *file, char __user *buf, size_t count,
  46.             loff_t *ppos)
  47. {
  48.     printk("user data: %x", buf[0]);
  49.     printk("kern data: %x", fpga_addr[0]);
  50.     if(copy_to_user(buf, fpga_addr, count))
  51.         return -EFAULT;
  52.     
  53.     return count;
  54. }

  55. static ssize_t fpga_write(struct file *file, const char __user *buf,
  56.                         size_t count, loff_t *ppos)
  57. {
  58.     printk("user data: %x", buf[0]);
  59.     printk("kern data: %x", fpga_addr[0]);
  60.     if(copy_from_user(fpga_addr, buf, count))
  61.         return -EFAULT;
  62.     printk("kern data: %x", fpga_addr[0]);
  63.     return count;
  64. }
  65. static int __init fpga_init(void)
  66. {
  67.     int ret;
  68.     ret = alloc_chrdev_region(&fpga_no, 0, 1, "fpga"); /* device num you get, from where to allocate, num of this kind of device, device name */
  69.     if(ret)
  70.     {
  71.         printk("alloc_chrdev_region failed!\n");
  72.         unregister_chrdev_region(fpga_no, 1); /* first device number, num of this kind of device */
  73.         return ret;
  74.     }
  75.     else
  76.     {
  77.         printk("alloc_chrdev_region success!\n");
  78.     }

  79.     cdev_init(&fpga_dev, &fpga_fops); /* initialize your device settings */

  80.     ret = cdev_add(&fpga_dev, fpga_no, 1); /* register your device to the kernel */
  81.     if(ret)
  82.     {
  83.         printk("fpga dev add fail.\n");
  84.         unregister_chrdev_region(fpga_no, 1);
  85.         return ret;
  86.     }
  87.     else
  88.     {
  89.         printk("fpga dev add success!\n");
  90.     }
  91.     /* ==================add module to /dev/fpga=================== */
  92.     fpga_class = class_create(THIS_MODULE, "fpga");
  93.     device_create(fpga_class, NULL, fpga_no, NULL, "fpga");
  94.     /* ==================address mapping ===================== */
  95.     fpga_addr = ioremap(FPGA_BASE_ADDR, FPGA_SIZE);
  96.     if(fpga_addr)
  97.     {
  98.         printk("ioremap success~\n");
  99.     }
  100.     else
  101.     {
  102.         unregister_chrdev_region(fpga_no, 1);
  103.         return -ENODEV;
  104.     }
  105.     return 0;
  106. }
  107. static void __exit fpga_exit(void)
  108. {
  109.     if(fpga_addr)
  110.         iounmap(fpga_addr);
  111.     cdev_del(&fpga_dev);
  112.     unregister_chrdev_region(fpga_no, 1);
  113.     printk("fpga dev exit success!\n");
  114. }
  115. module_init(fpga_init);

将上述代码编入内核,便可使用cat /proc/devices 来看到fpga设备以及其设备号,并且可以在/dev/目录下查看到fpga啦~~~


阅读(17345) | 评论(0) | 转发(0) |
0

上一篇:浅析Kerberos协议

下一篇:堆排序简述

给主人留下些什么吧!~~