Linux嵌入式驱动开发13——ioctl接口(gpio控制使用)

GNU/Linux - 使用字符设备来操作GPIO GPIO 通过 /sys/class/gpio 中的导出文件进行配置和控制。在第 4 行,我们将 line_info 结构的 line_offset 属性设置为要查询的 GPIO 线路/偏移量,然后通过 GPIO_GET_LINEINFO_IOCTL 请求调用 ioctl 函数。通过 /sys/class/gpio/export 配置 GPIO 方向(输入/输出): 通过: /sys/class/gpio/gpioX/direction 配置 GPIO 方向(输入/输出。 阅读详情

文章目录

全系列传送门

Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)

Linux嵌入式驱动开发02——驱动编译到内核

Linux嵌入式驱动开发03——杂项设备驱动(附源码)

Linux嵌入式驱动开发04——应用层和内核层数据传输

Linux嵌入式驱动开发05——物理地址到虚拟地址映射

Linux嵌入式驱动开发06——第一个相对完整的驱动实践编写

Linux嵌入式驱动开发07——GPIO驱动过程记录(飞凌开发板)

Linux嵌入式驱动开发08——字符设备(步步为营)

Linux嵌入式驱动开发09——平台总线详解及实战

Linux嵌入式驱动开发10——设备树开发详解

Linux嵌入式驱动开发11——平台总线模型修改为设备树实例

Linux嵌入式驱动开发12——pinctl和gpio子系统实践操作

Linux嵌入式驱动开发13——ioctl接口(gpio控制使用)

Linux嵌入式驱动开发14——中断的原理以及按键中断的实现(tasklet中断下文)

Linux嵌入式驱动开发15——等待队列和工作队列

Linux嵌入式驱动开发16——按键消抖实验(内核定时器)

Linux嵌入式驱动开发17——输入子系统

Linux嵌入式驱动开发18——I2C通信

引言

我们从平台总线模型,然后到pinctrl和gpio子系统,会发现步骤逐渐的规范,代码也逐渐的简单,也越来越能体会到linux屏蔽底层硬件的优势。

在之前的代码中,在write函数中往内核中写入数据。
在这里插入图片描述
并且在应用层传入内核层的过程,需要执行copy函数,对于我们这里只需要传入0或者1的少量数据来说,有些繁琐。

什么是unlocked_ioctl接口?

unlocked_ioctl就是ioctl接口,但是功能和对应的系统调用均没有发生变化

unlocked_ioctl和read/write函数有什么相同和不同

之前我们使用read/write函数完成写数据或者读数据的操作,ioctl函数也可以往内核中写入命令。

不同点是read/write函数是两个单独的函数,完成单一的读或者写功能,我们的ioctl函数,既可以读,也可以写。

不过read/write函数在读写大数据时候效率比较高。

所以,对于gpio控制led灯或者蜂鸣器等操作时,我们不需要大量的数据读写,可以使用ioctl函数,来简化,而read/write函数专职于大量数据的传输。

unlocked_ioctl接口命令规则

unlocked_ioctl总共32位

第一个分区 0-7,命令的编号,范围是0-255

第二个分区 8-15 命令的幻数。

(第一个分区和第二个分区主要作用就是用来区分命令的。)

第三个分区 16-29 表示传递的数据大小

第四个分区 30-31 代表读写的方向
00:表示用户程序和驱动数据没有数据传递
10:表示用户程序从驱动里面读取数据
01:表示用户程序向驱动里面写入数据

11:先写数据到驱动,然后再从驱动把数据读出来(不常用)

命令的合成宏与分解宏

合成宏

在这里插入图片描述

分解宏

在这里插入图片描述

测试程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/ioctl.h>

#define CMD_TEST0 _IO(‘L’, 0) // 'L’是幻数 0是编号
#define CMD_TEST1 _IO(‘L’, 1)
#define CMD_TEST2 _IOW(‘L’, 2, int) // 第三个参数size,不是数据大小,而是数据类型,这里是四个字节的话,就是int
#define CMD_TEST3 _IOR(‘L’, 3, int) // 这四个命令幻数虽然一样,但是编号不同,所以不同。

int main(int argc, char *argv[])
{
printf(“30-31 is %d\n”, _IOC_DIR(CMD_TEST0));
printf(“30-31 is %d\n”, _IOC_DIR(CMD_TEST3));

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

我们先来测试一下代码的功能,这里使用_IOC_DIR分解命令的方向,CMD_TEST0是定义命令编号,没有数据操作,所以_IOC_DIR分解后30-31的数据应该是00

CMD_TEST3是_IOR(‘L’, 3, int),是读取,所以分解后应该读到是读对应的10,对应十进制也就是2
在这里插入图片描述
接下来继续测试_IOC_TYPE函数

    printf("8-15 is %c\n", _IOC_TYPE(CMD_TEST0));
    printf("8-15 is %c\n", _IOC_TYPE(CMD_TEST1));

执行后可以看到返回了8-15位的幻数
在这里插入图片描述

printf("编号 0-7 is %d\n", _IOC_NR(CMD_TEST2));

在这里插入图片描述

使用_IO

模拟一个闪灯的操作

module_leds.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define CMD_TEST0 _IO(‘L’, 0) // 'L’是幻数 0是编号
#define CMD_TEST1 _IO(‘L’, 1)

int misc_open (struct inode inode, struct file file){

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"hello misc_open!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

int misc_release(struct inode inode, struct file file){

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"bye bye misc_release!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

ssize_t misc_read(struct file file, const char __user ubuf, size_t size, loff_t *loff_t){

<span class="token keyword">char</span> kbuf<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"copy to user!!!\n"</span><span class="token punctuation">;</span>

<span class="token keyword">if</span><span class="token punctuation">(</span> <span class="token function">copy_to_user</span><span class="token punctuation">(</span>ubuf<span class="token punctuation">,</span> kbuf<span class="token punctuation">,</span> size<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"copy_to_user error!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"hello misc_read!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

ssize_t misc_write(struct file file, const char __user ubuf, size_t size, loff_t *loff_t){

<span class="token keyword">char</span> kbuf<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"copy from user!!!\n"</span><span class="token punctuation">;</span>
<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"hello misc_write!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span> <span class="token function">copy_from_user</span><span class="token punctuation">(</span>kbuf<span class="token punctuation">,</span> ubuf<span class="token punctuation">,</span> size<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"copy_from_user error!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"buf is:%s\n"</span><span class="token punctuation">,</span> kbuf<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
switch (cmd)
{
case CMD_TEST0:
printk(“LED_ON!!!\n”);
case CMD_TEST1:
printk(“LED_OFF!!!\n”);
break;

<span class="token keyword">default</span><span class="token punctuation">:</span>
    <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write,
.unlocked_ioctl = misc_ioctl,
};

struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = “hello_misc”,
.fops = &misc_fops
};

static int misc_init(void)
{
int ret;

ret <span class="token operator">=</span> <span class="token function">misc_register</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>misc_dev<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span><span class="token punctuation">(</span>ret <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"misc_register failed!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"misc_register succeed!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>           <span class="token comment">// 在内核中无法使用c语言库,所以不用printf</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

static void misc_exit(void)
{
misc_deregister(&misc_dev);

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"misc exit!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

module_init(misc_init);
module_exit(misc_exit);

MODULE_LICENSE(“GPL”); //声明模块拥有开源许可

Makefile

# 开发板Linux内核的实际路径 
# KDIR变量
KDIR:=/work/linux-4.1.15

获取当前目录

PWD:=$(shell pwd)

# obj-m表示将 chrdevbase.c这个文件 编译为 chrdevbase.ko模块。
obj-m += module_leds.o

编译成模块

all:
make -C < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > K D I R < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ) < / s p a n > M < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > <span class="token punctuation">(</span>KDIR<span class="token punctuation">)</span> M<span class="token operator">=</span> <spanclass="tokenpunctuation">(</span>KDIR<spanclass="tokenpunctuation">)</span>M<spanclass="tokenoperator">=</span>(PWD) modules

clean:
make -C < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > K D I R < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ) < / s p a n > M < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > <span class="token punctuation">(</span>KDIR<span class="token punctuation">)</span> M<span class="token operator">=</span> <spanclass="tokenpunctuation">(</span>KDIR<spanclass="tokenpunctuation">)</span>M<spanclass="tokenoperator">=</span>(PWD) clean

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/ioctl.h>

#define CMD_TEST0 _IO(‘L’, 0) // 'L’是幻数 0是编号
#define CMD_TEST1 _IO(‘L’, 1)

int main(int argc, char *argv[])
{
int fd;

<span class="token keyword">char</span> buff<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{<!-- --></span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

fd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/dev/hello_misc"</span><span class="token punctuation">,</span> O_RDWR<span class="token punctuation">)</span><span class="token punctuation">;</span>       <span class="token comment">// 打开节点时候触发open函数</span>

<span class="token keyword">if</span><span class="token punctuation">(</span>fd <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>

    <span class="token function">perror</span><span class="token punctuation">(</span><span class="token string">"open error\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                 <span class="token comment">// perror在应用中打印</span>
    <span class="token keyword">return</span> fd<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">while</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">ioctl</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> CMD_TEST0<span class="token punctuation">)</span><span class="token punctuation">;</span>                   <span class="token comment">// 触发驱动中的.unlocked_ioctl</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ioctl</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> CMD_TEST1<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

结果

在测试结果中可以看到每次ioctl都会进入到驱动中的misc_ioctl中进行判断,然后打印出来预期的结果
在这里插入图片描述

使用_IOW

这里只修改了两个地方的代码
module_leds.c

long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
    switch (cmd)
    {
    case CMD_TEST2:
        printk("LED_ON!!!\n");
        printk("value is %d\n", value);
        break;
    case CMD_TEST3:
        printk("LED_OFF!!!\n");
        printk("value is %d\n", value);
        break;
<span class="token keyword">default</span><span class="token punctuation">:</span>
    <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

app.c

    while(1){
        ioctl(fd, CMD_TEST2, 0);                   // 触发驱动中的.unlocked_ioctl
        sleep(2);                               // 每隔两秒钟
        ioctl(fd, CMD_TEST3, 1);
        sleep(2);
    }

这里的一一对应的关系如图所示
在这里插入图片描述
这样,我们的实验结果就是,可以正常的写入数据
在这里插入图片描述

使用_IOR

有些时候我们需要读取按键的值,或者引脚的状态,使用_IOR就会很方便

在应用函数里,设置如下,传入value的地址到ioctl函数

    while(1){
        ioctl(fd, CMD_TEST4, &value);                   // 触发驱动中的.unlocked_ioctl
        printf("app value is %d\n", value);
        sleep(2);                               // 每隔两秒钟
<span class="token punctuation">}</span>

在驱动函数中,依然要使用copy_to_user函数,复制数据从底层到应用层中,所以,在这里第一个参数就是应用层的value的地址,因为是int型指针,所以要强制转换一下,然后第二个参数就是底层的val值,第三个就是底层val的长度大小

    case CMD_TEST4:
        val = 12;
        if( copy_to_user((int *)value, &val, sizeof(val)) != 0 ){
            printk("copy_to_user error!!!\n");
            return -1;
        }
        break;

实验结果

在这里插入图片描述
我们程序中的val可以替换为底层io口的状态。

完整代码

module_leds.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define CMD_TEST0 _IO(‘L’, 0) // 'L’是幻数 0是编号
#define CMD_TEST1 _IO(‘L’, 1)

#define CMD_TEST2 _IOW(‘L’, 2, int)
#define CMD_TEST3 _IOW(‘L’, 3, int)

#define CMD_TEST4 _IOR(‘L’, 4, int)

int misc_open (struct inode inode, struct file file){

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"hello misc_open!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

int misc_release(struct inode inode, struct file file){

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"bye bye misc_release!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

ssize_t misc_read(struct file file, const char __user ubuf, size_t size, loff_t *loff_t){

<span class="token keyword">char</span> kbuf<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"copy to user!!!\n"</span><span class="token punctuation">;</span>

<span class="token keyword">if</span><span class="token punctuation">(</span> <span class="token function">copy_to_user</span><span class="token punctuation">(</span>ubuf<span class="token punctuation">,</span> kbuf<span class="token punctuation">,</span> size<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"copy_to_user error!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"hello misc_read!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

ssize_t misc_write(struct file file, const char __user ubuf, size_t size, loff_t *loff_t){

<span class="token keyword">char</span> kbuf<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"copy from user!!!\n"</span><span class="token punctuation">;</span>
<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"hello misc_write!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span> <span class="token function">copy_from_user</span><span class="token punctuation">(</span>kbuf<span class="token punctuation">,</span> ubuf<span class="token punctuation">,</span> size<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"copy_from_user error!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"buf is:%s\n"</span><span class="token punctuation">,</span> kbuf<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

long misc_ioctl(struct file file, unsigned int cmd, unsigned long value)
{
int val;
switch (cmd)
{
case CMD_TEST2:
printk(“LED_ON!!!\n”);
printk(“value is %d\n”, value);
break;
case CMD_TEST3:
printk(“LED_OFF!!!\n”);
printk(“value is %d\n”, value);
break;
case CMD_TEST4:
val = 12;
if( copy_to_user((int )value, &val, sizeof(val)) != 0 ){
printk(“copy_to_user error!!!\n”);
return -1;
}
break;

<span class="token keyword">default</span><span class="token punctuation">:</span>
    <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write,
.unlocked_ioctl = misc_ioctl,
};

struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = “hello_misc”,
.fops = &misc_fops
};

static int misc_init(void)
{
int ret;

ret <span class="token operator">=</span> <span class="token function">misc_register</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>misc_dev<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span><span class="token punctuation">(</span>ret <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"misc_register failed!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"misc_register succeed!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>           <span class="token comment">// 在内核中无法使用c语言库,所以不用printf</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

static void misc_exit(void)
{
misc_deregister(&misc_dev);

<span class="token function">printk</span><span class="token punctuation">(</span><span class="token string">"misc exit!!!\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

module_init(misc_init);
module_exit(misc_exit);

MODULE_LICENSE(“GPL”); //声明模块拥有开源许可

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/ioctl.h>

#define CMD_TEST0 _IO(‘L’, 0) // 'L’是幻数 0是编号
#define CMD_TEST1 _IO(‘L’, 1)

#define CMD_TEST2 _IOW(‘L’, 2, int)
#define CMD_TEST3 _IOW(‘L’, 3, int)

#define CMD_TEST4 _IOR(‘L’, 4, int)

int main(int argc, char *argv[])
{
int fd;

<span class="token keyword">int</span> value<span class="token punctuation">;</span>

fd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/dev/hello_misc"</span><span class="token punctuation">,</span> O_RDWR<span class="token punctuation">)</span><span class="token punctuation">;</span>       <span class="token comment">// 打开节点时候触发open函数</span>

<span class="token keyword">if</span><span class="token punctuation">(</span>fd <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>

    <span class="token function">perror</span><span class="token punctuation">(</span><span class="token string">"open error\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                 <span class="token comment">// perror在应用中打印</span>
    <span class="token keyword">return</span> fd<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">while</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token function">ioctl</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> CMD_TEST4<span class="token punctuation">,</span> <span class="token operator">&amp;</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>                   <span class="token comment">// 触发驱动中的.unlocked_ioctl</span>
    <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"app value is %d\n"</span><span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                               <span class="token comment">// 每隔两秒钟</span>

<span class="token punctuation">}</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

            </div>
            <link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/markdown_views-22a2fefd3b.css" rel="stylesheet">
            <link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/style-4f8fbf9108.css" rel="stylesheet">
    </div>
Linux驱动开发 -----高级I/O操作(ioctl设备操作) 一个设备除了能通过读写操作来收发数据或返回、保存数据,还与许多操作。这些操作内核委派给ioctl。 ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。 两个函数: ioctl : #include &lt;sys/ioctl.h&gt; int ioctl(int d, int request,... 阅读详情

相关推荐

嵌入式开发系统学习路线:从硬件认知到Linux驱动与AI部署实战

嵌入式系统作为融合计算机体系结构、电子电路与操作系统的专用计算机系统,其核心在于针对特定任务进行软硬件协同设计。从原理层面看,嵌入式开发涉及处理器架构、外设接口通信、实时调度等关键技术,其技术价值体现在对资源、功耗和可靠性的极致优化。在应用场景上,嵌入式系统广泛应用于智能家居、工业控制、边缘计算等领域。随着物联网和人工智能技术的发展,嵌入式AI部署和边缘计算成为行业热点。本文基于嵌入式Linux和单片机开发实践,系统梳理了从开发环境搭建、外设驱动到系统移植的完整知识体系,并探讨了TensorFlow Lit

312

测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android

用来控制一些GPIO引脚和电源LED的程序,可以根据不同的参数来执行不同的命令。

我其实什么都不会 2534

Linux嵌入式开发:使用C语言编写简单的GPIO控制代码

需要注意的是,上述代码只是一个简单的示例,实际的GPIO控制操作可能会更加复杂。在实际的嵌入式开发中,可能需要考虑更多的因素,如错误处理、GPIO引脚的初始化和释放、使用延时函数等。在嵌入式系统中,通过控制GPIO引脚的高低电平,我们可以实现对外部设备的控制和与之的交互。本文将介绍如何使用C语言编写简单的GPIO控制代码,在Linux嵌入式系统中实现对GPIO引脚的控制。然后,我们定义了几个函数,分别用于导出GPIO控制文件、设置GPIO引脚为输出模式、以及控制GPIO引脚输出高电平和低电平。

CyberBytezZ的博客 604

Linux应用程序——用户层操作GPIO

stm32mp157 盘古开发板 Linux内核版本4.19 目录 1、拜兔核i2SOM的wiki上关于gpio应用的说明 2、gpio操作相关的数据结构 3、测试代码: 4、参考链接 1、拜兔核i2SOM的wiki上关于gpio应用的说明 链接:http://wiki.i2som.com/pages/viewpage.action?pageId=22479311 以下是链接中的复制内容: GPIO操作在Linux系统上是常用功能,STM32MP1芯片平台也同样支持。从Linu...

fang_yang_wa的博客 4560

TI 实时操作系统SYS/BIOS使用总结

1:概述: SYS/BIOS 是一个可扩展的实时的操作系统。具有非常快速的响应时间(在中断和任务切换时达到较短的延迟),响应时间的确定性,强壮的抢占系统,优化的内存分配和堆栈管理(尽量少的消耗和碎片)。能够实现系统的模块化并可裁剪。 最大的特点就是:实时。 2:XDCtools: XDCtools 是SYS/BIOS引用的一种实时的软件组件技术(RTSC),它包括一些有用的工具,标准的AP

带头奋青的博客 5万+

告别环境配置焦虑:在Win10的Ubuntu子系统里搞定CSAPP实验环境(附32/64位库编译指南)

本文详细介绍了如何在Win10的Ubuntu子系统中搭建CSAPP实验环境,包括WSL 2的安装与配置、32/64位库的编译指南以及高效开发工具链的设置。通过优化WSL性能和使用实用技巧,开发者可以轻松应对CSAPP实验中的环境配置问题,提升学习效率。

weixin_30443813的博客 297

从入门到实战:Linux GPIO_LED 驱动开发(ioctl 接口实现)

本文介绍了嵌入式Linux中通过ioctl接口控制LED的驱动开发流程。ioctl是Linux内核提供的设备控制接口,支持"命令+数据"交互方式,适合LED等外设控制。文章详细解析了ioctl命令码的32位组成结构,包括传输方向、数据大小、魔数和命令编号。开发流程涉及杂项设备注册、GPIO操作和ioctl命令交互等核心内容,配套代码可直接编译运行,帮助初学者快速掌握GPIO外设开发技能。

Arockdj的博客 1512

Dual-stream multiple instance learning networks for tumor detection in Whole Slide Image——论文笔记

关于多示例学习的资料网上比较少,但是在医学图像方面还是有人在应用的。主要是因为一般比较大,几个G都是十分常见的,这么大图片是无法直接训练,一般都会进行切图,所以天然契合多示例学习bag和instance的概念。最近看了一篇论文刚好关于这方面的,所以做下笔记。 github地址:https://github.com/binli123/dsmil-wsi paper:https://arxiv.org/abs/2011.08939 背景知识 在多示例学习(MIL)中,一组训练样本被视为包含多个instance的

weixin_41693877的博客 4170

Linux嵌入式驱动开发07——GPIO驱动过程记录(飞凌开发板)

1. 在/arch/arm/boot/dts/imx6q-pinfunc.h查找 /arch/arm/boot/dts 打开头文件 imx6q-pinfunc.h 查找EIM_A17 #define MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x0f4 0x408 0x000 0x5 0x0 2. 在设备树配置文件中添加设备节点定义以及其引脚定义 然后,我们要在设备树中添加引脚定义,打开imx6qdl-sabresd.dtsi imx6qdl-sab

“逛丢一只鞋”的博客 2763

基于CLICKHOUSE的数据仓库分层规范

接入层。

zjyy1987的博客 770

10|Git Diff 与增量代码识别:本次到底改了哪些代码?

本文介绍 Git Diff 和增量代码识别,帮助你理解精准测试如何先找到本次真正变化的代码。测试开发工程师。Java 后端开发工程师。质量平台 / DevOps 平台建设者。想了解精准测试落地方法的技术负责人。

专注 AI 精准测试平台实战落地,分享从代码 Diff 到回归决策的完整工程闭环。主张“先建数据链路,再上 AI 智能”,让测试从“靠经验”走向“基于风险”。 160

嵌入式linux led驱动有几种写法,嵌入式linux下LED驱动教程

在嵌入式系统的设计中,LED一般直接由CPU的GPIO(通用可编程I/O口)控制。GPIO一般由两组寄存器控制,即一组控制寄存器和一组数据寄存器。控制寄存器可设置GPIO口的工作方式为输入或是输出。当引脚被设置为输出时,向数据寄存器的对应位写入1和0会分别在引脚上产生高电平和低电平;当引脚设置为输入时,读取数据寄存器的对应位可获得引脚上的电平为高或低。LED设备介于字符设备和块设备之间我们称之为m...

weixin_39709262的博客 236

AutoSAR从0开始实战 --- 目录

​​​​​​本专栏是全网最真实的AutoSAR实战专栏,博主将从一个0基础小白的身份来讲解AutoSAR工具的配置,以及相应代码的讲解。

wj博客 1729

[嵌入式Linux驱动]S5PV210的蜂鸣器Linux驱动

智能家居报警器控制驱动程序: 1. 本驱动使用platform模型进行设计,分为Alarm_Beeper_device和Alarm_Beeper_driver两个文件 2. 注册杂项设备(misc),主设备号固定是10(misc),从设备号由系统自动分配,加载成功后使用lsmod可以看到:      Alarm_Beeper_device      Alarm_Beeper_driver

kinyanderson的专栏 1300

北斗导航 | 卡尔曼滤波与因子图优化对比(附图优化matlab代码)

- 历史数据利用:因子图通过滑动窗口保留历史状态,优化时联合多帧数据;卡尔曼滤波仅依赖当前和上一帧状态 。 - 迭代优化:因子图通过多次迭代逼近最优解,卡尔曼滤波仅单次更新 。 - 误差抑制:因子图的多次线性化可有效抑制非线性误差(如GNSS伪距观测的非线性) 。

尘世冰封的专栏 1303

【WRF-Urban数据集】中国60个城市的1 km分辨率城市冠层参数(UCPs)

中国60个城市的1 km分辨率城市冠层参数(UCPs)

WW、forever的博客 1068

嵌入式开发三大方向对比:MCU、Linux应用与驱动开发指南

嵌入式系统作为连接硬件与软件的核心技术,其开发主要围绕微控制器(MCU)、操作系统和应用层展开。从技术原理来看,MCU开发直接操作硬件寄存器,强调实时性和资源优化;Linux应用开发基于系统调用,利用操作系统提供的抽象层实现功能;而Linux驱动开发则深入内核空间,充当硬件与操作系统的桥梁。在工程实践中,这三种技术路径对应不同的技能要求:MCU开发需要掌握电路基础和RTOS,Linux应用开发侧重系统编程和网络通信,驱动开发则要求深入理解内核机制和硬件协议。对于智能家居、工业控制和物联网等应用场景,开发者需

weixin_34211761的博客 352

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

深入RK3568 GPIO:从硬件架构到Linux驱动实战

GPIO(通用输入输出)是嵌入式系统与外部世界交互的基础接口,其核心原理是通过控制微控制器引脚的电压电平来实现数字信号的输入与输出。在Linux系统中,GPIO子系统通过gpiolib等抽象层,将硬件差异统一为标准的设备树配置与驱动API,极大地提升了驱动开发的效率与可移植性。对于RK3568这类高性能AIoT SoC,深入理解其GPIO的硬件架构(如Bank/Port划分、复用功能)与内核驱动模型(如gpio_chip、GPIO描述符),是进行可靠外设控制、实现高效中断处理以及优化系统功耗管理的技术基石。

weixin_34174105的博客 389

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

从零构建嵌入式PWM驱动:揭秘RK3566泰山派与Linux内核的深度对话

本文深入探讨如何在RK3566泰山派开发板上从零构建嵌入式PWM驱动,详细解析Linux内核PWM子系统架构、设备树配置、内核驱动开发及用户空间控制策略。通过实战案例展示如何利用sysfs接口控制直流电机,为嵌入式开发者提供了一套完整的技术方案和深度优化技巧。

linux6sysadmin的博客 1086

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Linux 设备驱动开发(一)

Linux 内核是一款复杂、可移植、模块化且广泛使用的软件,约 80%的服务器和超过一半的全球嵌入式系统都在运行该软件。设备驱动程序在 Linux 系统性能方面起着至关重要的作用。随着 Linux 成为最受欢迎的操作系统之一,对于开发个人设备驱动程序的兴趣也在稳步增长。设备驱动程序是用户空间和设备之间的链接,通过内核。本书将从两章开始,帮助您了解驱动程序的基础知识,并为您在 Linux 内核中的漫长旅程做好准备。

龙哥盟 1530

Linux设备驱动开发实战:从设备树到OLED驱动全链路

Linux设备驱动是内核空间与硬件交互的核心技术,其本质是构建内核可识别、可调度、可安全卸载的硬件抽象层。理解设备树(Device Tree)作为硬件描述与驱动匹配的契约机制,掌握字符设备驱动框架中生命周期管理与状态机设计思想,是突破‘编译通过但加载失败’困境的关键。结合I2C总线协议、GPIO控制、ioctl接口设计等底层原理,驱动开发不仅涉及寄存器操作与中断处理,更强调系统级可靠性——如资源自动释放(devm_系列API)、原子上下文安全(gpiod_cansleep)、脏区域优化等工程实践。本文以SS

weixin_29194693的博客 235

嵌入式Linux驱动开发实战:设备树、调试与硬件协同

嵌入式驱动开发是连接硬件物理特性与Linux内核抽象模型的关键桥梁,其核心在于理解设备树的静态描述机制、驱动框架的动态匹配原理,以及寄存器级硬件行为与内核子系统(如I2C、MIPI、中断、DMA)的协同逻辑。技术价值体现在将芯片手册中的时序约束、电气参数和协议规范,转化为可验证、可调试、可量产的内核模块;典型应用场景包括USB转串口(CP2102)、摄像头(OV5695)等外设在RK3568等SoC平台的Bring-up与问题定位。本文聚焦‘设备树’与‘调试’两大高频痛点,结合逻辑分析仪波形分析、fdtge

weixin_34393428的博客 271

深入理解Linux SPI驱动框架:以SSD1306 OLED模块为例,剖析字符设备驱动开发全流程

本文深入解析Linux SPI驱动框架,以SSD1306 OLED模块为例,详细讲解字符设备驱动开发全流程。从SPI子系统架构、设备树配置到字符设备注册和文件操作集设计,全面剖析Linux驱动开发的核心技术。通过实际代码示例,帮助开发者掌握SPI通信协议实现、用户空间交互设计等关键技能,提升嵌入式Linux驱动开发能力。

weixin_30892763的博客 394

Linux驱动学习记录-13.demo

基于前面所学知识,写了一个完整的小程序,功能如下: App可控制led的亮灭,采用定时器模拟pwm输出,key1增大占空比,led亮度增高,key2减少占空比。 gpio中断控制key,按键按一次,输出此时占空比,每次±10%,范围在0%-100% 两个定时器,定时器1负责输出PWM,定时器2用于按键延迟确认。 窗口输入,可直接设置占空比 可设置输出,显示目前亮度占空比 目录标题一、设备树1.iomuxc设置2.节点设置二、驱动程序1.两个结构体2.入口函数3.gpio初始化4.两个外部中断函数4.两个定时

weixin_41903358的博客 558

Linux V4L2驱动框架实战:从零开始搭建摄像头驱动(附完整代码)

本文提供了一份从零开始构建Linux V4L2摄像头驱动的实战指南。内容涵盖硬件接口配置、V4L2驱动核心结构体初始化、视频缓冲区管理与流式IO实现,并分享了格式协商与调试技巧,旨在帮助嵌入式开发者和Linux驱动工程师深入理解V4L2驱动框架,快速完成驱动开发。

yyy34的博客 556
上一篇: 使用 systemd 开机启动
下一篇: RTL8211千兆网PHY芯片LED灯配置
szembed
博客等级 码龄18年 1475粉丝 256原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值