蜂鸣器驱动程序,自动创建设备节点,内核目录之外编译。通过应用程序控制,每次按回车改变蜂鸣器的状态(响或不响),并输出引脚状态。
驱动程序: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/ 目录下) // 动态卸载
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
#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; }
KERNELDIR ?=/home/user/kernel all: beep_test #大写I指定头文件所在目录 beep_test : main.c arm-none-linux-gnueabi-gcc -I$(KERNELDIR) -o $@ $^ clean : rm beep_test