这个驱动本来是非常简单的,但是我就是想做个杂项驱动。
Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述)。miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同。
蜂鸣器控制原理
先来看下蜂鸣器的电路图:
其实做了前面的LED点灯驱动,那做这个驱动就是分分钟钟的事。从上面的电路图可以知道控制蜂鸣器的引脚就是GPB0;这样就非常简单了,需要操作的就是。
1、初始化
s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);// 设置GPBCON
s3c2410_gpio_setpiin(S3C2410_GPB(0), 1); // 设置GPBDAT
2、根据参数开关蜂鸣器
s3c2410_gpio_setpin(S3C2410_GPB(0), flag); // 根据flag来开关蜂鸣器;
杂项设备知识
杂项设备结构体(杂项设备的主设备号固定为10,不同的杂项设备是通过次设备号来区分的)
struct miscdevice { int minor; // 次设备号 const char *name;// 设备名称 const struct file_operations *fops; // 关联的操作函数 struct list_head list; struct device *parent; struct device *this_device; const char *nodename; mode_t mode; };
其实从上面的结构体可以知道,杂项设备驱动只能驱动一个设备,因为杂项驱动主设备号固定为10(不同杂项设备通过次设备号来区分),而结构体中只有一个次设备号,所以可以看出杂项驱动只能驱动一个设备;如果要驱动多个设备,则不能用杂项驱动;(同类设备要靠次设备来区分)
下面要说的两个杂项驱动操作函数都在:/devices/char/Misc.c;创建和初始化杂项驱动:int misc_register(struct miscdevice * misc);这个函数就大概相当于:字符驱动中的设备号创建,字符设备的申请和初始化等(alloc_chrdev_region()设备号申请;cdevp = cdev_alloc()申请字符结构;cdev_init(cdevp, &fops)让字符结构和操作函数绑定;cdev_add(cdevp, devNum,
1)绑定主设备号;)
当然和创建初始化相反的就是:int misc_deregister(struct miscdevice *misc);函数了,该函数的功能和上面的创建函数相反;
驱动代码
#include<linux/init.h> #include<linux/module.h> #include<linux/fs.h> #include<linux/miscdevice.h> #include<linux/gpio.h> #include<mach/regs-gpio.h> #define DEV_NAME "yzhBuzzer" ssize_t myOpen(struct inode *inode, struct file *file) { printk(KERN_INFO"in myOpen!\n"); s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT); s3c2410_gpio_setpin(S3C2410_GPB(0), 1); return 0; } int myIoctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { printk(KERN_INFO"in myIoctl cmd:%u, arg:%ld\n", cmd, arg); if (!cmd) s3c2410_gpio_setpin(S3C2410_GPB(0), 0); else s3c2410_gpio_setpin(S3C2410_GPB(0), 1); return 0; } struct file_operations fop = { .owner = THIS_MODULE, .ioctl = myIoctl, .open = myOpen, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEV_NAME, .fops = &fop, }; static int __init buzzer_init(void) { int ret; printk(KERN_INFO"buzzer init!\n"); ret = misc_register(&misc); return ret; } static void __exit buzzer_exit(void) { printk(KERN_INFO"buzzer exit!\n"); misc_deregister(&misc); } module_init(buzzer_init); module_exit(buzzer_exit); MODULE_LICENSE("Dual BSD/GPL");
附上一个Makefile,现在写的驱动都是非常简单的,所以Makefile基本是可以通用的:
obj-m:=buzzer.o CC=arm-linux-gcc #KERDIR=/lib/modules/$(shell uname -r)/build KERDIR=/home/kernel/linux-2.6.32.2 CURDIR=$(shell pwd) all: make -C $(KERDIR) M=$(CURDIR) modules clean: make -C $(KERDIR) M=$(CURDIR) clean
测试代码
测试代码非常简单,这个驱动加载进去后会自动在dev下面创建设备文件。直接操作这个文件就可以了;因为只有一个蜂鸣器,所以用ioctl函数实现有个参数是多余的。
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<fcntl.h> int main(int argc, char *argv[]) { int flag = 0; int fd = open("/dev/yzhBuzzer", O_RDWR); if(fd < 0) printf("int open error:%d\n", errno); if (argc > 1) flag = 1; if(ioctl(fd, flag, 0) < 0) printf("int ioctl error:%d", errno); return 0; }
转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/45131611
若有不正确之处,望大家指正,共同学习!谢谢!!!