记录开发过程中的问题和功能。毕se代做,小家电开发。 收徒带做企业级项目,帮助毕业生和转行人员顺利找到工作。

LiSun

记录开发过程中的问题和功能。毕se代做,小家电开发。 收徒带做企业级项目,帮助毕业生和转行人员顺利找到工作。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、分配和释放设备号

动态申请设备号:

/*
 dev:设备号--dev_t devid;
 count:是要申请的数量,一般都是一个;
 name:是设备名字
*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

静态申请设备号:

/*
 from:是要申请的起始设备号,也就是给定的设备号;
 count:是要申请的数量,一般都是一个;
 name:是设备名字
*/
int register_chrdev_region(dev_t from, unsigned count, const char *name)

释放(删除)设备号:

/*
 from:是要申请的起始设备号,也就是给定的设备号;
 count:是要申请的数量,一般都是一个;
*/
void unregister_chrdev_region(dev_t from, unsigned count)

二、驱动模块的加载和卸载

module_init(xxx_init); //注册模块加载函数
module_exit(xxx_exit); //注册模块卸载函数

当在终端使用“insmod”命令加载驱动的时候,xxx_init 这个函数就会被调用。
当在终端使用“rmmod”命令卸载具体驱动的时候 xxx_exit 函数就会被调用。

字符驱动模块:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>

#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


#define NEWCHR_CNT			1		  	/* 设备号个数 */
#define NEWCHR_NAME			"newchr"	/* 名字 */



/* newchr设备结构体 */
struct newchr_dev
{
    dev_t  devid;			/* 设备号 	 */
    struct cdev cdev;		/* cdev 	 */
    struct class *class;	/* 类 		 */
    struct device *device;	/* 设备 	 */
    int    major;		    /* 主设备号	 */
    int    minor;			/* 次设备号  */
};

struct newchr_dev newchr;	/* 设备 */

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int chr_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &newchr; /* 设置私有数据 */
    return 0;
}

/*
 * @description		: 从设备读取数据
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t chr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    return 0;
}

/*
 * @description		: 向设备写数据
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t chr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    int retvalue;
    unsigned char databuf[1];
    unsigned char state;

    retvalue = copy_from_user(databuf, buf, cnt);//将用户传递的参数转移到内核中
    if(retvalue < 0)
    {
        printk("kernel write fail!\r\n");
        return -EFAULT;
    }

    state = databuf[0];		/* 获取状态值 */
    /*处理....*/
    return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int chr_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/* 设备操作函数 */
static struct file_operations newchr_fops =
{
    .owner   = THIS_MODULE,
    .open    = chr_open,
    .read    = chr_read,
    .write   = chr_write,
    .release = chr_release,
};

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init chr_init(void)
{
    u32 val = 0;

    /* 注册字符设备驱动 */
	newchr.major = 0;  //将设备号定义为0,则每次都动态申请设备号
    /* 1、创建设备号 */
    if (newchr.major)  		/*  定义了设备号 */
    {
        newchr.devid = MKDEV(newchr.major, 0);
        register_chrdev_region(newchr.devid, newchr_CNT, newchr_NAME);
    }
    else  					/* 没有定义设备号 */
    {
        alloc_chrdev_region(&newchr.devid, 0, newchr_CNT, newchr_NAME);	/* 申请设备号 */
        newchr.major = MAJOR(newchr.devid);	/* 获取分配号的主设备号 */
        newchr.minor = MINOR(newchr.devid);	/* 获取分配号的次设备号 */
    }
    printk("newche major=%d,minor=%d\r\n",newchr.major, newchr.minor);

    /* 2、初始化cdev */
    newchr.cdev.owner = THIS_MODULE;
    cdev_init(&newchr.cdev, &newchr_fops);

    /* 3、添加一个cdev */
    cdev_add(&newchr.cdev, newchr.devid, newchr_CNT);

    /* 4、创建类 */
    newchr.class = class_create(THIS_MODULE, newchr_NAME);
    if (IS_ERR(newchr.class))
    {
        return PTR_ERR(newchr.class);
    }

    /* 5、创建设备 */
    newchr.device = device_create(newchr.class, NULL, newchr.devid, NULL, newchr_NAME);
    if (IS_ERR(newchr.device))
    {
        return PTR_ERR(newchr.device);
    }

    return 0;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit chr_exit(void)
{

    /* 注销字符设备驱动 */
    cdev_del(&newchr.cdev);/*  删除cdev */
    unregister_chrdev_region(newchr.devid, newchr_CNT); /* 注销设备号 */

    device_destroy(newchr.class, newchr.devid);
    class_destroy(newchr.class);
}

module_init(chr_init);
module_exit(chr_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xjq");

Makefil 文件 注意这里需要修改路径,请按照自身路径修改

gedit Makefil

KERNELDIR := /home/xue1995/linux/IMX6ULL/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)

obj-m := newchr.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

终端输入:make -j32

编译成功以后就会生成一个名为“newchr.ko”的驱动模块文件

APP
终端输入:

gedit App.c

导入下面代码

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
使用方法	 :./test /dev/chr    0 关闭
		       ./test /dev/chr    1 打开	
***************************************************************/


/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	unsigned char databuf[1];
	
	if(argc != 3){
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];

	/* 打开驱动 */
	fd = open(filename, O_RDWR);
	if(fd < 0){
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}

	databuf[0] = atoi(argv[2]);	/* 要执行的操作:打开或关闭 */

	/* 向/dev/chr文件写入数据 */
	retvalue = write(fd, databuf, sizeof(databuf));
	if(retvalue < 0){
		printf("Control Failed!\r\n");
		close(fd);
		return -1;
	}

	retvalue = close(fd); /* 关闭文件 */
	if(retvalue < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

终端输入,进行编译:arm-linux-gnueabihf-gcc App.c -o App

运行测试

将编译出来的 newchr.ko 和 App 这两个文件拷贝到 rootfs/lib/modules/4.1.15目录中,重启开发板,在串口工具中,进入到目录 lib/modules/4.1.15 中,输入如下命令加载 newchr.ko 驱动模块:

depmod //第一次加载驱动的时候需要运行此命令
./App /dev/newchr 1

卸载驱动输入如下命令即可:

rmmod newchrled.ko

posted on 2022-08-13 11:00  嵌入式单片机实验室  阅读(38)  评论(0)    收藏  举报
记录开发过程中的问题和功能。毕se代做,小家电开发。 收徒带做企业级项目,帮助毕业生和转行人员顺利找到工作。