misc类设备与蜂鸣器驱动==Linux驱动开发6

本文详细介绍了Linux系统中如何通过Misc设备框架驱动蜂鸣器,包括打开文件、ioctl调用来设置频率和停止蜂鸣器。同时,文章探讨了Misc类设备的定义、驱动框架结构以及内核中的实现。通过对源码的分析,揭示了设备注册、文件操作函数以及ioctl函数的工作原理。此外,还展示了蜂鸣器驱动的具体实现,包括信号量、GPIO配置等关键步骤。
摘要由CSDN通过智能技术生成
一、板载蜂鸣器驱动测试
  • 应用编写:打开文件 + ioctl。
#include <stdio.h>
#include <sys/stat.h>
#incldue <fcntl.h>

#define DEVNAME "/dev/buzzer"

#define PWM_IOCTL_SET_FREQ 	1
#define PWM_IOCTL_STOP 		0

int main(void)
{
	int fd=-1;
	fd=open(DEVNAME,O_RDWR);
	if(fd<0){
		perror("open");return -1;
	}
	ioctl(fd,PWM_IOCTL_SET_FREQ,10000);
	sleep(3);
	ioctl(fd,PWM_IOCTL_STOP);
	sleep(3);
	ioctl(fd,PWM_IOCTL_SET_FREQ,3000);
	sleep(3);
	ioctl(fd,PWM_IOCTL_STOP);
	sleep(3);
	close(fd);return 0;
}
二、misc 类设备介绍

1、何为misc

  • (1)中文名:杂项设备/杂散设备。
  • (2)位于/sys/class/misc 中。
  • (3)有一套驱动框架,内核实现一部分(misc.c),驱动实现一部分(x210-buzzer.c)。
  • (4)misc 是对原始字符设备注册接口的一个类层次的封装,很多典型字符设备可以归到 misc 类,使用 misc 驱动框架来管理。

2、misc 类驱动框架架构

  • (1)内核开发者实现部分,关键点有两个:一个是类的创建,另一个是开放给驱动开发者的接口。
  • (2)设备工程师具体实现部分。
三、misc驱动框架源码分析1

1、misc 源码框架基础

  • (1)misc 源码框架本身也是一个模块,内核启动时自动加载。
  • (2)misc 源码框架的主要工作:注册 misc 类(class_create),使用老接口(register_chrdev) 注册字符设备驱动(主设备号 10),开放 misc_register 给驱动工程师。

2、misc 类设备的注册

  • (1)驱动工程师需要借助 misc 来加载自己的驱动时,只需要调用 misc_register 接口注册自 己的设备即可,其余不用管。
  • (2)misc_list 链表的作用:内核定义了一个 misc_list 链表用来记录所有内核中注册了的杂 散类设备,当我们向内核注册一个 misc 类设备时,内核就会向 misc_list 链表中 insert 一个节点。
四、misc 驱动框架源码分析 2

1、open 函数分析

  • (1)open 函数经过层层调用,最终调用来 file_operations 里面的 open 函数。

2、misc 在 proc 下的展现

  • (1)调用 proc_create。

3、内核互斥锁

  • (1)何为互斥锁:一种特殊的信号量,用来对特定的代码段实行段保护。
  • (2)定义:DEFINE_MUTEX
  • (3)上锁 mutex_lock 和解锁 mutex_unlock。
  • (4)内核防止竞争状态的手段:原子操作、自旋锁、互斥锁、信号量。
  • (5)原子访问主要用来做计数、自旋锁后面讲中断会讲、互斥锁和信号量很相似。互斥锁 出现比信号量晚,实现上比信号量优秀,尽量使用互斥锁。
五、蜂鸣器驱动源码分析 1

1、dev_init

  • (1)信号量。 (2)miscdevice。 (3)gpio_request。 (4)printk。

2、ioctl

  • (1)为什么需要 ioctl:ioctl 即可实现读,也可实现写,且除了命令外还可加参数。
  • (2)ioctl 怎么用:见驱动源码。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h> 
#include <linux/poll.h> 
#include <asm/irq.h> 
#include <asm/io.h> 
#include <linux/interrupt.h> 
#include <asm/uaccess.h> 
#include <mach/hardware.h> 
#include <plat/regs-timer.h> 
#include <mach/regs-irq.h> 
#include <asm/mach/time.h> 
#include <linux/clk.h> 
#include <linux/cdev.h> 
#include <linux/device.h> 
#include <linux/miscdevice.h> 
#include <linux/gpio.h> 
#include <plat/gpio-cfg.h>

#define DEVICE_NAME	"buzzer"

#define PWM_IOCTL_SET_FREQ	1
#define PWM_IOCTL_STOP		0

typedef unsigned long u_long;
 
static struct semaphore lock;

//被ioctl调用// TCFG0 在 Uboot 中设置,这里不再重复设置
static void PWM_Set_Freq(unsigned long freq)
{
	u_long tcon,tcnt,tcfg1,pclk;
	struct clk* clk_p;
	
	s3c_gpio_cfgpin(S5PV210_GPD0(2),S3C_GPIO_SFN(2));//设置 GPD0_2 为 PWM 输出
	tcon=__raw_readl(S3C2410_TCON);
	tcfg=__raw_readl(S3C2410_TCFG1);
	
	tcfg1&=~(0xf<<8);//mux=1/16
	tcfg1|=(0x4<<8);
	__raw_write(tcfg1,S3C2410_TCFG1);
	clk_p=clk_get(NULL,"pclk");
	pclk=clk_get_rate(clk_p);
	tcnt=(pclk/16/16)/freq;
	__raw_write(tcnt,S3C2410_TCNTB(2));
	__raw_write(tcnt/2,S3C2410_TCMPB(2));//占空比0.5

	tcon &= ~(0xf<<12);
	tcon |= (0xb<<12);
	__raw_writel(tcon, S3C2410_TCON);
	tcon &= ~(2<<12);
	__raw_writel(tcon, S3C2410_TCON); 
}
// 被ioctl调用
void PWM_Stop(void)
{
	s3c_gpio_cfgpin(S5PV210_GP0(2),S3C_GPIO_SFN(0));//将GPD0_2设置为input	
}
static int x210_pwm_open(struct inode* inode,struct file* file)
{
	if(!down_trylock(&lock))//上锁
		return 0;
	else
		return -EBUSY;	
}
static int x210_pwm_close(struct inode* inode,struct file* file,unsigned int cmd,unsigned long arg)
{
	ip(&lock);//解锁
	return 0;
}

//PWM:GPF14->PWM0
static int x210_pwm_ioctl(struct inode* inode,struct file* file,unsigned int cmd,unsigned long arg)
{
	switch(cmd)
	{
		case PWM_IOCTL_SET_FREQ:
			printk("PWM_IOCTL_SET_FREQ:\r\n");
			if (arg == 0) return -EINVAL;
			PWM_Set_Freq(arg);break;
		case PWM_IOCTL_STOP:
		default:
			printk("PWM_IOCTL_STOP:\r\n");
			PWM_Stop();	break;
	}
	return 0;
}
// 文件操作结构体
static struct file_operations dev_fops={
	.owner=THIS_MODULE,
	.open=x210_pwm_open,
	.release=x210_pwm_close,
	.ioctl=x210_pwm_ioctl,
}
//设备结构体
static int __init dev_init(void)
{
	.minor=MISC_DYNAMIC_MINOR,
	.name=DEVICE_NAME,
	.fops=&dev_fops,
}

//设备安装函数
static int __init dev_init(void)
{
	int ret=-1;
	init_MUTEX(&lock);
	ret=misc_register(&misc);//设备

	/*GPD0_2(PWMTOUT2)*/
	ret=gpio_request(S5PV210_GPD0(2),"GPD0");//申请资源
	if(ret)	printk("buzzer-x210: request gpio GPD0(2) fail");

	s3c_gpio_setpull(S5PV210_GPD0(2),S3C_GPIO_PULL_UP);//gpio初始化
	s3c_gpio_cfgpin(S5PV210_GPD0(2),S3C_GPIO_SFN(1));
	gpio_set_value(S5PV210_GPD0(2),0);
	printk ("x210 "DEVICE_NAME" initialized\n"); return ret;
}
//设备卸载函数
static void __exit dev_exit(void)
{
	misc_deregister(&misc);//注销设备
	gpio_free(S5PV210_GPD0(2));//释放资源
}

module_init(dev_init); 
module_exit(dev_exit); 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("www.9tripod.com");
MODULE_DESCRIPTION("x210 PWM Driver");
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋哥爱做饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值