//--------------------------------------------------------------------------------------------
// 作者:longtian635241([email protected])
// 论坛ID:idea6410
// 版权:idea6410
// 平台:友坚idea6410开发板
// 发布日期:2012-11-22
// 最后修改:2012-11-22
//
//----------------------------------------------------------------------------------------------
1、驱动源码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <mach/gpio.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/hardware.h>
#include <linux/io.h>
#define BUZZER_MAJOR 240
#define S3C64XX_GPFCON (S3C64XX_GPF_BASE + 0x00)
#define S3C64XX_GPFDAT (S3C64XX_GPF_BASE + 0x04)
#define BUZZER_NAME "6410buzzer"
int buzzer_open(struct inode *inode, struct file *filp)
{
unsigned int tmp;
tmp = readl(S3C64XX_GPFCON);
tmp = (tmp & ~(0xc0000000)|(0x40000000)); //set the GPIO output mode
writel(tmp, S3C64XX_GPFCON);
printk("$$$$$$$$$$$buzzer_open$$$$$$$$$\n");
return 0;
}
ssize_t buzzer_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk("$$$$$$$$$$buzzer_read$$$$$$$$$\n");
return count;
}
ssize_t buzzer_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
char mbuf[10];
unsigned int tmp;
copy_from_user(mbuf,buf,count);
switch(mbuf[0])
{
case 0:
tmp = readl(S3C64XX_GPFDAT);
tmp |= (0x8000);
writel(tmp, S3C64XX_GPFDAT);
break;
case 1:
tmp = readl(S3C64XX_GPFDAT);
tmp &= ~(0x8000);
writel(tmp, S3C64XX_GPFDAT);
break;
default:
break;
}
printk("$$$$$$$$$$buzzer_write$$$$$$$$$\n");
return count;
}
int buzzer_release(struct inode *inode, struct file *filp)
{
printk("$$$$$$$$$$buzzer_release$$$$$$$$$\n");
return 0;
}
struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = buzzer_open,
.read = buzzer_read,
.write = buzzer_write,
.release = buzzer_release,
};
static struct class *buzzer_class;
static int buzzer_init(void)
{
int rc;
printk("Test buzzer dev\n");
rc = register_chrdev(BUZZER_MAJOR, "BUZZER_NAME", &my_fops);
if(rc < 0)
{
printk("register %s dev error\n", "BUZZER_NAME");
return -1;
}
printk("$$$$$$$$$ register buzzer dev OK\n");
buzzer_class = class_create(THIS_MODULE, BUZZER_NAME);
if(IS_ERR(buzzer_class))
{
printk( " register class falid!\n","BUZZER_NAME");
return -1;
}
//创建一个设备节点,设备名为BUZZER_NAME,即:6410buzzer
device_create(buzzer_class, NULL, MKDEV(BUZZER_MAJOR, 0), NULL, BUZZER_NAME);
return 0;
}
static void buzzer_exit(void)
{
unregister_chrdev(BUZZER_MAJOR, "BUZZER_NAME");
device_destroy(buzzer_class, MKDEV(BUZZER_MAJOR, 0));
class_destroy(buzzer_class);
printk("Good Bye!\n");
}
MODULE_LICENSE("GPL");
module_init(buzzer_init);
module_exit(buzzer_exit);
2、测试源码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h> //POSIX 终端控制定义
#include <unistd.h> //Unix 标准函数定义
#include <stdlib.h>
#define DEVICE "/dev/6410buzzer"
static int getch(void) //定义函数在终端上获得输入,并把输入的量(int)返回
{
struct termios oldt,newt; //终端结构体struct termios
int ch;
if (!isatty(STDIN_FILENO)) { //判断串口是否与标准输入相连
fprintf(stderr, "this problem should be run at a terminal\n");
exit(1);
}
// save terminal setting
if(tcgetattr(STDIN_FILENO, &oldt) < 0) { //获取终端的设置参数
perror("save the terminal setting");
exit(1);
}
// set terminal as need
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO ); //控制终端编辑功能参数ICANON 表示使用标准输入模式;参数ECH0 表示显示输入字符
if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) { //保存新的终端参数
perror("set terminal");
exit(1);
}
ch = getchar();
// restore termial setting
if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) { //恢复保存旧的终端参数
perror("restore the termial setting");
exit(1);
}
return ch;
}
int main(void)
{
int fd, i;
char buf[10] = {0, 1};
fd = open(DEVICE, O_RDWR);
if(fd < 0)
{
printf("Open /dev/6410buzzer file error\n");
return -1;
}
while(1)
{
char key;
key = getch();
if(key=='0') //输入字符0即退出
break;
write(fd, &buf[0], 1);
usleep(10000);
write(fd, &buf[1], 1);
usleep(10000);
}
close(fd);
return 0;
}
3:、编译进内核linux-3.6.6的配置:
为了和pwm-beeper对照所以我把他放在了:Y:\linux-3.6.6\drivers\input\misc目录下,本来本驱动是字符驱动,你可以放在drivers\char目录下!
a、修改Kconfig
config INPUT_PWM_BEEPER
tristate "PWM beeper support"
#add by hcm
# select HAVE_PWM
depends on HAVE_PWM
help
Say Y here to get support for PWM based beeper devices.
If unsure, say N.
To compile this driver as a module, choose M here: the module will be
called pwm-beeper.
#add by hcm
config INPUT_PWM_6410BEEPER
tristate "PWM 6410beeper support"
depends on HAVE_PWM
help
this is buzzer driver for s3c6410
Say Y here to get support for PWM based beeper devices.
If unsure, say N.
To compile this driver as a module, choose M here: the module will be
called pwm-beeper.
b、修改makefile
#add by hcm
obj-$(CONFIG_INPUT_PWM_6410BEEPER) += pwm-6410beeper.o
c、make menuconfig
System Type --->
| | [*] MMU-based Paged Memory Management Support | |
| | ARM system type (Samsung S3C64XX) ---> | |
| | *** Boot options *** | |
| | [*] S3C Reboot on decompression error | |
| | [*] Force UART FIFO on during boot process | |
| | (0) S3C UART to use for low-level messages | |
| | (0) Number of additional GPIO pins | |
| | (0) Space between gpio banks | |
| | [ ] ADC common driver support | |
| | [*] PWM device support
Input device support --->
[*] Miscellaneous devices --->
| | < > User level driver support | |
| | < > PCF8574 Keypad input device | |
| | < > PWM beeper support | |
| | <*> PWM 6410beeper support | |
| | < > Rotary encoders connected to GPIO pins
d、编译pwm-test.c
arm-linux-gcc -o pwm-test pwm-test.c
拷贝进系统运行即可听到声音!
[root@urbetter /]# ./pwm-test1
$$$$$$$$$$$buzzer_open$$$$$$$$$
$$$$$$$$$$buzzer_write$$$$$$$$$
$$$$$$$$$$buzzer_write$$$$$$$$$
$$$$$$$$$$buzzer_release$$$$$$$$$(0退出)