混杂设备驱动模型设计LED驱动

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SLASH_24/article/details/54952767

一、使用混杂设备驱动,设计字符设备设备驱动程序的流程

1. 定义一个混杂设备
2. 定义混杂的file_operations和其接口函数
3. 将物理地址申请为内核的一个资源,request_mem_region()
4. 通过ioremap()函数得到物理地址对应的虚拟地址
5. 注册混杂设备 --->已经创建了class和device
6. 访问虚拟地址,控制硬件。


二、混杂设备结构体

混杂设备结构体在内核源码目录下include/linux/miscdevice.h下定义:
struct miscdevice  {
int minor;  
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const char *nodename;
mode_t mode;
};


成员说明:
int minor; --->次设备号,可以指定,也可以动态分配:MISC_DYNAMIC_MINOR
const char *name; --->混杂设备的名字,也是设备文件的名字
const struct file_operations *fops; --->文件操作集

struct list_head list; --->内核链表
struct device *parent; --->父设备
struct device *this_device; --->设备
const char *nodename;
mode_t mode;

三、混杂设备的注册和注销函数

混杂设备的注册函数:
函数原型:int misc_register(struct miscdevice *misc);
参数说明:
struct miscdevice *misc:混杂设备结构体
返回值:
成功返回0,失败返回一个负的错误码。

混杂设备的注销函数:
函数原型:int misc_deregister(struct miscdevice *misc);
参数说明:
struct miscdevice *misc:混杂设备结构体
返回值:
成功返回0,失败返回一个负的错误码。

四、查看混杂设备

混杂设备主设备号在/proc/devices下,如:
cat /proc/devices
混杂设备在/proc/misc下,如:
cat /proc/misc

五、混杂设备驱动设计实例

驱动程序(led_dev.c):

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/miscdevice.h>	//混杂设备相关定义

static struct resource * led_reg_res;
static void __iomem *gpj2_con_val;
static void __iomem *gpj2_dat_val;

static ssize_t led_dev_write(struct file *flip, const char __user *buf, size_t size, loff_t *ops)
{
	int ret;
	char kbuf[1];
	
	if(size != 2)
		return -EINVAL;
	
	ret = copy_from_user(kbuf, buf, size);
	if(ret != 0)
		return -EFAULT;
	
	if(kbuf[0]!=0 && kbuf[0]!=1){
		printk("cmd error\n");
		return -EINVAL;
	}
	
	if(kbuf[1]<0 || kbuf[1]>4){
		printk("args error\n");
		return -EINVAL;
	}
	
	if(kbuf[0]==0)
		writel(readl(gpj2_dat_val) | (1<<(kbuf[1]-1)),gpj2_dat_val);//led off
	else
		writel(readl(gpj2_dat_val)  & ~(1<<(kbuf[1]-1)),gpj2_dat_val); //led on 
	
	return size;
}

//2. 定义led_dev的文件操作集并初始化
static struct file_operations led_fops = {
	.owner = THIS_MODULE,
	//.open = led_dev_open,
	.write = led_dev_write,
	//.release = led_dev_release,
};

//1. 定义一个混杂设备的cdev
static struct miscdevice led_misc_cdev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "led_drv",
	.fops = &led_fops,
};

static int __init led_dev_init(void)
{
	int ret = -1;
	
	//3. 将物理地址申请为内核的一个资源
	led_reg_res = request_mem_region(0xE0200280, 8, "GPJ2_LED");
	if(led_reg_res == NULL){
		printk("request mem region error\n");
		ret = -EBUSY;
		return ret;
	}
	
	//4. 将物理地址映射为虚拟地址
	gpj2_con_val = ioremap(0xE0200280, 8);
	if(gpj2_con_val == NULL){
		printk("ioremap error\n");
		ret = -EFAULT;
		goto ioremap_error;
	}
	
	gpj2_dat_val = gpj2_con_val + 4;
	
	//5. 注册混杂设备到内核
	ret = misc_register(&led_misc_cdev);
	if(ret < 0){
		printk("misc register is error\n");
		goto misc_reg_error;
	}
	
	writel((readl(gpj2_con_val) & (~0xFFFF) )| 0x1111,gpj2_con_val);
	writel(readl(gpj2_dat_val)  | 0xF,gpj2_dat_val);
	
	printk("led_dev init\n");
	
	return 0;

misc_reg_error:
	iounmap(gpj2_con_val);
ioremap_error:
	release_mem_region(0xE0200280,8);
	
	return ret;
}

static void __exit led_dev_exit(void)
{
	release_mem_region(0xE0200280,8);
	iounmap(gpj2_con_val);
	misc_deregister(&led_misc_cdev);
	
	printk("led_dev exit\n");
}

module_init(led_dev_init); 
module_exit(led_dev_exit); 
MODULE_LICENSE("GPL");

编译文件(Makefile):

obj-m += led_dev.o 
KERN_DIR=/home/gec/linux-2.6.35.7-gec-v3.0-gt110

modules:
	$(MAKE) -C $(KERN_DIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KERN_DIR) M=$(PWD) modules clean

测试文件(test.c):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main(void)
{
	int fd;
	char buf[2]; 
	fd = open("/dev/led_drv", O_WRONLY); 
	if(fd < 0){
		perror("open led_drv");
		return -1;
	}
	
	while(1){
		buf[0]=1; buf[1]=2;//D2 亮
		write(fd,buf,2);
		sleep(1);
		buf[0]=0; buf[1]=2;//D2 灭
		write(fd,buf,2);
		sleep(1);		
	}
	
	close(fd);
	
	return 0;
}


展开阅读全文

没有更多推荐了,返回首页