一.驱动框架

初始化:insmod 加载

1.确定主设备号:

分为静态和动态分配,其中LED_GPIO_SIZE 表示支持的次设备号数目,一般默认为1. 相关实现代码如下:

  1. int result;
  2. dev_t dev;
  3. /*分配主设备号*/
  4. if (scull_major)   /*静态分配一个主设备号*/
  5. {
  6. dev = MKDEV(scull_major,0);
  7. result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);
  8. }
  9. else               /*动态分配一个主设备号*/
  10. {
  11. result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);
  12. scull_major = MAJOR(dev);
  13. }
  14. if(result <0)
  15. {
  16. printk("LED:can not get major:%d\n",scull_major);
  17. return result;
  18. }

2.构造 file_operations 结构:结构成员对应相应的处理函数:

  1. static struct file_operations mini2440_leds_fops = {
  2. .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  3. .open   =   mini2440_leds_open,
  4. .write  =   mini2440_leds_write,
  5. };

3.将相关操作告诉内核:

内核用cdev结构来表示字符设备,cev_init()将文件操作和cdev关联。cdev_add()将之前生成的主次设备号和cdev连接在一起,

  1. led_class = class_create(THIS_MODULE,DEVICE_NAME);
  2. cdev_init(&led_gpio_cdev, &mini2440_leds_fops);
  3. result = cdev_add(&led_gpio_cdev, dev, 1);
  4. if(result <0)
  5. {
  6. printk("LED:cdev_add error\n");
  7. return result;
  8. }
  9. device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");

卸载驱动 rmmod 卸载 代码实现如下:

  1. dev_t dev_id = MKDEV(scull_major, 0);
  2. /*卸载主设备号*/
  3. unregister_chrdev_region(dev_id, LED_GPIO_SIZE);
  4. device_destroy(led_class,MKDEV(scull_major, 0));
  5. cdev_del(&led_gpio_cdev);
  6. class_destroy(led_class);

最后附上一个较为完整的驱动框架,其中创建了主设备号和次设备号,驱动代码如下:

  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 <mach/io.h>
  9. #include <mach/regs-gpio.h>
  10. #include <mach/hardware.h>
  11. #include <linux/device.h>
  12. #include <linux/cdev.h>
  13. #define DEVICE_NAME "led_1"
  14. #define LED_GPIO_SIZE 4
  15. static int scull_major = 0;
  16. static struct class *led_class;
  17. static struct cdev led_gpio_cdev[LED_GPIO_SIZE];
  18. static int mini2440_leds_open(struct inode *inode, struct file *file)
  19. {
  20. int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
  21. printk("/dev/led%d has opened\n",minor);
  22. return 0;
  23. }
  24. static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
  25. {
  26. char val;
  27. int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
  28. copy_from_user(&val, buf, 1);
  29. printk("/dev/led%d write the val = %d\n",minor,val);
  30. return 0;
  31. }
  32. static struct file_operations mini2440_leds_fops = {
  33. .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  34. .open   =   mini2440_leds_open,
  35. .write  =   mini2440_leds_write,
  36. };
  37. /*
  38. * 执行insmod命令时就会调用这个函数
  39. */
  40. static int mini2440_leds_init(void)
  41. {
  42. int result,i;
  43. dev_t dev;
  44. /*分配主设备号*/
  45. if (scull_major)   /*静态分配一个主设备号*/
  46. {
  47. dev = MKDEV(scull_major,0);
  48. result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);
  49. }
  50. else               /*动态分配一个主设备号*/
  51. {
  52. result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);
  53. scull_major = MAJOR(dev);
  54. }
  55. if(result <0)
  56. {
  57. printk("LED:can not get major:%d\n",scull_major);
  58. return result;
  59. }
  60. led_class = class_create(THIS_MODULE,DEVICE_NAME);
  61. if (IS_ERR(led_class)) {
  62. return PTR_ERR(led_class);
  63. }
  64. for (i=0; i<LED_GPIO_SIZE;i++)
  65. {
  66. cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops);
  67. result = cdev_add(&led_gpio_cdev[i], (dev+i), 1);
  68. if(result <0)
  69. {
  70. printk("LED:cdev_add error\n");
  71. return result;
  72. }
  73. device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i);
  74. }
  75. return 0;
  76. }
  77. /*
  78. * 执行rmmod命令时就会调用这个函数
  79. */
  80. static void mini2440_leds_exit(void)
  81. {
  82. int i;
  83. dev_t dev_id = MKDEV(scull_major, 0);
  84. /*卸载主设备号*/
  85. unregister_chrdev_region(dev_id, LED_GPIO_SIZE);
  86. for(i=0;i<LED_GPIO_SIZE;i++)
  87. {
  88. device_destroy(led_class,MKDEV(scull_major, i));
  89. cdev_del(&led_gpio_cdev[i]);
  90. }
  91. class_destroy(led_class);
  92. }
  93. /* 这两行指定驱动程序的初始化函数和卸载函数 */
  94. module_init(mini2440_leds_init);
  95. module_exit(mini2440_leds_exit);
  96. /* 描述驱动程序的一些信息,不是必须的 */
  97. MODULE_LICENSE("GPL");

linux 测试代码:

    1. #include <sys/types.h>
    2. #include <sys/stat.h>
    3. #include <fcntl.h>
    4. #include <stdio.h>
    5. /*
    6. *  ledtest <dev> <on|off>
    7. */
    8. void print_usage(char *file)
    9. {
    10. printf("Usage:\n");
    11. printf("%s <dev> <on|off>\n",file);
    12. printf("eg. \n");
    13. printf("%s /dev/led0 a\n", file);
    14. printf("%s /dev/led1 b\n", file);
    15. printf("%s /dev/led2 c\n", file);
    16. printf("%s /dev/led3 d\n", file);
    17. }
    18. int main(int argc, char **argv)
    19. {
    20. int fd;
    21. char* filename;
    22. char val;
    23. if (argc != 3)
    24. {
    25. print_usage(argv[0]);
    26. return 0;
    27. }
    28. filename = argv[1];
    29. fd = open(filename, O_RDWR);
    30. if (fd < 0)
    31. {
    32. printf("error, can't open %s\n", filename);
    33. return 0;
    34. }
    35. if (!strcmp("a", argv[2]))
    36. {
    37. val = 10;
    38. write(fd, &val, 1);
    39. }
    40. else if (!strcmp("b", argv[2]))
    41. {
    42. val = 11;
    43. write(fd, &val, 1);
    44. }
    45. else if (!strcmp("c", argv[2]))
    46. {
    47. val = 12;
    48. write(fd, &val, 1);
    49. }
    50. else if (!strcmp("d", argv[2]))
    51. {
    52. val = 13;
    53. write(fd, &val, 1);
    54. }
    55. return 0;
    56. }

linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)的更多相关文章

  1. 【linux】驱动-5-驱动框架分层分离&实战

    目录 前言 5. 分离分层 5.1 回顾-设备驱动实现 5.2 分离分层 5.3 设备 5.4 驱动 5.5 系统,模块 5.6 Makefile 参考: 前言 5. 分离分层 本章节记录实现LED驱 ...

  2. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

  3. linux块设备驱动---概念与框架(转)

    基本概念   块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性 ...

  4. Linux内核USB驱动【转】

    本文转载自:http://www.360doc.com/content/12/0321/14/8363527_196286673.shtml 注意,该文件是2.4的内核的驱动源文件,并不保证在2.6内 ...

  5. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  6. Linux块设备驱动(一) _驱动模型

    块设备是Linux三大设备之一,其驱动模型主要针对磁盘,Flash等存储类设备,本文以3.14为蓝本,探讨内核中的块设备驱动模型 框架 下图是Linux中的块设备模型示意图,应用层程序有两种方式访问一 ...

  7. linux usb总线驱动(一)

    目录 linux usb总线驱动框架 USB 介绍 传输类型 控制器接口 2440接口 基本流程 alloc_dev choose_address hub_port_init usb_get_devi ...

  8. Linux网络设备驱动 _驱动模型

    Linux素来以其强大的网络功能著名,同时, 网络设备也作为三大设备之一, 成为Linux驱动学习中必不可少的设备类型, 此外, 由于历史原因, Linux并没有强制对网络设备贯彻其"一切皆 ...

  9. EDK II之USB总线驱动的实现框架

    本文简单介绍一下UEFI中USB驱动的实现框架: 下图是USBD向上层驱动提供的接口: 1.从图中我们可以看出,USBDI的实现主要通过调用HCDI实现 和 访问USB_INTERFACE结构体(该结 ...

随机推荐

  1. UVa 12265 贩卖土地 单调栈

    题意 输入一个\(n\times m\)的矩阵,每个格子可能是空地,也可能是沼泽.对于每个空地格子,求出以它为右下角的空矩形的最大周长,然后统计每个周长出现了多少次. 思路 对于 每一行 每两个沼泽之 ...

  2. 用maven创建第一个SpringMVC

    首先创建一个maven项目,然后依次完成如下配置: 在pom.xml加入如下基础配置,利用maven加载我们所需要的jar: <project xmlns="http://maven. ...

  3. Oracle基础 05 联机日志 redolog

    --两个相关视图v$logv$logfile alter system switch logfile;  --强制日志切换alter system checkpoint;      --强制检查点 - ...

  4. zabbix ZBX_NOTSUPPORTED: Timeout while executing a shell script.

    有一个监控一直都是正常的,今天突然收到报警邮件,上服务器查看服务又是正常的,但是报警邮件还是没恢复 监控端进行脚本测试,发现是正常的 到监控端使用zabbix_get -s ip -p 端口  -k ...

  5. Git-回滚操作

    git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit git log 查询回滚版本唯一commit标识代码 git reset --ha ...

  6. Tkinter 计算器

    from tkinter import * master = Tk() frame = Frame(master) frame.pack(padx=10,pady=10) v1 = StringVar ...

  7. pytest学习(3)

    在pytest 2.0以上的版本里,我们也可以通过python -m pytest ...来调用.这实际上和pytest ...几乎一摸一样. 只是用python的时候,把当面目录也加入到sys.pa ...

  8. redis使用管道pipeline提升批量操作性能(php演示)

    Redis是一个TCP服务器,支持请求/响应协议. 在Redis中,请求通过以下步骤完成: 客户端向服务器发送查询,并从套接字读取,通常以阻塞的方式,用于服务器响应. 服务器处理命令并将响应发送回客户 ...

  9. [libgdx游戏开发教程]使用Libgdx进行游戏开发(4)-素材管理

    游戏中总是有大量的图像资源,我们通常的做法是把要用的图片做成图片集,这样做的好处就不多说了.直接来看怎么用. 这里我们使用自己的类Assets来管理它们,让这个工具类作为我们的资源管家,从而可以在任何 ...

  10. Python与数据结构[4] -> 散列表[2] -> 开放定址法与再散列的 Python 实现

     开放定址散列法和再散列 目录 开放定址法 再散列 代码实现 1 开放定址散列法 前面利用分离链接法解决了散列表插入冲突的问题,而除了分离链接法外,还可以使用开放定址法来解决散列表的冲突问题. 开放定 ...