《OK6410-蜂鸣器驱动程序设计》之阻塞型字符设备

来源:互联网 发布:网络配线架 编辑:程序博客网 时间:2024/05/31 20:51

        蜂鸣器是通过I/O 口GPF15来间接控制的,为了增加驱动能力,增加了三级管驱动电路。当三极管的基极(B)为高电平即GPF15 为高电平时,蜂鸣器会鸣叫,反之则不响。通过设置两者之间的时间(即改变频率)可以使蜂鸣器发出不同的声音,甚至播放乐曲。

OK6410蜂鸣器原理图:


通过I/O 口GPF15来控制:


查看s3c6410芯片手册,端口M对应的三个寄存器地址:

实验相应寄存器


端口配置寄存器


端口数据寄存器


代码:

been_wait.c

#include <linux/module.h>//内核模块相关宏定义,必须有#include <linux/init.h>//__init 和 __exit宏定义所在头文件#include <linux/miscdevice.h>// 混杂设备所需的头文件#include <linux/fs.h>// file_operations结构的定义所在的头文件#include <linux/ioport.h>// ioremap映射所需的头文件#include <asm/io.h>//io内存所需的头文件#include <linux/wait.h>//阻塞型IO所需的头文件#include <linux/sched.h>//进程调度所需的头文件#define GPFCON 0x7F0080A0 //蜂鸣器的控制端口的物理地址#define GPFDAT 0x7F0080A4 //蜂鸣器的数据端口的物理地址static volatile unsigned long* gpfcon_addr;//经过ioremap映射后的虚拟地址static volatile unsigned long* gpfdat_addr;void been_port_init(void){//设置GPF15寄存器为输出模式*gpfcon_addr &= (~(0x1<<(31)));*gpfcon_addr |= (0x1<<(2*15));//设置GPF[15]为低电平,不响*gpfdat_addr &= 0x7fff;}//开启蜂鸣器void been_start(void){*gpfdat_addr |= 0x8000;}//关闭蜂鸣器void been_stop(void){*gpfdat_addr &= 0x7fff;}DECLARE_WAIT_QUEUE_HEAD(wq);//初始化等待队列头static volatile int flag=0; //设置条件标志ssize_t my_read(struct file* filp,char __user* buf, size_t size,loff_t* ppos){if(filp->f_flags & O_NONBLOCK)//非阻塞的读取{if(flag !=0)been_stop();return -EAGAIN;}else{been_start();wait_event_interruptible(wq,flag!=0);flag=0;been_stop();}return 0;}ssize_t my_write(struct file* filp,const char __user* buf,size_t size,loff_t* ppos){flag=1;wake_up_interruptible(&wq); return 0;}struct file_operations my_fops={.owner = THIS_MODULE,.read = my_read,.write = my_write,};struct miscdevice mymisc={.minor = MISC_DYNAMIC_MINOR,//MISC_DYNAMIC_MINOR=10,动态的获得次设备号.name = "my_been",.fops = &my_fops,};static int __init been_wait_init(void){int ret;//申请IO内存,不是必须的。if(!request_mem_region(GPFCON,1,"been")){ret = -EBUSY;goto request_mem_failed;}gpfcon_addr = ioremap(GPFCON,1);//将物理地址映射为虚拟地址if(NULL==gpfcon_addr){ret = -EIO;printk("gpfcon remap failed\n");goto con_map_failed;}gpfdat_addr = ioremap(GPFDAT,1);if(NULL==gpfdat_addr){ret = -EIO;printk("gpfdat remap failed\n");goto dat_map_failed;}printk("gpfcon_addr remap on %p\n",gpfcon_addr);printk("gpfdat_addr remap on %p\n",gpfdat_addr);been_port_init();//初始化beenret=misc_register(&mymisc);//注册一个混杂设备驱动,主设备号为10if(ret){printk("misc_register failed\n");goto failed;}printk("been init\n");return 0;failed:iounmap(gpfdat_addr);dat_map_failed:iounmap(gpfcon_addr);con_map_failed:release_mem_region(GPFCON,1);request_mem_failed:return ret;}static void __exit been_wait_exit(void){iounmap(gpfdat_addr); //取消映射iounmap(gpfcon_addr);release_mem_region(GPFCON, 1); //释放I/O内存misc_deregister(&mymisc); printk("been exit\n");}module_init(been_wait_init);module_exit(been_wait_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("liye");
方案2:

#include <linux/module.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/gpio.h>#include <linux/io.h>#include <plat/gpio-core.h>#include <plat/gpio-cfg.h>#include <plat/gpio-cfg-helpers.h>void been_port_init(void){s3c_gpio_cfgpin(S3C64XX_GPF(15),S3C_GPIO_OUTPUT);    //设置端口为输出gpio_set_value(S3C64XX_GPF(15),0); //设置端口值为低电平}void been_start(void){gpio_set_value(S3C64XX_GPF(15),1);}void been_stop(void){gpio_set_value(S3C64XX_GPF(15),0);}DECLARE_WAIT_QUEUE_HEAD(wq);static volatile int flag=0;ssize_t my_read(struct file* filp,char __user* buf, size_t size,loff_t* ppos){if(filp->f_flags & O_NONBLOCK){if(flag !=0)been_stop();return -EAGAIN;}else{been_start();wait_event_interruptible(wq,flag!=0);flag=0;been_stop();}return 0;}ssize_t my_write(struct file* filp,const char __user* buf,size_t size,loff_t* ppos){flag=1;wake_up_interruptible(&wq);return 0;}struct file_operations my_fops={.owner = THIS_MODULE,.read = my_read,.write = my_write,};struct miscdevice mymisc={.minor = MISC_DYNAMIC_MINOR,//MISC_DYNAMIC_MINOR=10.name = "my_been",.fops = &my_fops,};static int __init been_wait_init(void){int ret;been_port_init();ret=misc_register(&mymisc);if(ret){printk("misc_register failed\n");return -1;}printk("been init\n");return 0;}static void __exit been_wait_exit(void){misc_deregister(&mymisc);}module_init(been_wait_init);module_exit(been_wait_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("liye");


测试代码:

read.c

#include <stdio.h>#include <fcntl.h>int main(){int fd;char buf;fd=open("/dev/my_been",O_RDWR);read(fd,buf,1);return 0;}

write.c

#include <stdio.h>#include <fcntl.h>int main(){int fd;char buf='a';fd=open("/dev/my_been",O_RDWR);write(fd,buf,1);return 0;}

Makefile

ifneq ($(KERNELRELEASE),)obj-m := been_wait.oelse KDIR := /home/liye/forlinux/linux-2.6.36all:make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-install:cp been_wait.ko write read /home/liye/forlinux/rootfs/courseclean:rm -f *.o *.ko *.mod.c *.mod.o *.order *.symversendif