手把手教你从零实现Linux misc设备驱动二(基于友善之臂4412开发板)

上一节,我教大家实现了一个最简单的MISC设备驱动,那么这节,我们将用一个实例来驱动蜂鸣器,这里为了方便,我就不再写应用程序进行测试,直接在驱动里调用open函数,这个程序是在Android系统里跑起来,后面我会教大家如何在Android下写应用测试程序。

我们参考以前写的蜂鸣器驱动程序,将它移植到我们这个程序里,让它成为一个MISC设备。

参考以前写的文章:

http://blog.csdn.net/morixinguan/article/details/50628588

接下来,看看代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <asm/uaccess.h>  
#include <asm/irq.h>  
#include <asm/io.h>   
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
//定义配置蜂鸣器的IO地址
#define GPD0CON  0x114000A0
volatile unsigned long *bell_config = NULL ;   
volatile unsigned long *bell_dat = NULL ;   

//misc设备名称--->就是字符设备
#define DEVICE_NAME "misc_dev"
//实现open函数
int tiny4412_misc_dev_open(struct inode *inode , struct file *filp)
{
	printk("tiny4412 bell dev open!\n");
	//配置引脚为输出状态
	*bell_config &= ~(0xf);
	*bell_config |= (0x1);
	//开启蜂鸣器
	*bell_dat |= 0x1 ;
	return 0 ;
}
//实现close函数
int tiny4412_misc_dev_close(struct inode *inode, struct file *filp)
{
	printk("tiny4412 bell dev close!\n");
	//关闭蜂鸣器
	*bell_dat &= ~0x1 ;
	return 0 ;
}
//初始化文件操作结构体
struct file_operations tiny4412_file_ops = {
	.owner = THIS_MODULE ,
	.open = tiny4412_misc_dev_open,
	.release = tiny4412_misc_dev_close,
};
//初始化misc设备结构体
struct miscdevice tiny4412_misc_dev = {
	//由内核自动分配次设备号
	.minor = MISC_DYNAMIC_MINOR ,
	//初始化设备名称
	.name = DEVICE_NAME ,
	//初始化文件操作结构体
	.fops = &tiny4412_file_ops,	
};


static int __init tiny4412_misc_dev_init(void) 
{
	int ret_error ;
	//1、映射IO
	//映射控制配置引脚IO
	bell_config = (volatile unsigned long *)ioremap(GPD0CON , 16);  
    //加4个字节偏移到GP0DAT顺便映射该物理地址---引脚状态控制IO
    bell_dat = bell_config + 1 ;
	
	
	//2、注册misc设备
	int ret = misc_register(&tiny4412_misc_dev);
	if(ret != 0){
	   ret_error = ret ;
	   printk("misc register fair!\n");
	   goto fair ;
	}
	printk("misc init success!\n");	
	//在这里直接调用open函数,就方便,不用直接写应用程序打开设备访问
	tiny4412_misc_dev_open(NULL,NULL);
	return ret ;
	fair:
	return ret_error ;
}

static void __exit tiny4412_misc_dev_exit(void) 
{
	//注销misc设备
	misc_deregister(&tiny4412_misc_dev);
	//取消映射   
    iounmap(bell_config);  
}

module_init(tiny4412_misc_dev_init);
module_exit(tiny4412_misc_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("YYX add misc driver");
运行结果:

在开机log中,我们看到open函数被正确调用,蜂鸣器发出了清脆的响声。

至此,我们完成了这个简单的基于蜂鸣器的misc设备驱动,当然,如果有兴趣,我们可以在Android上写一个C的应用程序,在开机的时候以服务的形式加载,一旦加载上,再在里面写一个按键输入的程序,当按下某个按键就调用bell open函数,当释放按键,就调用bell close函数。

以上的程序还可以进一步优化,做得更好。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一些创建Linux字符设备驱动的指导。在这个过程中,我将涉及一些基本的Linux内核编程知识。 首先,您需要了解什么是Linux字符设备和watchdog。Linux字符设备是一种与字符流进行交互的设备,例如终端、串口、打印机等。watchdog是一种硬件计时器,可以在系统出现问题时触发复位操作。 以下是创建Linux字符设备驱动的基本步骤: 1. 创建字符设备驱动的源文件。在这个文件中,你需要定义一些函数,如 file_operations 结构体中的 read 和 write 函数,以及初始化和清理函数。你需要使用字符设备驱动框架中的 API 函数来注册字符设备,分配和释放设备号等。 2. 实现字符设备的 read 和 write 函数。在这些函数中,你需要实现读写设备的逻辑。在这个特定的案例中,你需要在 write 函数中设置 watchdog 定时器的时间,以及在 read 函数中触发复位操作。 3. 在初始化函数中初始化 watchdog 定时器,并启动它。 4. 在清理函数中清理 watchdog 定时器,并停止它。 这是一个基本的框架,你需要根据你的需求来调整它。 接下来是一些参考代码,可以帮助你开始编写代码: ```c #include <linux/module.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #define DEVICE_NAME "watchdog" #define MAX_TIMEOUT 3600 static struct miscdevice watchdog_miscdev; static struct timer_list watchdog_timer; static int watchdog_timeout = MAX_TIMEOUT; static int watchdog_enabled = 0; static void watchdog_timeout_handler(unsigned long data) { printk(KERN_INFO "Watchdog: Timer expired, triggering reset\n"); watchdog_enabled = 0; watchdog_miscdev.minor = 0; misc_deregister(&watchdog_miscdev); watchdog_miscdev.minor = MISC_DYNAMIC_MINOR; misc_register(&watchdog_miscdev); watchdog_enabled = 1; watchdog_timer.expires = jiffies + watchdog_timeout * HZ; add_timer(&watchdog_timer); machine_restart(NULL); } static ssize_t watchdog_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { if (!watchdog_enabled) { printk(KERN_INFO "Watchdog: Device not enabled\n"); return -EIO; } printk(KERN_INFO "Watchdog: Triggering reset\n"); machine_restart(NULL); return 0; } static ssize_t watchdog_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long timeout; if (count != sizeof(timeout)) { printk(KERN_INFO "Watchdog: Invalid write size\n"); return -EINVAL; } if (!watchdog_enabled) { printk(KERN_INFO "Watchdog: Device not enabled\n"); return -EIO; } if (copy_from_user(&timeout, buf, sizeof(timeout))) { printk(KERN_INFO "Watchdog: Failed to copy timeout value from user\n"); return -EFAULT; } if (timeout < 1 || timeout > MAX_TIMEOUT) { printk(KERN_INFO "Watchdog: Timeout value out of range\n"); return -EINVAL; } watchdog_timeout = timeout; mod_timer(&watchdog_timer, jiffies + watchdog_timeout * HZ); printk(KERN_INFO "Watchdog: Timeout set to %lu seconds\n", timeout); return count; } static int watchdog_open(struct inode *inode, struct file *file) { if (watchdog_enabled) { printk(KERN_INFO "Watchdog: Device already enabled\n"); return -EBUSY; } printk(KERN_INFO "Watchdog: Enabling device\n"); watchdog_timer.function = watchdog_timeout_handler; watchdog_timer.expires = jiffies + watchdog_timeout * HZ; add_timer(&watchdog_timer); watchdog_enabled = 1; return 0; } static int watchdog_release(struct inode *inode, struct file *file) { if (!watchdog_enabled) { printk(KERN_INFO "Watchdog: Device not enabled\n"); return -EIO; } printk(KERN_INFO "Watchdog: Disabling device\n"); del_timer_sync(&watchdog_timer); watchdog_enabled = 0; return 0; } static const struct file_operations watchdog_fops = { .owner = THIS_MODULE, .read = watchdog_read, .write = watchdog_write, .open = watchdog_open, .release = watchdog_release, }; static int __init watchdog_init(void) { watchdog_miscdev.minor = MISC_DYNAMIC_MINOR; watchdog_miscdev.name = DEVICE_NAME; watchdog_miscdev.fops = &watchdog_fops; misc_register(&watchdog_miscdev); printk(KERN_INFO "Watchdog: Device registered\n"); return 0; } static void __exit watchdog_exit(void) { misc_deregister(&watchdog_miscdev); printk(KERN_INFO "Watchdog: Device unregistered\n"); } module_init(watchdog_init); module_exit(watchdog_exit); MODULE_LICENSE("GPL"); ``` 这个代码实现了一个基本的 watchdog 设备驱动,它可以在 write 函数中设置定时器时间,在 read 函数中触发复位操作。当设备被打开时,定时器会被启动,在定时器时间到达时触发复位操作。当设备被关闭时,定时器会被停止。 请注意,这个代码没有经过完整的测试,您需要根据您的需求进行修改和测试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值