您的位置:首页 > 运维架构 > Linux

linux驱动开发之一个真正的设备驱动需要一些什么元素(设备号,操作方法)

2018-01-27 17:52 471 查看
1,需要一个设备号(重点看下面的代码)

因为内核中有很多的设备驱动,所以需要一个设备号id来进行区分

设备号分成两个部分:

主设备号:某一类设备

次设备号: 某类设备中某个设备设备

比如:前置和后置摄像头都是camera这类设备

前置 : 0

后置 : 1

在内核中: dev_t来表示设备号,

32bit的整数

高12bit: 主设备号

低20bit:次设备号

(1)申请设备号函数

//参数1—指定一个号码也可以由系统分配,填0表示由系统分配

//参数2–字符串–描述设备驱动信息–自定义

//参数3—文件操作对象

// 返回值—如果是系统分配,返回分配之后的号码,否则返回负数为错误

int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

(2)卸载设备号函数

//参数1—已经申请到的设备号

//参数2–字符串–描述设备驱动信息–自定义

void unregister_chrdev(unsigned int major, const char *name)

备注:怎样在开发板查看驱动模块是否装载成功 用cat /proc/devices

2,需要一个设备文件

linux中将所有的设备都看成是文件,操作设备其实就是操作文件

设备文件称为设备节点

系统中所有的设备节点都在    ls -l /dev/
crw--w----  1 root     tty       4,  10 Nov 23 00:41 tty10
crw--w----  1 root     tty       4,  11 Nov 23 00:41 tty11
crw--w----  1 root     tty       4,  12 Nov 23 00:41 tty12


(c表示字符设备,b表示块设备)

创建: 手动和自动创建
手动:每次都要创建, /dev中所有的文件都是在内存中
mknod 文件名   类型 主设备号  次设备号

mknod /dev/hello c 254 0

[root@ubuntu /drv_module]# ls /dev/hello -l
crw-r--r--    1 0        0         254,   0 Jan  1 00:52 /dev/hello


驱动可以操作底层硬件,并且为应用服务的,例如驱动可以操控led亮或者灭,但是怎样亮灭,亮灭多久,是应用程序决定的。即如果只有驱动程序,没有应用程序,驱动程序就没有任何作用



3,需要一个设备的操作方法

int hello_drv_open(struct inode *inode, struct file *filp)
{

printk("-------^_^ %s-------\n", __FUNCTION__);
return 0;

}

const struct file_operations hello_fops = {
.open = hello_drv_open,

};


编译工具:source insight 4.0

驱动程序:hello_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>

static int dev_major;//申请的设备号

int hello_drv_open(struct inode *inode, struct file *filp)
{

printk("-------^_^ %s-------\n", __FUNCTION__);
return 0;

}

//文件操作对象int (*open) (struct inode *, struct file *);
const struct file_operations hello_fops = {
.open = hello_drv_open,//当应用程序调用open,实际是调用驱动程序中(该程序)的xxx_open()

};

//实现驱动模块的装载函数-----insmod
// 模块加载函数中主要完成系统资源的申请
static int __init hello_init(void)
{
printk("-------^_^ %s-------\n", __FUNCTION__);

// 需要有一个设备号----申请/注册
//参数1---指定一个号码也可以由系统分配,填0表示由系统分配
//参数2--字符串--描述设备驱动信息--自定义--/proc/devices
//参数3---文件操作对象
// 返回值---如果是系统分配,返回分配之后的号码,否则返回负数为错误
dev_major = register_chrdev(0, "hello_drv",  &hello_fops);
if(dev_major < 0)
{
printk("register_chrdev error\n");
return -EINVAL;//注意有负号
}
return 0;
}

//实现驱动模块的卸载函数
// 模块卸载函数中主要完成系统资源的释放
static void __exit hello_exit(void)
{
printk("-------^_^ %s-------\n", __FUNCTION__);

//参数1---已经申请到的设备号
//参数2--字符串--描述设备驱动信息--自定义
//卸载这类型的函数一般没有返回值
unregister_chrdev(dev_major, "hello_drv");
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");


应用程序:hello_app.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd = open("/dev/hello", O_RDWR);
return 0;
}


Makefile

CROSS_COMPILE = arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
APP_NAME = hello_app
MODULE_NAME = hello_drv

#内核源码路径
KERNEL_DIR = /home/ubuntu/s5pv210/kernel/linux-3.0.8

CUR_DIR = $(shell pwd)

all :
#表示进入到内核目录,并且告诉内核要将当前的源码编译成模块
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
$(CC) $(APP_NAME).c -o  $(APP_NAME)

clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
rm -rf $(APP_NAME)

install:
cp -raf  *.ko $(APP_NAME)  /opt/rootfs/drv_module/

#指定编译哪个源文件
obj-m = $(MODULE_NAME).o


执行应用程序./hello.app



查看设备节点:

cat /proc/devices



可知设备号为254,设备节点时hello_drv
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: