linux2.6.14.1下蜂鸣器驱动程序

/*http://blog.csdn.net/zhengmeifu/archive/2009/12/15/5002900.aspx*/

本驱动程序经过测试,证明运行良好,下面附有驱动原码和测试程序,若有哪位引用了我的驱动,请注明出处。谢谢!

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
/**************************************************************** 
    Copyright(c) 2009-2010,Newkoom Net Tech.Co,.Ltd 
     
    模块名称(Filename):         beep_s3c2410.c   
    项目名称(Projectname):          RPM(Remote Power Manager System) 
    版本号(Version):               1.0.0 
    创建日期(Date):                 2009-11-22         
    作者(Author):                         ZMF(Zheng meifu) 
    功能描述(Description):      buzzer(beep) driver for linux2.6.14.1 
    其他说明(Others):                
    修改记录(History):      调试成功:2009-11-23  
    2009-12-1:之前只能在定时任务结束后才释放锁,今天改为 
    设置完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 <asm/arch/regs-gpio.h>   
#include <asm/arch/hardware.h>   
#include <asm/arch/regs-timer.h>   
#include <asm/arch/regs-irq.h>   
#include <asm/mach/time.h>  
#include <asm/hardware/clock.h>   
#include <linux/cdev.h>  
#include <linux/device.h>  
#include <linux/miscdevice.h>  
 
#define BEEPDEV_NAME     "beep"                        /*设备名 beep*/  
#define PWM_IOCTL_SET_FREQ   1                 /*定义宏常量,用于后面的ioctl中的switch case*/  
#define PWM_IOCTL_STOP    2  
#define SET_RIGHT_ACTION_BEEP   3   // 此处宏数字不能改,和以下beep_const序号相关  
#define SET_ERROR_ACTION_BEEP   4   // 同上  
#define SET_KEY_PRESS_BEEP      5   // 同上  
#define BEON    (1<<(sizeof(int)*8-1))  
#define BEOF    0  
#define PRESET_FREQ 1000  
#define KEY_DELAYMS(X)  (HZ/(1000/(X)))  
 
static struct semaphore lock;                            /*定义信号量 lock*/ 
static struct semaphore ioctl_lock;  
/* freq: pclk/50/16/65536 ~ pclk/50/16                        
* if pclk = 50MHz, freq is 1Hz to 62500Hz 
* human ear : 20Hz~ 20000Hz 
*/ 
const int beep_const[3][8]={  
    {500|BEON,100|BEOF,0,0,0,0,0,0},        // right  
    {100|BEON,50|BEOF,100|BEON,50|BEOF,100|BEON,50|BEOF,0,0},       // error  
    {100|BEON,50|BEOF,0,0,0,0,0,0},     // key  
};  
struct timer_list beep_timer;  
static int beep_step;  
 
static void PWM_Set_Freq(unsigned long freq);  
static void PWM_Stop(void);  
static void beep_timer_handler(unsigned long data){  
    int onofftime=beep_const[data][beep_step++];  
    if(onofftime !=0){  
        beep_timer.data = data;  
        mod_timer(&beep_timer, jiffies+ KEY_DELAYMS(onofftime&(~BEON)));  
        if(onofftime&BEON)  
            PWM_Set_Freq(PRESET_FREQ);  
        else        PWM_Stop();  
    }else{  
        PWM_Stop();  
        del_timer(&beep_timer);  
//up(&ioctl_lock);  
    }  
}  
static void set_beep_type(int type){  
    int tmp_time= beep_const[type-3][0]&(~BEON);  
    del_timer(&beep_timer);  
    init_timer(&beep_timer);  
    beep_timer.expires = jiffies + KEY_DELAYMS(tmp_time);  
    beep_timer.function = beep_timer_handler;  
       beep_timer.data = type-3;  
    beep_step=1;  
    add_timer(&beep_timer);  
    PWM_Set_Freq(PRESET_FREQ);  
}  
static void PWM_Set_Freq( unsigned long freq )            /*设置pwm的频率,配置各个寄存器*/ 
{  
    unsigned long tcon, tcnt, tcfg1, tcfg0,pclk;  
    struct clk *clk_p;  
    /*set GPB0 as tout0, pwm output              设置GPB0为tout0,pwm输出*/ 
    s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0);  
    tcon = __raw_readl(S3C2410_TCON);           /*读取寄存器TCON到tcon*/ 
    tcfg1 = __raw_readl(S3C2410_TCFG1);        /*读取寄存器TCFG1到tcfg1*/ 
    tcfg0 = __raw_readl(S3C2410_TCFG0);        /*读取寄存器TCFG0到tcfg0*/ 
    //prescaler = 50  
    tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;  /* S3C2410_TCFG_PRESCALER0_MASK定时器0和*/ 
                                                                                     /*   1的预分频值的掩码,TCFG[0~8]*/ 
    tcfg0 |= (50 - 1);   /* 预分频为50 */ 
    //mux = 1/16  
    tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;     /*S3C2410_TCFG1_MUX0_MASK定时器0分割值的掩*/ 
                                                                             /*码:TCFG1[0~3]*/ 
    tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;         /*定时器0进行16分割*/ 
    __raw_writel(tcfg1, S3C2410_TCFG1);          /*把tcfg1的值写到分割寄存器S3C2410_TCFG1中*/ 
    __raw_writel(tcfg0, S3C2410_TCFG0);          /*把tcfg0的值写到预分频寄存器S3C2410_TCFG0中*/ 
    clk_p = clk_get(NULL, "pclk");                                    /*得到pclk*/ 
    pclk = clk_get_rate(clk_p);  
    tcnt = (pclk/50/16)/freq;         /*得到定时器的输入时钟,进而设置PWM的调制频率*/ 
    __raw_writel(tcnt, S3C2410_TCNTB(0));        /*PWM脉宽调制的频率等于定时器的输入时钟   */ 
    __raw_writel(tcnt/2, S3C2410_TCMPB(0));    /*占空比是50%*/ 
    tcon &= ~0x1f;  
    tcon |= 0xb;   /*disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0*/ 
    __raw_writel(tcon, S3C2410_TCON);  
    tcon &= ~2;    /*clear manual update bit*/ 
    __raw_writel(tcon, S3C2410_TCON);               /*把tcon写到计数器控制寄存器S3C2410_TCON中*/ 
}  
static void PWM_Stop( void ){  
    s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);   /*设置GPB0为输出*/ 
    s3c2410_gpio_setpin(S3C2410_GPB0, 0);               /*设置GPB0为低电平,使蜂鸣器停止*/ 
}  
static int s3c24xx_pwm_open(struct inode *inode, struct file *file){  
    if (!down_trylock(&lock))          /*是否获得信号量,是down_trylock(&lock)=0,否则非0*/ 
       return 0;  
    else 
       return -EBUSY;                                                      /*返回错误信息:请求的资源不可用*/ 
}  
static int s3c24xx_pwm_close(struct inode *inode, struct file *file){  
    up(&lock);                                                         /*释放信号量lock*/ 
    return 0;  
}  
/*cmd 是1,表示设置频率;cmd 是2 ,表示停止pwm*/ 
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<zhengmeifu@sina.com>");  
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 <stdio.h>                     /*标准输入输出定义*/  
#include <termios.h>                  /*POSIX终端控制定义*/  
#include <unistd.h>                     /*Unix 标准函数定义*/  
#include <stdlib.h>                      /*标准函数库定义*/  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include "beep.h"  
 
Cbeep::Cbeep(){  
    beep_fd=-1;  
    freq=1000;  
    cmd = SET_BEEP_OFF;  
}  
Cbeep::~Cbeep(){  
    close_buzzer();  
}  
int Cbeep::open_buzzer(void)                   //打开蜂鸣器  
{  
    beep_fd = open(BEEP_FILE, 0);                       //打开pwm设备驱动文件  
    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);                             //退出回调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");  
    }  
    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 < 0) {                                                                       //如果输入的频率错误  
       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;  

/****************************************************************
    Copyright(c) 2009-2010,Newkoom Net Tech.Co,.Ltd
   
    模块名称(Filename):        beep_s3c2410.c 
    项目名称(Projectname):        RPM(Remote Power Manager System)
    版本号(Version):         1.0.0
    创建日期(Date):             2009-11-22       
    作者(Author):                ZMF(Zheng meifu)
    功能描述(Description):     buzzer(beep) driver for linux2.6.14.1
    其他说明(Others):           
    修改记录(History):  调试成功:2009-11-23 
    2009-12-1:之前只能在定时任务结束后才释放锁,今天改为
    设置完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 <asm/arch/regs-gpio.h>
#include <asm/arch/hardware.h>
#include <asm/arch/regs-timer.h>
#include <asm/arch/regs-irq.h>
#include <asm/mach/time.h>
#include <asm/hardware/clock.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>

#define BEEPDEV_NAME     "beep"                        /*设备名 beep*/
#define PWM_IOCTL_SET_FREQ   1                 /*定义宏常量,用于后面的ioctl中的switch case*/
#define PWM_IOCTL_STOP    2
#define SET_RIGHT_ACTION_BEEP 3 // 此处宏数字不能改,和以下beep_const序号相关
#define SET_ERROR_ACTION_BEEP 4 // 同上
#define SET_KEY_PRESS_BEEP  5 // 同上
#define BEON (1<<(sizeof(int)*8-1))
#define BEOF 0
#define PRESET_FREQ 1000
#define KEY_DELAYMS(X)  (HZ/(1000/(X)))

static struct semaphore lock;                            /*定义信号量 lock*/
static struct semaphore ioctl_lock;
/* freq: pclk/50/16/65536 ~ pclk/50/16                      
* if pclk = 50MHz, freq is 1Hz to 62500Hz
* human ear : 20Hz~ 20000Hz
*/
const int beep_const[3][8]={
 {500|BEON,100|BEOF,0,0,0,0,0,0},  // right
 {100|BEON,50|BEOF,100|BEON,50|BEOF,100|BEON,50|BEOF,0,0},  // error
 {100|BEON,50|BEOF,0,0,0,0,0,0},  // key
};
struct timer_list beep_timer;
static int beep_step;

static void PWM_Set_Freq(unsigned long freq);
static void PWM_Stop(void);
static void beep_timer_handler(unsigned long data){
 int onofftime=beep_const[data][beep_step++];
 if(onofftime !=0){
  beep_timer.data = data;
  mod_timer(&beep_timer, jiffies+ KEY_DELAYMS(onofftime&(~BEON)));
  if(onofftime&BEON)
   PWM_Set_Freq(PRESET_FREQ);
  else  PWM_Stop();
 }else{
  PWM_Stop();
  del_timer(&beep_timer);
//up(&ioctl_lock);
 }
}
static void set_beep_type(int type){
 int tmp_time= beep_const[type-3][0]&(~BEON);
 del_timer(&beep_timer);
 init_timer(&beep_timer);
 beep_timer.expires = jiffies + KEY_DELAYMS(tmp_time);
 beep_timer.function = beep_timer_handler;
       beep_timer.data = type-3;
 beep_step=1;
 add_timer(&beep_timer);
 PWM_Set_Freq(PRESET_FREQ);
}
static void PWM_Set_Freq( unsigned long freq )            /*设置pwm的频率,配置各个寄存器*/
{
 unsigned long tcon, tcnt, tcfg1, tcfg0,pclk;
 struct clk *clk_p;
 /*set GPB0 as tout0, pwm output              设置GPB0为tout0,pwm输出*/
 s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0);
 tcon = __raw_readl(S3C2410_TCON);           /*读取寄存器TCON到tcon*/
 tcfg1 = __raw_readl(S3C2410_TCFG1);        /*读取寄存器TCFG1到tcfg1*/
 tcfg0 = __raw_readl(S3C2410_TCFG0);        /*读取寄存器TCFG0到tcfg0*/
 //prescaler = 50
 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;  /* S3C2410_TCFG_PRESCALER0_MASK定时器0和*/
                                                                                  /*   1的预分频值的掩码,TCFG[0~8]*/
 tcfg0 |= (50 - 1);   /* 预分频为50 */
 //mux = 1/16
 tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;     /*S3C2410_TCFG1_MUX0_MASK定时器0分割值的掩*/
                                                                          /*码:TCFG1[0~3]*/
 tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;         /*定时器0进行16分割*/
 __raw_writel(tcfg1, S3C2410_TCFG1);          /*把tcfg1的值写到分割寄存器S3C2410_TCFG1中*/
 __raw_writel(tcfg0, S3C2410_TCFG0);          /*把tcfg0的值写到预分频寄存器S3C2410_TCFG0中*/
 clk_p = clk_get(NULL, "pclk");                                    /*得到pclk*/
 pclk = clk_get_rate(clk_p);
 tcnt = (pclk/50/16)/freq;         /*得到定时器的输入时钟,进而设置PWM的调制频率*/
 __raw_writel(tcnt, S3C2410_TCNTB(0));        /*PWM脉宽调制的频率等于定时器的输入时钟   */
 __raw_writel(tcnt/2, S3C2410_TCMPB(0));    /*占空比是50%*/
 tcon &= ~0x1f;
 tcon |= 0xb;   /*disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0*/
 __raw_writel(tcon, S3C2410_TCON);
 tcon &= ~2;    /*clear manual update bit*/
 __raw_writel(tcon, S3C2410_TCON);               /*把tcon写到计数器控制寄存器S3C2410_TCON中*/
}
static void PWM_Stop( void ){
 s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);   /*设置GPB0为输出*/
 s3c2410_gpio_setpin(S3C2410_GPB0, 0);               /*设置GPB0为低电平,使蜂鸣器停止*/
}
static int s3c24xx_pwm_open(struct inode *inode, struct file *file){
 if (!down_trylock(&lock))          /*是否获得信号量,是down_trylock(&lock)=0,否则非0*/
    return 0;
 else
    return -EBUSY;                                                      /*返回错误信息:请求的资源不可用*/
}
static int s3c24xx_pwm_close(struct inode *inode, struct file *file){
 up(&lock);                                                         /*释放信号量lock*/
 return 0;
}
/*cmd 是1,表示设置频率;cmd 是2 ,表示停止pwm*/
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<zhengmeifu@sina.com>");
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 <stdio.h>                     /*标准输入输出定义*/
#include <termios.h>                  /*POSIX终端控制定义*/
#include <unistd.h>                     /*Unix 标准函数定义*/
#include <stdlib.h>                      /*标准函数库定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "beep.h"

Cbeep::Cbeep(){
 beep_fd=-1;
 freq=1000;
 cmd = SET_BEEP_OFF;
}
Cbeep::~Cbeep(){
 close_buzzer();
}
int Cbeep::open_buzzer(void)                   //打开蜂鸣器
{
 beep_fd = open(BEEP_FILE, 0);                       //打开pwm设备驱动文件
 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);                             //退出回调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");
 }
 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 < 0) {                                                                       //如果输入的频率错误
    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;
}

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhengmeifu/archive/2009/12/15/5002900.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值