这个驱动本来是非常简单的,但是我就是想做个杂项驱动。
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
若有不正确之处,望大家指正,共同学习!谢谢!!!