linux字符驱动之概念介绍

一、字符驱动框架

问:应用程序open、read、write如何找到驱动程序的open、read、write函数?

答:应用程序的open、read、write是在C库里面实现的,它里面通过swi val指令去触发一个异常,这个异常就会进入到内核空间,在内核的异常处理函数里面有根据我们传入的val来决定调用system_open还是system_read、system_write函数,这些函数根据我们打开不同的文件、不同的文件就有不同的属性(例如设备类型(字符设备还是块设备还是网络设备)、主设备号),根据这些属性找到更底层的驱动程序。

 

问:什么是主设备号,什么是次设备号

答:Linux主设备号用来区分不同硬件设备类型,如LED和串口之间的区别;
Linux次设备号用来区分不同硬件设备,如串口1和串口2之间的区别;

 

问:通过什么样的方法来找到驱动程序的open函数

答:通过一个注册函数+设备节点

注册函数如下(旧的注册函数,新的以后再说):

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

参数1:主设备号(重要)

参数2:名字(不重要)

参数3:file_operations结构体(重要)

设备节点:

可以手工创建也可以自动创建,这里暂且只说手工创建

mknod  /dev/xxx  c  252  0

创建一个名为/dev/xxx的设备节点,c表示字符设备节点,252是主设备号,0是次设备号。

 

问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?

答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。

例如:module_init(first_drv_init);  //用于修饰入口函数

自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。

例如:module_exit(first_drv_exit);  //用于修饰出口函数
 

 

驱动源程序如下:

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
 
 
int major;
static int first_drv_open(struct inode * inode, struct file * filp)
{
	printk("first_drv_open\n");
	return 0;
}
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
{
	printk("first_drv_write\n");
	return 0;
}
 
/* File operations struct for character device */
static const struct file_operations first_drv_fops = {
	.owner		= THIS_MODULE,
	.open		= first_drv_open,
	.write      = first_drv_write,
};
 
/* 驱动入口函数 */
static int first_drv_init(void)
{
	/* 主设备号设置为0表示由系统自动分配主设备号 */
	major = register_chrdev(0, "first_drv", &first_drv_fops);
	return 0;
}
 
/* 驱动出口函数 */
static void first_drv_exit(void)
{
	unregister_chrdev(major, "first_drv");
}
 
module_init(first_drv_init);  //用于修饰入口函数
module_exit(first_drv_exit);  //用于修饰出口函数	
 
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL");  //遵循GPL协议

Makefile源码如下:

ifneq ($(KERNELRELEASE),)
 
obj-m := first_drv.o
 
else
	
KDIR := /home/opt/EmbedSky/linux-2.6.30.4
 
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers
 
endif

测试程序如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
int main(void)
 
{
	int fd;
	int val = 1;
	fd = open("/dev/xxx",O_RDWR);    //打开名为  /dev/xxx  的设备节点
	if(fd < 0)
	{
		printf("open error\n");
	}
	
	write(fd,&val,4);
	
	return 0;
}

开发板上的测试步骤如下:

[WJ2440]# insmod first_drv.ko 
[WJ2440]# ./first_test 
open error                    //没有创建设备节点
[WJ2440]# cat proc/devices 
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 81 video4linux
 89 i2c
 90 mtd
116 alsa
128 ptm
136 pts
180 usb
188 ttyUSB
189 usb_device
204 tq2440_serial
252 first_drv                //我们创建的字符设备,主设备号252
253 usb_endpoint
254 rtc
 
Block devices:
259 blkext
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
[WJ2440]# mknod /dev/xxx c 252 0        //手动创建一个字符设备节点
[WJ2440]# ls -l /dev/xxx 
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
[WJ2440]# ./first_test                 //有设备节点后成功我们的应用程序运行了
first_drv_open
first_drv_write
[WJ2440]# 

本文参考:

https://blog.csdn.net/lwj103862095/article/details/17468587

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值