内核的杂项驱动开发

目录

1、在Linux中什么是驱动?

2、Linux驱动的设备文件特点

3、Linux下杂项驱动特点

4、Linux下杂项驱动的API 

5、Linux下杂项驱动的开发示例

6、Linux下的内存映射

7、Linux下的GPIO子系统

1、在Linux中什么是驱动?

让一个硬件(文件)正常工作的代码。

在Linux系统中一切皆文件!!!

操作硬件文件接口函数:打开---open;关闭---close;读---read;写---write

上层open会调用内核层的open

上层close会调用内核层的close

2、Linux驱动的设备文件特点

Linux下设备文件分为三大类:

        字符设备文件:几乎所有的设备文件都是字符设备文件

        块设备文件:存储设备---DRAM SD卡 Emmc

        网络设备文件:WiFi...

crw-rw---- 1 root video 81, 0 6  14 09:56 /dev/video0       

    *Linux下设备文件一定都有设备号!

        81,0 就是摄像头设备的设备号!

        就好比ID号

    * 81 是主设备号

        主设备号代表一类设备

    * 0  是次设备号

        次设备号代表这类设备不同设备

    * 81 0 虽说你看到的是两个号

        但是在Linux系统下他俩会合并成

        一个号码--uint32_t 号码

        81 占据高12 位

        0  占据低 20 位

    0000 0101 0001 0000 0000 0000 0000 0000

    这个就是真实的在系统中的设备号!

 3、Linux下杂项驱动特点

杂项设备驱动的特点:

    * Linux下最简单的驱动开发的方法

    * Linux下杂项设备主设备号固定10

    * Linux下杂项设备次设备号0-255

    * 但是系统已经占据了一部分杂项设备

    * 你不知道系统占用了哪个次设备号

      一般为了防止冲突

      所以一般使用杂项设备的时候

      我们往往指定次设备号为 255

      255 代表让系统给你分配一个可以用的

    * 杂项会自动生成一个设备文件

        他也是唯一自动生成设备文件的

        驱动开发的方法

        驱动开发有三种方法:

            杂项

            经典

            Linux2.6

4、Linux下杂项驱动的API 

杂项的关键字: misc

头文件      : <linux/miscdevice.h>

函数的功能:往内核注册一个杂项设备

函数头文件:<linux/miscdevice.h>

            <linux/fs.h>

函数的原型:

    int misc_register(

        struct miscdevice * misc

    )

函数的参数:

    misc:

        就是该杂项注册的核心结构体

        该结构体描述你要注册什么设备!

        描述一个设备:

            生成一个什么名字设备文件

            描述文件的打开的内核函数

            描述文件的关闭的内核函数

             .....................

            设备的设备号

函数返回值:

    成功返回  0

    失败返回  -1

struct miscdevice  {

    int minor;

    const char *name;

    const struct file_operations *fops;

    struct list_head list;

    struct device *parent;

    struct device *this_device;

    const char *nodename;

    umode_t mode;

};

    仅需要填充前三个成员变量即可完成注册

    minor:

        major:主设备号

        minor:次设备号

        255 代表让系统帮你分配一个

    name:

        你要生成一个设备文件

        你要告诉你生成的设备文件

            名字叫什么

        假如说我填的是 ccc

        他就会在 /dev/ccc 文件

    fops:

        文件的接口!

        内核的文件接口!

        内核层也有一套 文件接口!

            open close read write

        用户层去调用 open的时候

            他会间接调用内核层的open

        close read write 也是同理

+++++++++++++++++++++++++++++++++++++++

struct file_operations {

    struct module *owner;

    ........

    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

    ssize_t (*write) (struct file *,

    int (*open) (struct inode *, struct file *);

    int (*release) (struct inode *, struct file *);

    ...........

};

    owner:

        固定填写 THIS_MODULE   

    open:

        内核层的open的函数指针

    release:

        内核层的close的函数指针

    read:

        内核层的read的函数指针

    write :

        内核层的write的函数指针

+++++++++++++++++++++++++++++++++++++++

函数的功能:取消注册一个杂项设备

            自动的删除设备文件

函数头文件:同上

函数的原型:

    int misc_deregister(

        struct miscdevice * misc

    )

函数的参数:

    misc:

        你注册的那个结构体往里填入即可!

函数返回值:

    成功返回  0

    失败返回  -1

 5、Linux下杂项驱动的开发示例

#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/miscdevice.h"
#include "linux/fs.h"
#include "linux/gpio.h"
uint32_t * base = NULL;
#define GPD0_CON  * (base)
#define GPD0_DAT  *(base + 1)

//加载函数
struct miscdevice misc;
struct file_operations ops;
//上层打开/dev/BIGLED 文件就会跳到内核层
//调用这个 myBIGLED_open 
int myBIGLED_open(struct inode * inode, struct file *file)
{
    printk("我是内核层的开灯函数!\r\n");
    /*
        在此处打开LED灯
        如果没有GPIO子系统
        那么你首先想到的方法是什么
    */
    GPD0_DAT|=(0x01<<0);
    
    return 0;
}
//当上层关闭 /dev/BIGLED文件
//就会调用内核层的 myBIGLED_close 函数 
int myBIGLED_close(struct inode * inode, struct file *file)
{
    printk("我是内核层的关灯函数!\r\n");
    /*
        关闭LED灯
    */
    GPD0_DAT&=~(0x01<<0);
    return 0;
}
/*
    GPD0_0 引脚       
    GPD0_CON        0x1140 00A0     
    GPD0_DAT 寄存器    0x1140 00A4
*/

static int __init led_init(void)
{

    ops.owner = THIS_MODULE;
    ops.open  = myBIGLED_open;
    ops.release = myBIGLED_close;
    misc.minor = 255;//系统分配次设备号
    misc.name  = "BIGLED";//在/dev/BIGLED 设备文件
    misc.fops  =&ops;
    int ret = misc_register(&misc);
    if(ret < 0)
    {
        printk("注册失败\r\n");
        return -EINVAL;//加载失败 
    }

    base = ioremap(0x114000A0,8);
    GPD0_CON &=~(0x0F<<0);//清零
    GPD0_CON |=(0x01<<0);//输出

    return 0;
}
//卸载函数 
static void __exit led_exit(void)

{
    misc_deregister(&misc);
        //取消注册设备
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

6、Linux下的内存映射

函数的功能:在内核中映射真实的物理地址

                举个例子:真实物理地址是  0x11111

                通过此函数他会给你返回一个映射后的地址

                0xbbbb

                那么我去访问或者操作0xbbbb 就相当于

                操作 0x11111

    函数头文件:#include <linux/io.h>

    函数的原型:

        void * ioremap(cookie, size)

    函数的参数:

        cookie:

            真实的物理地址

        size:

            你要映射的物理地址的大小

            只要是32位的CPU

            他的寄存器一般都是四字节对齐!

            每个寄存器大小都是四个字节

    函数返回值:

        成功返回映射后的 地址

        失败返回  NULL

 7、Linux下的GPIO子系统

 gpio_request(unsigned gpio, const char * label)

    申请注册使用一个IO

        gpio: 要申请使用哪个IO

        label: 要给这个IO口起个标签名--无所谓

gpio_free(unsigned gpio)

    释放一个GPIO口

        gpio:要释放哪个IO

gpio_direction_output(unsigned gpio, int value)

    要把gpio口设置为输出工作模式!

        有个输出的默认电平---value

                    1 -- 高电平

                    0 -- 低电平

gpio_direction_input(unsigned gpio)

    要把gpio口设置为输入工作模式!

gpio_set_value(unsigned gpio,int value);

    使用此函数的前提是 GPIO口已经是 输出工作模式了

    int value   1 就代表高电平  0 -- 低电平

gpio_get_value(unsigned gpio)

    获取这个IO口的状态

    返回值 int 返回0代表当前低电平

                返回1代表当前高电平

     

针对开发板--exynos4412CPU

它的GPIO口全部定义在

    arch/arm/mach-exynos/include/mach

    此文件夹是开发板的专属文件夹

    有个头文件  gpio.h

    此文件定义着开发板的所有的GPIO口的定义

    举个例子:

        想用  GPM2_3  引脚

        EXYNOS4X12_GPM2(3);

        想用 GPD0_0

        EXYNOS4_GPD0(0); 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andy.w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值