蜂鸣器驱动程序,应用程序控制(自动创建设备节点,内核目录之外编译)

蜂鸣器驱动程序,自动创建设备节点,内核目录之外编译。通过应用程序控制,每次按回车改变蜂鸣器的状态(响或不响),并输出引脚状态。


驱动程序: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


你可能感兴趣的:(ARM-LINUX驱动学习)