设备驱动分类、设备号、字符设备

一、设备驱动分类

设备驱动分为三大类:字符设备、块设备、网络设备

1.字符设备

该设备对数据的处理按照字节流的形式进行的,支持顺序访问(是有时间的概念),也可以支持随机访问

典型的字符设备:串口、键盘、触摸屏、摄像头、I2C、SPI、声卡、帧缓冲设备

顺序访问的设备:串口、键盘、触摸屏

随机访问的设备:帧缓冲设备

2.块设备

该设备的处理按照若干个块来进行的。一个块的固定大小512字节、4096字节。这类设备支持随机访问,这种以块和随机访问能够提高数据存储效率。

块设备往往是面向于存储类的设备: nand flash、SD卡、U盘、eMMC、硬盘

3.网络设备

网络设备是比较特殊的,在/dev没有设备文件,它就是专门针对网络设备的一类驱动,其主要作用是进行网络的数据收发。

网络类设备:有线网卡、无线WiFi网卡(RT3070)、无线GPRS网卡、无线4G网卡
应用程序:socket套接字

二、设备号

主设备号:区分某一类的设备。
ttySAC这是串口设备,主设备号为204;
mmcblk0这是电子硬盘属于块设备,主设备号为179.

次设备号:用于区分同一类设备的不同个体或不同分区。

串口设备:串口0串口3,则使用次设备号6467进行区分。

电子硬盘设备:分区1分区7,则使用次设备号17进行区分。

设备号 = 主设备号 + 次设备号

三、code

基本流程:

申请设备号
1)静态注册
MKDEV
register_chrdev_region
2)动态注册
alloc_chrdev_region
定义一个字符设备,struct cdev
定义file_operations,初始化打开、关闭、读、写等函数接口。
cdev初始化
.cdev_init
将cdev加入到内核
.cdev_add
创建设备文件
.手动创建,使用mknod去/dev目录进行创建
mknod [设备名称] [设备类型] [主设备号] [次设备号]
.自动创建
1)class_create
2)device_create

led_drv.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>

static dev_t myled_num;				//设备号
static struct cdev led_cdev;		//设备
static struct class *led_class;		//设备类
static struct device *led_device;	//设备文件信息

int myled_release (struct inode *inode, struct file *file);
int myled_open (struct inode *inode, struct file *file);
ssize_t myled_read (struct file *, char __user *, size_t, loff_t *);
ssize_t myled_write (struct file *, const char __user *, size_t, loff_t *);
// long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

static struct file_operations led_ops = {
	.owner		= THIS_MODULE,
	.open		= myled_open,
	.release	= myled_release,
	.write 		= myled_write,
	.read		= myled_read,
	//  .unlocked_ioctl = ,
};
int myled_release(struct inode *inode, struct file *file)
{
	printk("<6>""myled_release\n");
	return 0;
}

int myled_open(struct inode *inode, struct file *file)
{
	printk(KERN_INFO"myled_open\n");
	return 0;
}

ssize_t myled_read (struct file *file, char __user *buf, size_t len, loff_t *loff)
{
	int ret;
	char kbuf[] = "hello world";
	ret = copy_to_user(buf,kbuf,sizeof kbuf);//返回未拷贝成功的字节数
	ret = len -	ret;
	printk(KERN_INFO"myled_read\n");

	return ret;
}

ssize_t myled_write (struct file *file, const char __user *buf, size_t len, loff_t *loff)
{
	int ret;
	char kbuf[2] = {0};
	if(len > sizeof(kbuf))
		len = sizeof(kbuf);
	ret = copy_from_user(kbuf,buf,len);	//返回未拷贝成功的字节数
	
	ret = len - ret;//得到成功拷贝的字节数

	printk(KERN_INFO"kbuf[0] = %d kbuf[1] = %d\n",*kbuf,kbuf[1]);
	printk(KERN_INFO"myled_write\n");
	return ret;
}

static int __init myled_init(void)
{
	int ret;
#ifdef _STATIC_REGISTCHAR_DEV
	// 1)静态注册
	myled_num = MKDEV(240,0);
	ret = register_chrdev_region(myled_num,1,"myled");//cat  /proc/devices 
	if(ret < 0)
	{
		printk("<7>""register_chrdev_region\n");
		goto err_register_chrdev_region;
	}
	//mknod /dev/myled c 243 0
#endif 

#if 1
	// 2)动态注册
	ret = alloc_chrdev_region(&myled_num,0,1,"myled");
	if(ret < 0)
	{
		printk("<7>""err_alloc_chrdev_region\n");
		goto err_alloc_chrdev_region;
	}
	printk("<6>""major = %d  minor = %d\n",MAJOR(myled_num),MINOR(myled_num));
	//mknod /dev/myled c 243 0
#endif


	//设备初始化
	cdev_init(&led_cdev,&led_ops);
	//将设备加载到内核
	ret = cdev_add(&led_cdev,myled_num,1);
	if(ret < 0)
	{
		printk("<7>""err_cdev_add\n");
		goto err_cdev_add;
	}

	//创建设备类-myled类  /sys/misc
	led_class = class_create(THIS_MODULE,"myled");
	if(IS_ERR(led_class))
	{
		printk("<7>""err_class_crete\n");
		goto err_class_crete;
	}
	//添加设备信息 设备号 设备文件名
	led_device = device_create(led_class,NULL,myled_num,NULL,"myled");
	if(IS_ERR(led_device))
	{
		printk("<7>""err_device_create\n");
		goto err_device_create;
	}
	//ls /dev/myled
	//ls /sys/class/myled
	//cat  /sys/class/myled/myled/uevent
	//cat  /sys/devices/virtual/myled/myled/uevent 

	printk("<6>""myled_init\n");
	return 0;

// err_register_chrdev_region: //静态注册设备出错
// 	return ret;
err_device_create:
	class_destroy(led_class);
err_class_crete:
	cdev_del(&led_cdev);
err_cdev_add:
	unregister_chrdev_region(myled_num,1);
	return ret;
err_alloc_chrdev_region:
	return ret;

}

static void __exit myled_exit(void)
{
	//从设备类中销毁设备信息	
	device_destroy(led_class,myled_num);
	//销毁设备类
	class_destroy(led_class);
	//从内核中删除字符设备
	cdev_del(&led_cdev);
	//设备号的注销
	unregister_chrdev_region(myled_num,1);

	printk("<6>""myled_exit\n");
}


module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");

/*
申请设备号
1)静态注册
MKDEV
register_chrdev_region
2)动态注册
alloc_chrdev_region
定义一个字符设备,struct cdev
定义file_operations,初始化打开、关闭、读、写等函数接口。
cdev初始化
.cdev_init
将cdev加入到内核
.cdev_add
创建设备文件
.手动创建,使用mknod去/dev目录进行创建
mknod    [设备名称]  [设备类型]  [主设备号]  [次设备号]
.自动创建
1)class_create
2)device_create
*/

test.c

#include <stdio.h>
#include <unistd.h>		
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>

#define DEVICE_DIR "/dev/myled"
int main(int argc, char const *argv[])
{
	char buf[2] = {7,1};
	char rbuf[10];
	int len;
	
	int fd_led = open(DEVICE_DIR,O_RDWR);
	if(fd_led < 0)
	{
		perror("open /dev/myled");
		return -1;
	}
	len = write(fd_led,buf,2);
	printf("write = %d len = %d\n",*buf,len);

	bzero(rbuf,10);
	len = read(fd_led,rbuf,10);
	printf("read = %s len = %d\n",rbuf,len);
	sleep(1);

	close(fd_led);
	return 0;
}

Makefile

obj-m += led_drv.o

KERNEL_DIR :=/kernel
CROSS_COMPILE :=linux/arm/arm-eabi-4.8/bin/arm-eabi-
PWD:=$(shell pwd) 


default: 
	$(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_DIR) M=$(PWD) modules
	$(MAKE) clean
	arm-linux-gcc test.c -o test

clean:
	rm *.o *.order .*.cmd *.mod.c *.symvers *.tmp_versions -rf
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Yengi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值