杂项设备驱动和自动创建设备结点

本文介绍了如何在Linux中使用杂项设备驱动,包括填充`miscdevice`结构体、注册和注销设备、自动创建设备结点、处理中断以及使用ioremap映射内存。示例代码展示了创建ADC设备驱动的过程,包括初始化、读写操作和中断处理。
摘要由CSDN通过智能技术生成

杂项设备驱动

我们复制一个以前的驱动文件修改

主要是两步

1.填充结构体  miscdevice

这个结构体我们就用前三个成员,如下

2.注册杂项设备、生成设备结点

misc_register       参数是我们上个结构体的地址

misc_deregister删除设备,驱动注销时也要写上

编译

make uImage            --------》     板子运行

然后就可以向板子上添加了

自动创建设备结点

主要用到两个函数

1.class_create

2.device_create 导出设备信息到用户空间

如下

此外,提供一种自动创建设备号的方法

示例

adc_automknod.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <mach/irqs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/device.h>

#define MAJOR_NUM 247
#define MINOR_NUM 0
#define DEV_NAME "adc2"
static wait_queue_head_t wq;
static int condition = 0;
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;

static void adc_init(void)
{
	*adccon = (1 << 14) | (49 << 6);
}

static void adc_start(void)
{
	*adccon |= (1 << 0);
}

static unsigned short adc_read(void)
{
	unsigned short adc_value = *adcdat0 & 0x3ff;
	return adc_value;
}

static irqreturn_t adc_handler(int irq, void * arg)
{
	condition = 1;
	wake_up_interruptible(&wq);	

	printk("irq = %d\n", irq);
	return IRQ_HANDLED;
}

static int open(struct inode * node, struct file * file)
{
	adc_init();
	printk("kernel open \n");
	return 0;
}

static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * loff)
{
	unsigned short data = 0;
	adc_start();
	condition = 0;
	wait_event_interruptible(wq, condition);
	
	data = adc_read();
	copy_to_user(buf, &data, sizeof(data));	

	printk("kernel read\n");
	return sizeof(data);
}

static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * loff)
{
	printk("kernel write \n");
	return 0;
}

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

static dev_t dev_num;
static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.release = close
};
static struct cdev dev;
static struct class * pcls;
struct device * pdev;

static int __init adc2_init(void)
{
	int ret = 0;
	dev_num = MKDEV(MAJOR_NUM, MINOR_NUM); // MAJOR_NUM << 20 | MINOR_NUM;

	ret = cdev_add(&dev, dev_num, 1);
	if(ret < 0)
		goto err_add_failed;

	cdev_init(&dev, &fops);

	ret = register_chrdev_region(dev_num, 1, DEV_NAME);
	if(ret < 0)
		goto err2_register_failed;

	pcls = class_create(THIS_MODULE, "class_adc");
	if(NULL == pcls)
		goto err_class_create_failed;

	pdev = device_create(pcls, NULL, dev_num, NULL, DEV_NAME);
	if(NULL == pdev)
		goto err_device_create_failed;

	ret = request_irq(IRQ_ADC, adc_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "adc_irq", NULL);
	if(ret < 0)
		goto err_request_irq_failed;

	init_waitqueue_head(&wq);

	adccon = ioremap(ADCCON, sizeof(adccon));
	adcdat0 = ioremap(ADCDAT0, sizeof(adcdat0));
	clkcon = ioremap(CLKCON, sizeof(clkcon));
	*clkcon |= (1 << 15);

	printk("clkcon = %lx\n", *clkcon);

	printk("adc_init  ############################\n");
	return 0;

err_add_failed:
	printk("cdev_add failed\n");
	cdev_del(&dev);
	return ret;

err2_register_failed:
	printk("register_chrdev_region failed\n");
	unregister_chrdev_region(dev_num, 1);
	cdev_del(&dev);
	return ret;

err_class_create_failed:
	printk("class_create failed\n");
	class_destroy(pcls);
	unregister_chrdev_region(dev_num, 1);
	cdev_del(&dev);
	return ret;

err_device_create_failed:
	printk("device_create failed\n");
	device_destroy(pcls, dev_num);
	class_destroy(pcls);
	unregister_chrdev_region(dev_num, 1);
	cdev_del(&dev);
	return ret;

err_request_irq_failed:
	printk("request_irq failed\n");
	disable_irq(IRQ_ADC);
	device_destroy(pcls, dev_num);
	class_destroy(pcls);
	free_irq(IRQ_ADC, NULL);
	unregister_chrdev_region(dev_num, 1);
	cdev_del(&dev);
	return ret;
}

static void __exit adc_exit(void)
{
	iounmap(clkcon);
	iounmap(adcdat0);
	iounmap(adccon);
	device_destroy(pcls, dev_num);
	class_destroy(pcls);
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, NULL);
	unregister_chrdev_region(dev_num, 1);
	cdev_del(&dev);
	printk("adc_exit ...\n");
}

module_init(adc2_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

adc_misc.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <mach/irqs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>

#define DEV_NAME "adc2"
static wait_queue_head_t wq;
static int condition = 0;
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;

static void adc_init(void)
{
	*adccon = (1 << 14) | (49 << 6);
}

static void adc_start(void)
{
	*adccon |= (1 << 0);
}

static unsigned short adc_read(void)
{
	unsigned short adc_value = *adcdat0 & 0x3ff;
	return adc_value;
}

static irqreturn_t adc_handler(int irq, void * arg)
{
	condition = 1;
	wake_up_interruptible(&wq);	

	printk("irq = %d\n", irq);
	return IRQ_HANDLED;
}

static int open(struct inode * node, struct file * file)
{
	adc_init();
	printk("kernel open \n");
	return 0;
}

static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * loff)
{
	unsigned short data = 0;
	adc_start();
	condition = 0;
	wait_event_interruptible(wq, condition);
	
	data = adc_read();
	copy_to_user(buf, &data, sizeof(data));	

	printk("kernel read\n");
	return sizeof(data);
}

static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * loff)
{
	printk("kernel write \n");
	return 0;
}

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

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.release = close
};

static struct miscdevice misc_d = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEV_NAME,
	.fops = &fops
};

static int __init adc2_init(void)
{
	int ret = misc_register(&misc_d);
	if(ret < 0)
		goto err_misc_register_failed;

	ret = request_irq(IRQ_ADC, adc_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "adc_irq", NULL);
	if(ret < 0)
		goto err_request_irq_failed;

	init_waitqueue_head(&wq);

	adccon = ioremap(ADCCON, sizeof(adccon));
	adcdat0 = ioremap(ADCDAT0, sizeof(adcdat0));
	clkcon = ioremap(CLKCON, sizeof(clkcon));
	*clkcon |= (1 << 15);

	printk("clkcon = %lx\n", *clkcon);

	printk("adc_init  ############################\n");
	return 0;

err_misc_register_failed:
	printk("misc_register failed\n");
	misc_deregister(&misc_d);
	return ret;

err_request_irq_failed:
	printk("request_irq failed\n");
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, NULL);
	misc_deregister(&misc_d);
	return ret;
}

static void __exit adc_exit(void)
{
	iounmap(clkcon);
	iounmap(adcdat0);
	iounmap(adccon);
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, NULL);
	misc_deregister(&misc_d);
	printk("adc_exit ...\n");
}

module_init(adc2_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值