首页 > 系统服务 > 详细

Linux驱动入门篇(二):基本的字符设备模块(1)

时间:2018-01-30 22:39:00      阅读:283      评论:0      收藏:0      [点我收藏+]

  在熟悉了模块的基本框架后,可以开启模块编程的大门了。


  如我们所知,模块编程的目的是驱动各种各样的设备。那么设备分为哪些类型呢?对Linux内核来说,设备分为字符设备、块设备和网络设备。


  今天先谈字符设备。字符设备的特性:只能一个字节一个字节地按顺序读取,不能任意读取。常见的字符设备有键盘、LED、串口等。


预备知识

一、设备号

  每个字符设备都有一个主设备号和次设备号。


  Linux内核允许多个驱动程序共享主设备号,但大多数设备都遵循“一个主设备号对应着一个驱动程序”原则。而次设备号供内核使用,用于确定指向的设备。


  内核中用 dev_t 类型来保存设备号。定义在<linux/types.h>中。dev_t 类型定义一个32位的数,前12位表示主设备号,后20位表示次设备号。为了安全地使用设备号(比如向后兼容),应该始终使用定义在<linux/kdev_t.h>中的宏。

#define MINORBITS    20
#define MINORMASK    ((1U << MINORBITS) - 1)

#define MAJOR(dev)    ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)    ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

  若要通过 dev_t 类型获得主设备号和次设备号:

  MAJOR(dev_t dev);

  MINOR(dev_t dev);


  若要通过主、次设备号得到 dev_t 类型的数:

  MKDEV(int major, int minor);

二、申请和释放设备号

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
            const char *name);

  在<linux/fs.h>中声明了动态分配设备号的函数,成功则返回0。(静态分配使用register_chrdev_region函数,此处不叙述)


  dev:保存申请到的设备号;

  baseminor:请求的第一个次设备号;

  count:连续请求多少个设备号;

  name:设备名,它将出现在/proc/devices和sysfs中。


void unregister_chrdev_region(dev_t from, unsigned count);

  当不再使用设备号时,应该释放它们,以留给其他设备使用。释放设备号函数中,from 为设备号,count 为连续释放的个数。


三、创建和销毁设备文件

  类 UNIX 操作系统中的一条设计思想就是“一切皆文件”。自然,设备也是文件咯。访问设备即是访问设备文件。那么我们就必须为设备创建一个设备文件,以便访问它。


  首先,我们需要通过 cat /proc/devices 来查看我们的设备名对应的设备号。之后就可以创建设备文件了。


  (1)手动创建:mknod filename filetype major minor (在/dev目录下创建)


  (2)自动创建:在系统支持 udev/mdev 的时候,可以自动创建设备文件。首先,在模块初始化代码里调用 class_create宏 为设备在 /sys/class 下创建一个class,再调用 device_create函数 创建对应的设备文件。它们在<linux/device.h>中被声明和定义。


  在模块的清除函数中还需调用 device_destroy 以及 class_destroy 来进行清除不再使用的文件节点和设备文件。

初始化及清除函数

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

dev_t devno;	//设备号

static struct class *my_class;

static int __init mycdev_init(void)
{
	int ret;
	ret = alloc_chrdev_region(&devno, 0, 1, "mycdev");
	if(ret != 0){
		printk(KERN_NOTEICE "Alloc device number failed.");
		return -1;
	}
	
	mycdev_setup();	//此处实现设备初始化及注册设备到内核,暂不实现

	my_class = class_create(THIS_MODULE, "mycdev");
	device_create(my_class, NULL, devno, NULL, "mycdev");

	return 0;
}

static void mycdev_exit(void)
{
	mycdev_del();	//此处实现设备注销

	device_destroy(my_class, devno);
	class_destroy(my_class);

	unregister_chrdev_region(devno);
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE(“Dual BSD/GPL”);


Linux驱动入门篇(二):基本的字符设备模块(1)

原文:https://www.cnblogs.com/salvare/p/8387264.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!