深入浅出linux驱动,Linux Kernel 字符驱动的深入浅出讲解

本文详细介绍了如何在Linux内核中开发字符驱动,包括设备注册、控制代码实现、ioctl函数使用,以及内核配置和编译。适合有一定Linux基础的读者,通过实例解析了驱动开发过程中的关键步骤和技术,帮助开发者掌握驱动开发技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注:在写Linux 内核驱动,并将这一过程发生的技术,和菜鸟们可能会碰的问题进行一次解释,希望对后来都有用,阅读此文需要一定Linux基础,或者不要浪费时间,好品德看完全文要顶一下,看完此文你应该肻定会开发自己的字符驱动,请注意注解部分。

我反着来讲整个过程,讲解是为让人更快明白,有些术语不是标准的哦,对于正在找这个朋友此文就是你的宝,如果你乐意你可以给我付费。

第一步:内核加入到你设备中,整个调用驱动过程代码以下

MyTest::MyTest(QWidget *parent, const char *name, WFlags f):led(parent, name, f)

{

/*1.int m_fd 是句柄 WIN32的名词 类的私有变量。private:  int m_fd;

2.:: 这是名字空间符

3.open Linux打开设备的系统function

4. "/dev/pwcs", 这句话的解释 /dev 表示linux系统驱动 可以指示 内核工程中 如图

a0a163928a67941e3701afb218af52cb.png

/pwcs   自定义的设备名称

5. O_RDWR   系统标准备读写宏

*/

m_fd = ::open("/dev/pwcs", O_RDWR);       //..打开设备.

if (m_fd < 0) {

//..没有打开设备

}

/*1.connect 系统函数

2.0,1,这些指驱动自定义要控制设备的系列号 ,

3.SIGNAL(什么事件)

4.this 这是什么呀,自己查去

5.SLOT(事件动作)

*/

connect(0,  SIGNAL(clicked()), this, SLOT(checkBoxClicked()) );   //..

connect(1,  SIGNAL(clicked()), this, SLOT(checkBoxClicked()) );

//.......可以有很多

checkBoxClicked();

}

MyTest::~MyTest()

{

::close(m_fd);  //..关闭设备

}

void MyTest::checkBoxClicked()

{

/* ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的参数个数如下:int ioctl(int fd, int cmd, …);其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就能在用户程序中使用ioctl函数控制设备的I/O通道。

*/

::ioctl(m_fd, int(m_pwc1->isChecked()), 0);

::ioctl(m_fd, int(m_pwc2->isChecked()), 1);

::ioctl(m_fd, int(m_pwc3->isChecked()), 2);

::ioctl(m_fd, int(m_pwc4->isChecked()), 3);

}

}

第二步:增加内核驱动控制代码

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include #include

#include

#include

#define DEVICE_NAME "pwcs"  //..注意这里 m_fd = ::open("/dev/pwcs", O_RDWR);  打开设备.

/*

connect(0,  SIGNAL(clicked()), this, SLOT(checkBoxClicked()) );   //..

connect(1,  SIGNAL(clicked()), this, SLOT(checkBoxClicked()) );

S3C64XX_GPK(XX) 来自这里  \u-kernel\arch\arm\mach-s3c64xx\include\mach\gpio.h

*/

static int power_gpios[] = {

S3C64XX_GPK(0),    //..设备中要控制CPU的GPIO                    :0  connect自定义要控制设备的系列号

S3C64XX_GPF(14),   //..                                                          :1   connect自定义要控制设备的系列号

S3C64XX_GPA(2),    //..                                                           :2   connect自定义要控制设备的系列号

S3C64XX_GPF(13),   //..                                                          :3   connect自定义要控制设备的系列号

S3C64XX_GPK(1),    //..                                                           :4  connect自定义要控制设备的系列号

};

#define PW_GPIO_NUM  ARRAY_SIZE(power_gpios)     //..数组大小

static long power_gpio_ctrls_ioctl(struct file *filp, unsigned int cmd,

unsigned long arg)

{

switch(cmd) {

case 0:

case 1:

if (arg > PW_GPIO_NUM) {

return -EINVAL;

}

gpio_set_value(power_gpios[arg], cmd);  //..\u-kernel\arch\arm\mach-s3c64xx\include\mach\gpio.h

//printk(DEVICE_NAME": %d %d\n", arg, cmd);

break;

default:

return -EINVAL;

}

return 0;

}

static struct file_operations power_gpio_ctrl_dev_fops = {

.owner   = THIS_MODULE,

.unlocked_ioctl = power_gpio_ctrls_ioctl,

};

static struct miscdevice power_gpio_ctrl_dev = {

.minor  = MISC_DYNAMIC_MINOR,

.name   = DEVICE_NAME, //..注意这里

.fops   = &power_gpio_ctrl_dev_fops,

};

static int __init power_gpio_ctrl_dev_init(void) {

int ret;

int i;

for (i = 0; i < PW_GPIO_NUM; i++) {

ret = gpio_request(power_gpios, "PWC"); //..用户控制符 “PWC”注册时用

if (ret) {

printk("%s: request GPIO %d for ctrl failed, ret = %d\n", DEVICE_NAME,

power_gpios, ret);

return ret;

}

s3c_gpio_cfgpin(power_gpios, S3C_GPIO_OUTPUT);

gpio_set_value(power_gpios, 0);

}

ret = misc_register(&power_gpio_ctrl_dev); //..注册

printk(DEVICE_NAME"\tinitialized\n");

return ret;

}

static void __exit power_gpio_ctrl_dev_exit(void) {

int i;

for (i = 0; i < PW_GPIO_NUM; i++) {

gpio_free(power_gpios);

}

misc_deregister(&power_gpio_ctrl_dev); //..干掉它

}

module_init(power_gpio_ctrl_dev_init);             //..模块初始化  给open用的

module_exit(power_gpio_ctrl_dev_exit);            //..模块初退出 给close用的

MODULE_LICENSE("GPL");                           //..模块许可授权 注意这个是必须的或者注册不了,其它方式我不说了,

//..给钱告 诉你。

MODULE_AUTHOR("IFOCOOL@QQ.COM");   //..作者信息

第三步:使用make menuconfig 可以看到.

source "drivers/char/Kconfig"  在内核配置菜单Kconfig文件中增加以下内容注意以下两个图

e9e20aa318dc263b0c8a8d25e594c870.png

e0d0e8ff0f15d0109ba3984e23815af6.png

在drivers/char/Kconfig的文件 menu "Character devices" 菜单下增加以下内容

config POWER_CTRL                  #配置关键字

tristate  "GPIO Power On/Off Ctrl"       #这段菜单名称

depends on  CPU_S3C6410              #depends on CPU_S3C6410     表示还要这个菜单项前“CPU_S3C6410”看我写的LINUX

#专题里面有讲到。

default y                                           #默为y

在drivers/char/Makefile的文件 增加以下内容

obj-$(CONFIG_POWER_CTRL)   += power_gpio_ctrl.o   #C文件编绎后目标文件 power_gpio_ctrl.c的目标文件

#CONFIG_POWER_CTRL=CONFIG+POWER_CTRL(注:这来自

Kconfig)

第四步:必须完成第三步后执行这一步

linux 命令台中执行: make menuconfig

进行字符驱动选择菜单如图

6abd76115c96d7aa1c80bb5b108ca23d.png

15a87a6487b2ed21211ce51ee02fa215.png

最后一步make内核

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值