现在的位置: 首页 > 综合 > 正文

1、字符设备驱动

2018年04月17日 ⁄ 综合 ⁄ 共 3169字 ⁄ 字号 评论关闭

1、应用程序调用open函数时,内核是如何找到对应的驱动程序:open("/dev/xxx",xx)------>(驱动->open)

首先驱动的初始化函数会调用register_chrdev(major, name, &fops),把该结构体注册进内核的一个数组中。当应用程序调用open打开该设备时,会得到该设备的major,系统的open调用会根据major找到这个结构体,从而调用fops里面的函数。

2、字符设备驱动的框架

#include <linux/module.h>
#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 <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

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

static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
printk("first_drv_write\n");
return 0;
}

static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};

int first_drv_init(void)
{
register_chrdev(123,"first_drv",&first_drv_fops);
return 0;
}

void first_drv_exit(void)
{
unregister_chrdev(123,"first_drv"); //卸载
}

module_init(frist_drv_init);
module_exit(first_drv_exit);

makefile:

obj-m := first.o
KDIR := ~/linux-3.2.0-04.06.00.08
PWD := $(shell pwd)
default:
make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux- modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

3、udev机制自动创建设备节点

      这个方法能避免手工使用mknod led major minor创建设备节点。

#include <linux/module.h>
#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 <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

static int major;
static struct class *firstdrv_class;

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

static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
printk("first_drv_write\n");
return 0;
}

static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};

int first_drv_init(void)
{
major = register_chrdev(0,"first_drv",&first_drv_fops);
firstdrv_class = class_create(THIS_MODULE,"first_drv");
device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"xyz");
return 0;
}

void first_drv_exit(void)
{
device_destroy(firstdrv_class,MKDEV(major,0));
class_destroy(firstdrv_class);
unregister_chrdev(123,"first_drv"); //卸载
}

module_init(frist_drv_init);
module_exit(first_drv_exit);

4、新内核下,注册字符设备驱动程序,不推荐使用register_chrdev。

register_chrdev函数,会使(major,0)......(major,255)都对应于fops,次设备号没有使用到,造成资源的浪费。

而新方法可以使(major,次).....(major,次+n)都对应于fops。

static struct cdev hello_cdev;
static struct class *cls;
static int major;
static int hello_init(void)
{
dev_t devid;

if (major) {
devid = MKDEV(major, 0);
register_chrdev_region(devid, 2, "hello");  /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
} else {
alloc_chrdev_region(&devid, 0, 2, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
major = MAJOR(devid);                     
}

cdev_init(&hello_cdev, &hello_fops);
cdev_add(&hello_cdev, devid, 2);

cls = class_create(THIS_MODULE, "hello");
class_device_create(cls, NULL, MKDEV(major, 0), NULL, "hello0"); /* /dev/hello0 */
class_device_create(cls, NULL, MKDEV(major, 1), NULL, "hello1"); /* /dev/hello1 */
return 0;
}

static void hello_exit(void)
{
class_device_destroy(cls, MKDEV(major, 0));
class_device_destroy(cls, MKDEV(major, 1));
class_destroy(cls);

cdev_del(&hello_cdev);
unregister_chrdev_region(MKDEV(major, 0), 2);
}

抱歉!评论已关闭.