驱动编写、编译、测试过程

题目有点大,好吧,我要记录的确实是我刚开始学写驱动的流程;这里我不会写怎么写Kconfig和配置menuconfig生成.config(本文所讲的驱动特指基于linux的字符设备驱动),

我这里要写的是将驱动程序作为单独模块,手动加载的过程(学习过程)。

  •     1.写驱动程序的入口函数、出口函数及其修饰,形如:

//入口
static int xxx_init()
{
      ……
    return 0;
}

//出口
static void xxx_exit()
{
      ……
}

//修饰
module_init(xxx_init);
module_init(xxx_exit);

  • 2.申请/释放设备号

设备号的操作函数:
  提取主设备号
  主设备号 = MAJOR(dev_t dev_id);
  提取次设备号
  次设别号 = MINOR(dev_t dev_id);
  合并主次设备号
  dev_t dev_id = MKDEV(主设备号,次设备号);


分配相关函数:

 register_chrdev_region //静态分配

alloc_chrdev_region //动态分配

unregister_chrdev_region //释放设备号资源


  • 3.注册/释放cdev结构

  1)分配cdev结构

static struct cdev cdev;

  2)分配file_operations结构

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    …… //关联驱动接口函数
};

  3)将file_operations填充到cdev

cdev_init(&cdev, &led_fops);

  4)注册cdev

 cdev_add(&cdev, dev_id, 1);

   5)释放cdev

cdev_del(&cdev);

  • 4.写具体设备驱动

参照file_operations提供的驱动接口编写驱动程序。

  • 5.编写编译驱动模块的Makefile

MODNAME=xxx #模块名

KERNELDIR=...... #内核路径     


obj-m += $(MODNAME).o

default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:    
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean

  • 6.编译加载内核

make编译 生成.ko模块;

insmod  xx.ko --加载模块

rmmod xx  --卸载模块

cat /proc/devices  --查看模块设备号

知道设备号后,创建设备节点文件(linux下一切皆文件,用户通过设备文件访问设备)

  mknod /dev/设备名 c 主设备号 次设备号;


  • 7.编写测试用应用程序

应用程序open上面创建的设备文件即可访问模块所驱动的设备(需交叉编译后copy到开发板根文件系统)。


  • 一个小例子:

//led_drv.c  驱动程序//

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>

static int major = 0; //主设备号
static int minor = 0;   //次设备号

//分配cdev
static struct cdev cdev;

//定义led_open
static int led_open(struct inode *inode, 
                            struct file *file)
{
    printk("%s\n", __FUNCTION__);
    //设置GPIO为输出然后输出1
    return 0;
}

//定义led_close
static int led_close(struct inode *inode, 
                            struct file *file)
{
    printk("%s\n", __FUNCTION__);
    //设置GPIO为输入
    return 0;
}

//分配初始化led_fops
static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .release = led_close,
};

static int char_drv_init(void)
{
    int retval;
    dev_t dev_id;

    /*1. 分配设备号*/
    if (major) {
        //合并主次设备号
        dev_id = MKDEV(major, minor);
        //静态分配
        retval = register_chrdev_region(dev_id, 
                                    1, 
                                    "my_char");
    } else {
        //动态分配
        retval = alloc_chrdev_region(&dev_id, 
                                    0, 1, "my_char");
        //提取主设备号
        major = MAJOR(dev_id);
        printk("major = %d, minor = %d\n", major, 
                                            minor);
    }
    if (retval) {
        printk("register my char device failed.\n");
        return -1;
    }

    /*2. 分配,初始化cdev*/
    /*2.1 填充struct file_operations*/
    cdev_init(&cdev, &led_fops);
    
    /*3. 注册cdev*/
    /*3.1 初始化设备号,设备个数然后注册*/
    cdev_add(&cdev, dev_id, 1);

    /*4. GPIO资源申请*/
    return 0;
}

static void char_drv_exit(void)
{
    dev_t dev_id = MKDEV(major, minor);

    /*释放cdev*/
    cdev_del(&cdev);
    
    //释放设备号资源
    unregister_chrdev_region(dev_id, 1);
}

module_init(char_drv_init);
module_exit(char_drv_exit);
MODULE_LICENSE("GPL v2");


led_test.c  测试用应用程序//
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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

    fd = open("/dev/myled", O_RDWR);//访问设备
    if (fd < 0) {
        printf("open led device failed.\n");
        return -1;
    }

    sleep(2);

    close(fd);//结束访问
    return 0;
}
























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值