蜂鸣器驱动程序,自动创建设备节点,内核目录之外编译。通过应用程序控制,每次按回车改变蜂鸣器的状态(响或不响),并输出引脚状态。
驱动程序:beep_drv.c
#include <mach/gpio.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static int beep_major = 0;
static struct class *pClass = NULL;
module_param(beep_major, int, 0);
MODULE_AUTHOR("Huangdezhi");
MODULE_LICENSE("Dual BSD/GPL");
#define BEEP_MAGIC 'k'
#define BEEP_START_CMD _IO (BEEP_MAGIC, 1)
#define BEEP_STOP_CMD _IO (BEEP_MAGIC, 2)
/*
* Open the device; in fact, there's nothing to do here.
*/
int beep_open (struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t beep_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
{
*buff = gpio_get_value(S5PV210_GPD0(0));//获取引脚的电平值
return 0;
}
ssize_t beep_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
return 0;
}
void beep_stop( void )
{
s3c_gpio_cfgpin(S5PV210_GPD0(0), S3C_GPIO_OUTPUT);//设置引进为输出状态
s3c_gpio_setpull(S5PV210_GPD0(0), S3C_GPIO_PULL_NONE);//不设置上拉
gpio_set_value(S5PV210_GPD0(0), 0);//设置引脚为低电平,即不要蜂鸣器响
}
void beep_start( void )
{
s3c_gpio_cfgpin(S5PV210_GPD0(0), S3C_GPIO_OUTPUT);
s3c_gpio_setpull(S5PV210_GPD0(0), S3C_GPIO_PULL_NONE);
gpio_set_value(S5PV210_GPD0(0), 1);//设置引脚为高电平,即要蜂鸣器响
}
static int beep_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch ( cmd ) {
case BEEP_START_CMD: {
beep_start(); break;
}
case BEEP_STOP_CMD: {
beep_stop(); break;
}
default: {
break;
}
}
return 0;
}
static int beep_release(struct inode *node, struct file *file)
{
return 0;
}
/*
* Our various sub-devices.
*/
/* Device 0 uses remap_pfn_range */
static struct file_operations beep_remap_ops = {
.owner = THIS_MODULE,
.open = beep_open,
.release = beep_release,
.read = beep_read,
.write = beep_write,
.ioctl = beep_ioctl,
};
/*
* There's no need for us to maintain any
* special housekeeping info, so we just deal with raw cdevs.
*/
static struct cdev BeepDevs;
/*
* Module housekeeping.
*/
static int beep_init(void)
{
int result;
dev_t dev = MKDEV(beep_major, 0);
s3c_gpio_cfgpin(S5PV210_GPD0(0), S3C_GPIO_OUTPUT);
s3c_gpio_setpull(S5PV210_GPD0(0), S3C_GPIO_PULL_NONE);
gpio_set_value(S5PV210_GPD0(0), 0);
/* Figure out our device number. */
if (beep_major)
result = register_chrdev_region(dev, 1, "beep");
else {
result = alloc_chrdev_region(&dev, 0, 1, "beep");
beep_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "beep: unable to get major %d\n", beep_major);
return result;
}
if (beep_major == 0)
beep_major = result;
/* Register a class_device in the sysfs. */
pClass = class_create(THIS_MODULE, "beep");//注册一个类,使mdev可以在"/dev/"目录下面建立设备节点,在设备中动态创建节点
if(NULL == pClass)
{
unregister_chrdev_region(dev, 1);
return -1;
}
device_create(pClass, NULL, dev, NULL, "beep");
/* Now set up cdev. */
cdev_init(&BeepDevs, &beep_remap_ops);
BeepDevs.owner = THIS_MODULE;
result = cdev_add (&BeepDevs, dev, 1);
if(result != 0)
{
device_destroy(pClass, dev);
class_destroy(pClass);
unregister_chrdev_region(dev, 1);
return -1;
}
printk("beep device installed, with major %d\n", beep_major);
return 0;
}
static void beep_cleanup(void)
{
cdev_del(&BeepDevs);
unregister_chrdev_region(MKDEV(beep_major, 0), 1);
printk("beep device uninstalled\n");
}
module_init(beep_init);
module_exit(beep_cleanup);
EXPORT_SYMBOL(beep_major);
//1.自动获取主设备号、次设备号
//2.动态生成设备节点(dev/ 目录下)
// 动态卸载
驱动程序的Makefile(便于在内核目录之外编译):Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?=/home/user/kernel
#当前Makefile目录
PWD := $(shell pwd)
# -C $(KERNELDIR)指明跳转到内核源码目录下读取那里的Makefile
# M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
obj-m := beep_drv.o
endif
应用程序:beep_test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#define BEEP_MAGIC 'k'
#define BEEP_START_CMD _IO (BEEP_MAGIC, 1)
#define BEEP_STOP_CMD _IO (BEEP_MAGIC, 2)
int main()
{
int i = 0;
char buf;
int dev_fd;
dev_fd = open("/dev/beep",O_RDWR | O_NONBLOCK);
if ( dev_fd == -1 ) {
printf("Cann't open file /dev/beep\n");
exit(1);
}
while(1)
{
getchar();
ioctl (dev_fd, BEEP_START_CMD,0);
read(dev_fd,&buf,sizeof(buf));
printf("The value of the buzzer:%d\n",buf);
getchar();
ioctl (dev_fd, BEEP_STOP_CMD,0);
read(dev_fd,&buf,sizeof(buf));
printf("The value of the buzzer:%d\n",buf);
}
return 0;
}
应用程序Makefile:Makefile
KERNELDIR ?=/home/user/kernel
all: beep_test
#大写I指定头文件所在目录
beep_test : main.c
arm-none-linux-gnueabi-gcc -I$(KERNELDIR) -o $@ $^
clean :
rm beep_test