基于 2.6 内核的 pwm 蜂鸣器驱动设计(5)
- UID
- 864567
|
基于 2.6 内核的 pwm 蜂鸣器驱动设计(5)
static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ if(!down_trylock(&ioctl_lock)){ switch (cmd) { case PWM_IOCTL_SET_FREQ: /*if cmd=1 即 进入 case PWM_IOCTL_SET_FREQ*/ if (arg == 0) /*如果设置的频率参数是 0*/ return -EINVAL; /*返回错误信息,表示向参数传递了无效 的参数*/ PWM_Set_Freq(arg); /*否 则设置频率*/ break; case PWM_IOCTL_STOP: /* if cmd=2 即进入 case PWM_IOCTL_STOP*/ PWM_Stop(); /*停止蜂鸣器*/ break; case SET_RIGHT_ACTION_BEEP: case SET_ERROR_ACTION_BEEP: case SET_KEY_PRESS_BEEP: set_beep_type(cmd); break; default: break; } up(&ioctl_lock); return 0; /* 成功返回*/ }else return -EBUSY; } /*初始化设备的文件操作的结构体*/ static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c24xx_pwm_open, .release = s3c24xx_pwm_close, .ioctl = s3c24xx_pwm_ioctl, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = BEEPDEV_NAME, .fops = &dev_fops, .devfs_name[0] = '\0', };
static int __init dev_init(void){ int ret; init_MUTEX(&lock); /*初始化一个互斥锁*/ init_MUTEX(&ioctl_lock); misc.devfs_name[0]='\0'; // 这句使/dev/misc/下产生 beep 设备文件 ret = misc_register(&misc); /*注册一个 misc 设备*/ if(ret){ printk (BEEPDEV_NAME "\tinit error!!\n"); } else printk (BEEPDEV_NAME "\tinitialized by newkoom.com\n"); return ret; } static void __exit dev_exit(void){ del_timer(&beep_timer); misc_deregister(&misc); /*注销设备*/ } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("newkoom"); MODULE_DESCRIPTION("S3C2410 RPM or yls3c2410 devlp board beep driver"); /* 1 计数器控制寄存器 1)配置定时器输入时钟 TCFG0-时钟配置寄存器 0,用于获得预分频值(1~255) TCFG1-时钟配置寄存器 1,用于获得分割值(2,4,8,16,32) 定时器输入时钟频率=PLCK/{预分频+1}/{分割值} 2)配置 PWM 的占空比 TCNTB0-定时器 0 计数缓存寄存器 ,是由定时器的输入时钟分频得到, 是脉宽调制的频率 TCMTB0-定时器 0 比较缓存寄存器 ,用于设定 PWM 的占空比 ,寄存器值为高定平的 假设 TCNTB0 的频率是 160,如果 TCMTB0 是 110,则 PWM 在 110 个周期是高定平, 50 周期是低电平,从而占空比为 11:5 3)定时器控制寄存器 TCON TCON[0~4]用于控制定时器 0 2.__raw_readl 和__raw_writel 读端口寄存器用__raw_readl(a ),该函数从端口 a 返回一个 32 位的值。
相关的定义在 include/asm-arm/io.h 中。#define __raw_readl(a) (*(volatile unsigned int*)(a)), 写端口寄存器用__raw_writel(v,a),该函数将一个 32 位的值写入端口 a 中。 相关的定义在 include/asm-arm/io.h 中。 #define __raw_writel(v,a) (*(volatile unsigned int*)(a) = (v))。 此处设置功能控制寄存器,将相应的引脚设为输出状态。 3 .gpio 操作 gpio_cfgpin 配置相应 GPIO 口的功能 gpio_setpin IO 口为输出功能时,写引脚 4 基于信号量的 Llinux 的并发控制 在驱动程序中,当多个线程同时访问相同的资源时,可能会引发“竞态” , 因此必须对共享资源进行并发控制。信号量(绝大多数作为互斥锁使用) 是一种进行并发控制的手段(还有自旋锁,它适合于保持时间非常短的时间) 。 信号量只能在进程的上下文中使用。 void init_MUTEX(&lock)初始化一个互斥锁,即他把信号量 lock 设置为 1 void up (&lock) 释放信号量,唤醒等待者 int down_trylock(&lock) 尝试获得信号量 lock ,如果能够立刻获得,就获得信号量, 并返回为 0.否则返回非 0.并且它不会导致休眠,可以在中断上下文中使用。 在 PWM 中,当计数值溢出时,就会引发计数中断。所以在这里用这个函数来 获得信号。 */ /**************************************************************** Copyright(c) 2009-2010,Newkoom Net Tech.Co,.Ltd 模块名称(Filename): beep.cpp 项目名称(Projectname): RPM(Remote Power Manager System) 版本号(Version): 1.0.0 创建日期(Date): 2009-11-22 作者(Author): ZMF(Zheng meifu) 功能描述(Description): beep class define 其他说明(Others): 修改记录(History): 调试成功: ****************************************************************/ class Cbeep{ protected: int beep_fd; int freq; int cmd; public: Cbeep(); ~Cbeep(); int close_buzzer(void); int open_buzzer(void); //打开蜂鸣器
int stop_buzzer(void); int set_buzzer(int freq, int cmd); }; #include #include #include #include #include #include #include #include #include "beep.h" /*标准输入输出定义*/ /*POSIX 终端控制定义*/ /*Unix 标准函数定义*/ /*标准函数库定义*/
Cbeep::Cbeep(){ beep_fd=-1; freq=1000; cmd = SET_BEEP_OFF; } Cbeep::~Cbeep(){ close_buzzer(); } int Cbeep:pen_buzzer(void) { beep_fd = open(BEEP_FILE, 0); if (beep_fd < 0) { perror("open /dev/misc/beep device"); exit(1); 进程。退出参数为 1 } return beep_fd; // any function exit call will stop the buzzer // atexit(close_buzzer); } int Cbeep::close_buzzer(void){ int ret=0; if (beep_fd >= 0) { close(beep_fd); 设备驱动文件 beep_fd = -1; ret=ioctl(beep_fd, SET_BEEP_OFF); if(ret<0) perror("close_buzzer ioctl"); }
//打开蜂鸣器 //打开 pwm 设备驱动文件
//打开错误, 则终止
//退出回调 close_buzzer //关闭蜂鸣器
//关闭
//停止蜂鸣器
return ret; } int Cbeep::set_buzzer(int freqt, int cmdt){ // this IOCTL command is the key to set frequency int ret = ioctl(beep_fd, cmdt, freqt); //设置频率 if(ret < { 入的频率错误 perror("set buzzer freq & cmd"); // exit(1); 退出,返回 1 } return ret; } int Cbeep::stop_buzzer(void){ int ret = ioctl(beep_fd, SET_BEEP_OFF); //关闭蜂鸣器 if(ret < 0) { 闭蜂鸣器 perror("stop the buzzer"); exit(1); 回1 } return ret; } |
|
|
|
|
|