1. 程式人生 > >s3c2440 雜項驅動實現蜂鳴器

s3c2440 雜項驅動實現蜂鳴器

        這個驅動本來是非常簡單的,但是我就是想做個雜項驅動。

        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;
 }