嵌入式实践教程--【Linux驱动】Linux驱动开发基于Linux4.0+(一)——字符设备驱动

简介: 嵌入式实践教程--【Linux驱动】Linux驱动开发基于Linux4.0+(一)——字符设备驱动

区别于Linux4.0之前的字符设备驱动结构,4.0采用cdev注册字符设备。

一、构造一个字符设备结构体,用于cdev的初始化


struct led_dev_t{
  struct cdev cdev;
};


二、__init 入口函数


1.设备号的处理

dev_t led_devno= MKDEV(led_major,0);


MKDEV(led_major,0)通过主次设备号生成dev_t,在cdev的结构体里面定义了成员dev_t为,32位,12位是主设备号,20位是次设备号。如果不想自己设定主次设备号,可以使用MAJOR(dev_t dev)和MINOR(dev_t dev)生成主次设备号。


if(led_major)
  {
    ret = register_chrdev_region(led_devno, 1,"led");
  }
  else
  {
    ret = alloc_chrdev_region(&led_devno, 0, 1, "led");
    led_major = MAJOR(led_devno);
  }


判断主设备号是否已定义,如果已定义,则注册设备号和设备名;否则申请一个设备号空间然后使用MAJOR(led_devno)生成主设备号。


2.注册字符设备前的准备:申请所需注册设备的结构体空间


ledevp = kzalloc(sizeof(led_dev_t), GFP_KERNEL);  /*申请内存空间*/
  /*判断内存是否申请成功*/
  if(!ledevp)
  {
    ret = -ENOMEM;
    unregister_chrdev_region(led_devno,1);
    return ret;
  }


3.注册字符设备

static void led_setup_cdev(struct led_dev_t *dev,int index)
{
  int err, led_devno = MKDEV(led_major,index);  /*通过主设备号和次设备号生成dev_t*/
  cdev_init(&dev->cdev,&chardev_led_fops);  /*初始化cdev*/
  dev->cdev.owner = THIS_MODULE;
  err = cdev_add(&dev->cdev,led_devno,1);   /*添加一个cdev,param1:cdev,param2:主次设备号*/
  if(err)
  {
    printk(KERN_NOTICE"Error %d adding led %d",err,index);
  }
}


cdev_init初始化cdev,将本驱动的cdev添加进cdev链表


三、字符设备驱动模板


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define LED_MAJOR 229
static int led_major = LED_MAJOR;
/*设备结构体*/
struct led_dev_t{
  struct cdev cdev;
};
struct led_dev_t *ledevp;
static int led_drv_open(struct inode *inode,struct file *file)
{
  /*设置LED引脚为输出模式*/
}
static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
  /*向引脚写入值*/
  copy_from_user(..,buf,..);//从用户空间获得参数
}
const static struct file_operations chardev_led_fops = {
  .owner = THIS_MODULE,
  .open = led_drv_open,
  .write = led_drv_write
};
static void led_setup_cdev(struct led_dev_t *dev,int index)
{
  int err, led_devno = MKDEV(led_major,index);  /*通过主设备号和次设备号生成dev_t*/
  cdev_init(&dev->cdev,&chardev_led_fops);  /*初始化cdev*/
  dev->cdev.owner = THIS_MODULE;
  err = cdev_add(&dev->cdev,led_devno,1);   /*添加一个cdev,param1:cdev,param2:主次设备号*/
  if(err)
  {
    printk(KERN_NOTICE"Error %d adding led %d",err,index);
  }
}
static int __init  chardev_led_init(void)
{
  int ret;
  dev_t led_devno= MKDEV(led_major,0);    
  /*获取字符设备号*/
  if(led_major)
  {
    ret = register_chrdev_region(led_devno, 1,"led");
  }
  else
  {
    ret = alloc_chrdev_region(&led_devno, 0, 1, "led");
  }
  ledevp = kzalloc(sizeof(led_dev_t), GFP_KERNEL);  /*申请内存空间*/
  /*判断内存是否申请成功*/
  if(!ledevp)
  {
    ret = -ENOMEM;
    unregister_chrdev_region(led_devno,1);
    return ret;
  }
  led_setup_cdev(ledevp,1);       /*设置字符设备*/
  return 0;
}
static void __exit chardev_led_exit(void)
{  
  cdev_del(&ledevp->cdev);        /*删除cdev,释放内存空间*/
  kfree(ledevp);
  unregister_chrdev_region(MKDEV(led_major, 0), 1);
}
module_init(chardev_led_init);
module_exit(chardev_led_exit);
MODULE_AUTHOR(" MUGGLE <1198492751@qq.com>")
MODULE_LICENSE("GPL v2");


相关文章
|
23天前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
72 15
|
1月前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
109 13
|
1月前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
1月前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
2月前
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
216 3
|
3月前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
77 3
|
3月前
|
Ubuntu Linux
Linux实践|设置静态 IP 地址
Linux实践|设置静态 IP 地址
90 0
Linux实践|设置静态 IP 地址
|
5月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
67 6
|
5月前
|
存储 人工智能 数据管理
深入理解Linux操作系统之文件系统管理探索人工智能:从理论到实践的旅程
【8月更文挑战第30天】在探索Linux的无限可能时,我们不可避免地会遇到文件系统管理这一核心话题。本文将深入浅出地介绍Linux文件系统的基础知识、操作命令及高级技巧,帮助你更有效地管理和维护你的系统。从基础概念到实践应用,我们将一步步揭开Linux文件系统的神秘面纱。
|
4月前
|
Linux API
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】