迅为嵌入式linux驱动开发笔记(五)—pinctl和gpio子系统_gpio_get_value

label : 给 gpio 设置个名字。 返回值: 0 , 申请成功;其他值,申请失败。

2 、 gpio_free 函数

作用:如果不使用某个 GPIO 了,那么就可以调用 gpio_free 函数进行释放。

函数原型: void gpio_free(unsigned gpio)

参数: gpio : 要释放的 gpio 标号。

返回值:无。

3 、 gpio_direction_input 函数

作用: 此函数用于设置某个 GPIO 为输入

函数原型:

int gpio\_direction\_input(unsigned gpio) 

参数 : gpio : 要设置为输入的 GPIO 标号。

返回值:设置成功返回 0 ; 设置失败返回负值

4 、 gpio_direction_output 函数
作用:此函数用于设置某个 GPIO 为输出,并且设置默认输出值

函数原型:

int gpio\_direction\_output(unsigned gpio, int value)

参数:

gpio : 要设置为输出的 GPIO 标号。

value : GPIO 默认输出值。 返回值:设置成功返回 0 ; 设置失败返回负值

5 、 gpio_get_value 函数

作用: 此函数用于获取某个 GPIO 的值 (0 或 1)

函数原型:

 int \_\_gpio\_get\_value(unsigned gpio) 

参数:

gpio : 要获取的 GPIO 标号。

返回值:成功返回 GPIO 值,失败返回负值。

6 、 gpio_set_value 函数

作用: 此函数用于设置某个 GPIO 的值 函数原型:

void \_\_gpio\_set\_value(unsigned gpio, int value) 

参数: gpio : 要设置的 GPIO 标号。

value : 要设置的值。 返回值:无

7 、 of_get_named_gpio

函数作用: 此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编 号,此函数会将设备树中类似 <&gpio1 3 GPIO_ACTIVE_LOW> 的属性信息转换为对应的 GPIO 编号,函数原型如下:

int of\_get\_named\_gpio(struct device\_node \*np,const char \*propname,int index) 

参数:

np : 设备节点。

propname : 包含要获取 GPIO 信息的属性名。

index : 因为一个属性里面可能包含多个 GPIO ,此参数指定要获取哪个 GPIO 的编号,如果 只有一个 GPIO 信息的话此参数为 0 。

返回值:

成功返回到的 GPIO 编号,失败返回一个负数。

实践课

使用gpio子系统控制蜂鸣器,基本配置文件如下所示:

				.
				.
				.
				.
				.
				.
				.

    beep_gpio = of\_get\_named\_gpio(test_device_node,"beep\_gpio",0);
    if (beep_gpio < 0){
        printk("of\_get\_named\_gpio is erron\n");
        return -1;
    }

    printk("beep\_gpio is %d\n",beep_gpio);

    ret = gpio\_request(beep_gpio,"beep\_gpio");
    if (ret<0)
    {
        printk("gpio\_request is erron\n");
        return -1;
    }
    
    gpio\_direction\_output(beep_gpio,1);//引脚配置

    ret = misc\_register(&misc_dev);//注册杂项设备
    if (ret<0)
    {
        printk("misc\_register is error\n");
        return -1;
    }

在杂项设备中,颠覆了以往使用蜂鸣器,而使用gpio子系统控制蜂鸣器。

 if (kbuf[0] == 1)
        gpio\_set\_value(beep_gpio,1);//open 寄存器操作换成了GPIO子系统的函数
    else if (kbuf[0] == 0)
        gpio\_set\_value(beep_gpio,0);//close

ioctl接口

unlocked_ioctl 接口

1、什么是 unlocked_ioctl 接口?

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

2、 unlocked_ioctl 和 read/write 函数有什么相同点和不同点?

相同点:都可以往内核写数据。

不同点: read 函数只能完成读的功能,write 只能完成写的功能。 但是读取大数据的时候效率高。

ioctl 既可以读也可以写。读取大数据的时候效率不高。

3、unlocked_ioctl 接口命令规则。
一共是32位。

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

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

第一个分区和第二个分区主要作用是用来区分命令的。编号一样,幻数不能一样。

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

第四个分区: 30-31 代表读写的方向。因为ioctl既可以读也可以写。

00 : 表示用户程序和驱动程序没有数据传递
10 : 表示用户程序从驱动里面读数据
01 : 表示用户程序向驱动里面写数据
11 : 先写数据到驱动里面,然后在从驱动里面把数据读出来。(用得不多)

4、 命令的合成宏与分解宏
合成宏:

\_IO(type,nr) : 用来定义没有数据传递的命令 

\_IOR(type,nr,size) : 用来定义从驱动中读取数据的命令 

\_IOW(type,nr,size) : 用来定义向驱动写入数据的命令

\_IOWR(type,nr,size) :用来定义数据交换类型的命令,先写入数据,再读取数据这类命令。

参数: type : 表示命令组成的魔数,也就是 8~15 位 

nr : 表示命令组成的编号,也就是 0~7 位 

size : 表示命令组成的参数传递大小,注意这里不是传递数字,而是数据类型,如要传递 4 字节,就可以写成 int

分解宏:


\_IOC\_DIR(nr) 分解命令的方向,也就是上面说 30~31 位的值 

\_IOC\_TYPE(nr) 分解命令的魔数,也就是上面说 8~15 位的值 

\_IOC\_NR(nr) 分解命令的编号,也就是上面说 0~7 位 

\_IOC\_SIZE(nr) 分解命令的复制数据大小,也就是上面说的 16~29 位 

参数说明: nr : 要分解的命令

实践课

通过应用层传递参数到驱动层控制硬件io。
驱动层代码:

#define CMD\_TEST0 \_IO('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 \_IOW('L',4,int)


long misc\_ioctl(struct file \*file,unsigned int cmd, unsigned long value)
{
    int val;

    switch(cmd){
        case CMD_TEST0:
            printk("LED ON!!!\n");
            printk("value is %ld\n",value);
            break;
        case CMD_TEST1:
            printk("LED OFF!!!\n");
            printk("value is %ld\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;
        
    }
    return 0;
}

struct file\_operations  misc_fops ={
    .owner = THIS_MODULE,
    .open = misc_open,
    .release = misc_close,
    .read = misc_read,
    .write = misc_write,
    
    .unlocked_ioctl = misc_ioctl//添加结构体成员
};

应用层代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
## 最后

**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/8dbb3739827a9fe70d56f8593b9582b3.png)

![img](https://img-blog.csdnimg.cn/img_convert/801530bbf940885f4ff73cc43244bb7b.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/4103cf92cb8d3fbe903c0d76bcbae3c8.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/07d11fb7a3f3f7096928d202026d833d.png)

![img](https://img-blog.csdnimg.cn/img_convert/e2498e145a902e12ff860a8ef58e69a2.png)

![img](https://img-blog.csdnimg.cn/img_convert/c36fdf736926922b3d1bf1150e311abf.png)

![](https://img-blog.csdnimg.cn/img_convert/94a3ad5ba675c18180abcdb8c07a174c.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


片转存中...(img-KIZM5H9T-1715840791669)]

[外链图片转存中...(img-LSTiNnRt-1715840791669)]

[外链图片转存中...(img-2cGiJLQt-1715840791670)]

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值