编写驱动程序需要编写那些代码:

1、硬件相关的驱动程序

2、Makefile的编译程序

3、还需要编写一个相关的测试程序

比如说:一个摄像头驱动程序

1、驱动程序的编写,需要编写一些硬件相关的操作,编译Makefile

2、安装、运行、卸载驱动程序(insmod ***、。./*** 、remod *** )。

3、使用这个驱动程序:需要一个测试程序,如QQ(测试程序)打开摄像头。

编写驱动程序框架:

APP:(测试程序)                         open         read         write         .........

-------------------------------------------------------------------------------------------

内核                                           sys_open    sys_read  sys_writ    sys_.......

-------------------------------------------------------------------------------------------

驱动程序                          入口函数:

注册一个结构体:register("  ",&file_operation);

/* 这里执行相关的硬件操作 */

struct   file_operation{

.open      =    open_,

.read       =    read_,

.write       =    write_,

}

出口函数:

----------------------------------------------------------------------------------------------------------------------------------------------------

驱动程序的编写步骤包括:

入口函数

static int first_drv_init(void)

{major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核}

出口函数

static void first_drv_exit(void)

{
  unregister_chrdev(major, "first_drv"); // 卸载

}

构造一个file_operation结构体

static struct file_operations first_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = first_drv_open,
.write = first_drv_write,
};

相关的修饰:让内核知道这是个特殊的函数,作为驱动用

module_init(first_drv_init);
module_exit(first_drv_exit);

在加上一个协议:应为Linux为开源的,所以要遵循一些协议

MODULE_LICENSE("GPL");

剩下的就是对结构体里面的open、read、write函数进行硬件操作,如open对硬件引脚的定义、设置,read读取硬件引脚寄存器的状态,如灯是开还是关,write就是对相关硬件寄存器的操作,比如对相关数据寄存器写0/1来控制LED灯的亮灭。

相关硬件操作:比如对于LED灯简单硬件操作而言

根据芯片手册、原理图、确定硬件,操作相关寄存器对设置相关的引脚。然后设置相关的数据寄存器对引脚的控制。

上层测试程序会调用open、read、write函数最终会调用到驱动程序file_opreation结果体里面的open、read、write函数进而对硬件如LED灯的点亮操作。

相关代码如下

fist_drv.c

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <asm/uaccess.h>
  7. #include <asm/irq.h>
  8. #include <asm/io.h>
  9. #include <asm/arch/regs-gpio.h>
  10. #include <asm/hardware.h>
  11.  
  12. static struct class *firstdrv_class;
  13. static struct class_device *firstdrv_class_dev;
  14.  
  15. volatile unsigned long *gpfcon = NULL;
  16. volatile unsigned long *gpfdat = NULL;
  17.  
  18. static int first_drv_open(struct inode *inode, struct file *file)
  19. {
  20. //printk("first_drv_open\n");
  21. /* 配置GPF4,5,6为输出 */
  22. *gpfcon &= ~((0x3<<(*)) | (0x3<<(*)) | (0x3<<(*)));
  23. *gpfcon |= ((0x1<<(*)) | (0x1<<(*)) | (0x1<<(*)));
  24. return ;
  25. }
  26.  
  27. static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
  28. {
  29. int val;
  30.  
  31. //printk("first_drv_write\n");
  32.  
  33. copy_from_user(&val, buf, count); // copy_to_user();
  34.  
  35. if (val == )
  36. {
  37. // 点灯
  38. *gpfdat &= ~((<<) | (<<) | (<<));
  39. }
  40. else
  41. {
  42. // 灭灯
  43. *gpfdat |= (<<) | (<<) | (<<);
  44. }
  45.  
  46. return ;
  47. }
  48.  
  49. static struct file_operations first_drv_fops = {
  50. .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  51. .open = first_drv_open,
  52. .write = first_drv_write,
  53. };
  54.  
  55. int major;
  56. static int first_drv_init(void)
  57. {
  58. major = register_chrdev(, "first_drv", &first_drv_fops); // 注册, 告诉内核
  59.  
  60. firstdrv_class = class_create(THIS_MODULE, "firstdrv");
  61.  
  62. firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, ), NULL, "xyz"); /* /dev/xyz */
  63.  
  64. gpfcon = (volatile unsigned long *)ioremap(0x56000050, );
  65. gpfdat = gpfcon + ;
  66.  
  67. return ;
  68. }
  69.  
  70. static void first_drv_exit(void)
  71. {
  72. unregister_chrdev(major, "first_drv"); // 卸载
  73.  
  74. class_device_unregister(firstdrv_class_dev);
  75. class_destroy(firstdrv_class);
  76. iounmap(gpfcon);
  77. }
  78.  
  79. module_init(first_drv_init);
  80. module_exit(first_drv_exit);
  81.  
  82. MODULE_LICENSE("GPL");

编写:Makefile

  1. KERN_DIR = /work/system/linux-2.6.22.6
  2.  
  3. all:
  4. make -C $(KERN_DIR) M=`pwd` modules
  5.  
  6. clean:
  7. make -C $(KERN_DIR) M=`pwd` modules clean
  8. rm -rf modules.order
  9.  
  10. obj-m += first_drv.o

编译成功后,把程序放到开发板文件系统目录下,执行insmod  文件名  装载驱动,运行驱动程序为./文件名   如果想卸载执行remod 文件名命令

测试程序:

firstdrvtest.c

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5.  
  6. /* firstdrvtest on
  7. * firstdrvtest off
  8. */
  9. int main(int argc, char **argv)
  10. {
  11. int fd;
  12. int val = ;
  13. fd = open("/dev/xyz", O_RDWR);
  14. if (fd < )
  15. {
  16. printf("can't open!\n");
  17. }
  18. if (argc != )
  19. {
  20. printf("Usage :\n");
  21. printf("%s <on|off>\n", argv[]);
  22. return ;
  23. }
  24.  
  25. if (strcmp(argv[], "on") == )
  26. {
  27. val = ;
  28. }
  29. else
  30. {
  31. val = ;
  32. }
  33.  
  34. write(fd, &val, );
  35. return ;
  36. }

字符设备驱动程序--LED驱动的更多相关文章

  1. 嵌入式Linux驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入

    字符设备驱动程序 应用程序是调用C库中的open read write等函数.而为了操作硬件,所以引入了驱动模块. 构建一个简单的驱动,有一下步骤. 1. 创建file_operations 2. 申 ...

  2. Linux驱动实践:你知道【字符设备驱动程序】的两种写法吗?

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  3. Linux 简单字符设备驱动程序 (自顶向下)

    第零章:扯扯淡 特此总结一下写的一个简单字符设备驱动程序的过程,我要强调一下“自顶向下”这个介绍方法,因为我觉得这样更容易让没有接触过设备驱动程序的童鞋更容易理解,“自顶向下”最初从<计算机网络 ...

  4. ARM Linux字符设备驱动程序

    1.主设备号和次设备号(二者一起为设备号): 一个字符设备或块设备都有一个主设备号和一个次设备号.主设备号用来标识与设备文件相连的驱动程序,用来反  映设备类型.次设备号被驱动程序用来辨别操作的是哪个 ...

  5. 浅析Linux字符设备驱动程序内核机制

    前段时间在学习linux设备驱动的时候,看了陈学松著的<深入Linux设备驱动程序内核机制>一书. 说实话.这是一本非常好的书,作者不但给出了在设备驱动程序开发过程中的所须要的知识点(如对 ...

  6. 一个简单的演示用的Linux字符设备驱动程序

    实现如下的功能:--字符设备驱动程序的结构及驱动程序需要实现的系统调用--可以使用cat命令或者自编的readtest命令读出"设备"里的内容--以8139网卡为例,演示了I/O端 ...

  7. 简单linux字符设备驱动程序

    本文代码参考<LINUX设备驱动程序>第三章 字符设备驱动程序 本文中的“字符设备”是一段大小为PAGE_SIZE的内存空间 功能:向字符设备写入字符串:从字符设备读出字符串 代码: 1. ...

  8. LINUX设备驱动程序笔记(三)字符设备驱动程序

          <一>.主设备号和次设备号        对字符设备的訪问时通过文件系统内的设备名称进行的.那些设备名称简单称之为文件系统树的节点,它们通常位于/dev文件夹. 字符设备驱动程 ...

  9. linux设备驱动程序--串行通信驱动框架分析

    linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...

随机推荐

  1. 转: 私人珍藏的Chrome插件,吐血推荐

    转:来自 http://stormzhang.com/devtools/2016/01/15/google-chrome-extension/

  2. SQL查询刚開始学习的人指南读书笔记(一)关系数据库和SQL介绍

    PART I:Relational Databases and SQL Chapter2, Ensuring Your Database Structure IsSound. 数据库设计准则 什么是关 ...

  3. 学习ajax总结

    之前公司的ajax学习分享,做一点总结,加深记忆 什么是ajax? 异步的的js和xml,用js异步形式操作xml,工作主要是数据交互 借阅用户操作时间,减少数据请求,可以无刷新请求数据 创建一个对象 ...

  4. iOS tableView下拉图片放大

    事实上这个效果,本质上就是在你tableView下拉 造成offset时候. 保持你顶部图片的y坐标点还停留在下拉时屏幕的顶点(offset), 而图片的长度变为原始的height长度-(offset ...

  5. centos7,py2和py3共存

    1.查看是否已经安装Python CentOS 7.2 默认安装了python2.7.5 因为一些命令要用它比如yum 它使用的是python2.7.5. 使用 python -V 命令查看一下是否安 ...

  6. Linux——解决RedHat6/CentOS6系统中“弹出界面eth0:设备似乎不存在”的问题

    刚刚在自己的CentOS6系统中执行service network restart时,竟然提示: 弹出界面 eth0: 设备 似乎不存在, 初始化操作将被延迟.   [失败] 这事可真神奇.于是手动编 ...

  7. windows上使用的免费连接linux终端xshell6,xftp6下载

    xshell 6 https://www.netsarang.com/download/down_form.html?code=622 xftp 6 https://www.netsarang.com ...

  8. C# 获取当前路径方法(转)

    C# 获取当前路径方法 //获取包含清单的已加载文件的路径或 UNC 位置. public static string sApplicationPath = Assembly.GetExecuting ...

  9. tcp/ip ---数据封装过程

  10. HIVE中join、semi join、outer join

    补充说明 left outer join where is not null与left semi join的联系与区别:两者均可实现exists in操作,不同的是,前者允许右表的字段在select或 ...