嵌入式实践教程--【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");


相关文章
|
6天前
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
36 0
|
27天前
|
关系型数据库 Linux 数据库
Linux系统安装Postgre和Postgis教程
本文详细介绍了PostgreSQL/PostGIS的卸载与安装步骤。卸载部分涵盖Docker、Yum/RPM及源码编译安装的清理方法,包括停止服务、删除容器/包、清理残留文件和环境变量等操作,并强调卸载前需备份数据库数据。安装部分提供在线yum安装和离线源码编译两种方式,前者简单快捷,后者需准备依赖(如gcc、readline-devel等)、创建用户组、初始化数据库及配置访问规则。每步均附带命令示例,确保操作清晰明确。
168 0
|
2月前
|
安全 Ubuntu Linux
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
104 0
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
|
3月前
|
安全 Java Linux
Linux安装Elasticsearch详细教程
Linux安装Elasticsearch详细教程
347 1
|
3月前
|
运维 安全 Linux
试试Linux设备命令行运维工具——Wowkey
WowKey 是一款专为 Linux 设备设计的命令行运维工具,提供自动化、批量化、标准化、简单化的运维解决方案。它简单易用、高效集成且无依赖,仅需 WIS 指令剧本文件、APT 账号密码文件和 wowkey 命令即可操作。通过分离鉴权内容与执行内容,WowKey 让运维人员专注于决策,摆脱繁琐的交互与执行细节工作,大幅提升运维效率与质量。无论是健康检查、数据采集还是配置更新,WowKey 都能助您轻松应对大规模设备运维挑战。立即从官方资源了解更多信息:https://atsight.top/training。
|
3月前
|
数据采集 运维 安全
Linux设备命令行运维工具WowKey问答
WowKey 是一款用于 Linux 设备运维的工具,可通过命令行手动或自动执行指令剧本,实现批量、标准化操作,如健康检查、数据采集、配置更新等。它简单易用,只需编写 WIS 指令剧本和 APT 帐号密码表文件,学习成本极低。支持不同流派的 Linux 系统,如 RHEL、Debian、SUSE 等,只要使用通用 Shell 命令即可通吃Linux设备。
|
4月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
Shell Linux Perl
在Linux命令行中进行大小写字符转换
在Linux命令行中进行大小写字符转换
在Linux命令行中进行大小写字符转换
|
Shell Linux Perl
Linux命令行:对内容进行大小写字符转换 ​​​​
Linux命令行:对内容进行大小写字符转换 ​​​​
Linux命令行:对内容进行大小写字符转换 ​​​​
|
1月前
|
JSON 自然语言处理 Linux
linux命令—tree
tree是一款强大的Linux命令行工具,用于以树状结构递归展示目录和文件,直观呈现层级关系。支持多种功能,如过滤、排序、权限显示及格式化输出等。安装方法因系统而异常用场景包括:基础用法(显示当前或指定目录结构)、核心参数应用(如层级控制-L、隐藏文件显示-a、完整路径输出-f)以及进阶操作(如磁盘空间分析--du、结合grep过滤内容、生成JSON格式列表-J等)。此外,还可生成网站目录结构图并导出为HTML文件。注意事项:使用Tab键补全路径避免错误;超大目录建议限制遍历层数;脚本中推荐禁用统计信息以优化性能。更多详情可查阅手册mantree。
linux命令—tree