misc类设备与蜂鸣器驱动
来源:互联网 发布:马哥linux培训 编辑:程序博客网 时间:2024/05/15 09:32
以下内容源于朱有鹏《物联网大讲堂》课程的学习,如有侵权,请告知删除。
一、板载蜂鸣器驱动测试
1、驱动部分
(1)九鼎移植内核已经提供了蜂鸣器驱动源码,但如何查找是否已经有驱动文件?
- 法一,在源码文件集合中搜索关键字buzzer,x210-buzzer……
- 法二,make menuconfig,然后查找关键字buzzer,知道路径……
(2)是否被编译?
- 取决于Makefile文件中的宏:obj-$(CONFIG_X210_BUZZER_DRIVER) += x210-buzzer.o;
- 而宏又取决于Kconfig文件中的项目(X210_BUZZER_DRIVER)是否显示“y”;
- 而Kconfig文件中的项目是否显示“y”,是通过make menuconfig来配置的(路径和源码文件的路径基本一致的)。
(3)bug排查
- 修改Makefile中的宏名(将CONFIG_BUZZER_DRIVER改为CONFIG_X210_BUZZER_DRIVER,因为Makefile中的要和Kconfig中的对应(make menuconfig是以Kconfig的为准的,配置后可以在.config文件中看到CONFIG_X210_BUZZER_DRIVER是“y”),最终可以在系统中看到/dev/buzzer。
2、应用部分
(1)应用编写
- 先查看自己编写的驱动文件x210_buzzer.c,看都有哪些操作:打开文件+ioctl;然后针对地编写应用。
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/poll.h>#include <asm/irq.h>#include <asm/io.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <mach/hardware.h>#include <plat/regs-timer.h>#include <mach/regs-irq.h>#include <asm/mach/time.h>#include <linux/clk.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/miscdevice.h>#include <linux/gpio.h>#include <plat/gpio-cfg.h>//#include <plat/regs-clock.h>//#include <plat/regs-gpio.h>//#include <plat/gpio-bank-e.h>//#include <plat/gpio-bank-f.h>//#include <plat/gpio-bank-k.h>#define DEVICE_NAME "buzzer"#define PWM_IOCTL_SET_FREQ1#define PWM_IOCTL_STOP0static struct semaphore lock;// TCFG0在Uboot中设置,这里不再重复设置// Timer0输入频率Finput=pclk/(prescaler1+1)/MUX1// =66M/16/16// TCFG0 = tcnt = (pclk/16/16)/freq;// PWM0输出频率Foutput =Finput/TCFG0= freqstatic void PWM_Set_Freq( unsigned long freq ){unsigned long tcon;unsigned long tcnt;unsigned long tcfg1;struct clk *clk_p;unsigned long pclk;//unsigned tmp;//设置GPD0_2为PWM输出s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(2));tcon = __raw_readl(S3C2410_TCON);tcfg1 = __raw_readl(S3C2410_TCFG1);//mux = 1/16tcfg1 &= ~(0xf<<8);tcfg1 |= (0x4<<8);__raw_writel(tcfg1, S3C2410_TCFG1);clk_p = clk_get(NULL, "pclk");pclk = clk_get_rate(clk_p);tcnt = (pclk/16/16)/freq;__raw_writel(tcnt, S3C2410_TCNTB(2));__raw_writel(tcnt/2, S3C2410_TCMPB(2));//占空比为50%tcon &= ~(0xf<<12);tcon |= (0xb<<12);//disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0__raw_writel(tcon, S3C2410_TCON);tcon &= ~(2<<12);//clear manual update bit__raw_writel(tcon, S3C2410_TCON);}void PWM_Stop( void ){//将GPD0_2设置为inputs3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(0));}static int x210_pwm_open(struct inode *inode, struct file *file){if (!down_trylock(&lock))return 0;elsereturn -EBUSY;}static int x210_pwm_close(struct inode *inode, struct file *file){up(&lock);return 0;}// PWM:GPF14->PWM0static int x210_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){switch (cmd) {case PWM_IOCTL_SET_FREQ://printk("PWM_IOCTL_SET_FREQ:\r\n");if (arg == 0)return -EINVAL;PWM_Set_Freq(arg);break;case PWM_IOCTL_STOP:default:printk("PWM_IOCTL_STOP:\r\n");PWM_Stop();break;}return 0;}static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = x210_pwm_open, .release = x210_pwm_close, .ioctl = x210_pwm_ioctl,};static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};static int __init dev_init(void){int ret;init_MUTEX(&lock);ret = misc_register(&misc);/* GPD0_2 (PWMTOUT2) */ret = gpio_request(S5PV210_GPD0(2), "GPD0");if(ret)printk("buzzer-x210: request gpio GPD0(2) fail");s3c_gpio_setpull(S5PV210_GPD0(2), S3C_GPIO_PULL_UP);s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(1));gpio_set_value(S5PV210_GPD0(2), 0);printk ("x210 "DEVICE_NAME" initialized\n"); return ret;}static void __exit dev_exit(void){misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("www.9tripod.com");MODULE_DESCRIPTION("x210 PWM Driver");
(2)测试实践
- 编写完下面的app_buzzer.c后,执行 arm-linux-gcc app_buzzer.c -o app.buzzer;
- 然后将app.buzzer拷贝到开发板根文件系统下,最后./app.buzzer执行。
- 注意,必须将buzzer编译进内核才能如此操作!
#include <stdio.h>#include <sys/stat.h>#include <fcntl.h>#define DEVNAME"/dev/buzzer" //蜂鸣器对应的设备文件#define PWM_IOCTL_SET_FREQ1 //命令来自驱动文件,应用层知道这些宏的含义#define PWM_IOCTL_STOP0int main(void){int fd = -1;fd = open(DEVNAME, O_RDWR);if (fd < 0){perror("open");return -1;}ioctl(fd, PWM_IOCTL_SET_FREQ, 10000);sleep(3);ioctl(fd, PWM_IOCTL_STOP);sleep(3);ioctl(fd, PWM_IOCTL_SET_FREQ, 3000);sleep(3);ioctl(fd, PWM_IOCTL_STOP);sleep(3);close(fd);return 0;}
二、misc类设备介绍
1、何为misc?
(1)中文名:杂项设备\杂散设备,不明确的分类。
(2)在/sys/class/misc目录下。
(3)都属于字符设备。
(4)有一套驱动框架,内核实现一部分(misc.c),驱动实现一部分(x210-buzzer.c)。
(5)misc是对原始的字符设备注册接口的一个类层次的封装,很多典型字符设备都可以归类到misc类中,使用misc驱动框架来管理。
(6)这些字符设备不符合预先确定的字符设备范畴
- 所有这些设备采用主编号10,次设备号不一样。它们一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。
2、misc类设备驱动架构
(1)内核开发者实现部分,关键点有2个
- 一个是类的创建(因此驱动开发者不需要再创建类);
- 一个是开放给驱动开发者的接口misc_deregister函数。
(2)具体设备驱动工程师实现部分
3、本部分学习方法
(1)蜂鸣器驱动源码已有,分析为主;
(2)复习并验证前面讲的驱动框架的思维;
(3)开始注意一些细节。
三、misc驱动框架源码分析1(内核开发者实现的部分)
1、misc源码框架基础
(1)在/driver/char/misc.c中。
(2)源码框架本身也是一个模块(因此可以实现裁剪),内核启动时自动加载。
- 因此会在/sys/class目录下创建misc子目录,即misc这个类
(3)源码框架的主要工作
- 注册miscc类;
- 使用老接口注册字符设备驱动(主设备号为10);
- 开放device注册的接口misc_register给驱动工程师。
2、misc类设备的注册
(1)驱动工程师需要借助misc来加载自己的驱动时,只需要调用misc_register接口注册自己的设备即可,其余均不用管。
(2)misc_list链表的作用
- 内核定义了一个misc_list链表(static LIST_HEAD(misc_list);),用来记录所有内核中注册了的杂散类设备。
- 当我们向内核注册一个misc类设备时,内核就会向misc_list链表中insert一个节点。
- 之前字符设备时,是固定大小(255)的数组。
- 当使用cat /proc/misc打印出信息时,其实就是遍历此链表。
#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)原式子:static LIST_HEAD(misc_list);展开后:static struct list_head misc_list = { &(misc_list), &(misc_list) }//被初始化的内核链表
(3)主设备号和次设备号的作用和区分。
- 主设备号,表示类;次设备号,表示某具体设备。
四、misc驱动框架源码分析2(misc.c文件,内核开发者提供)
1、open函数分析
- 最终还是会映射到x210_buzzer.c中的open函数。
2、misc在proc下的展现
3、内核互斥锁
(1)何为互斥锁?
- 实现互斥访问。类似于图书馆借书。
(2)定义:DEFINE_MUTEX
- 解析方法同上面三2(2)
原式子:static DEFINE_MUTEX(misc_mtx);……
(3)上锁mutex_lock和解锁mutex_unlock
- 要访问某资源时,要给该资源上锁;使用完后,要解锁。
- 当某进程想访问已经被上锁的资源时,会休眠,直到其他进程解锁后此进程才能访问该资源。类似于上厕所(休眠锁、等待锁)。
(4)内核防止竞争状态的手段:原子访问,自旋锁、互斥锁、信号量
- 原子访问主要用来做计数;如int count;count++(这个可能被打断)
- 自旋锁后面讲中断会详细讲;应用于多核心。
- 互斥锁和信号量很相似(其实就是计数值为1的信号量),互斥锁的出现比信号量晚,实现上比信号量优秀,尽量使用互斥锁。
五、蜂鸣器驱动源码分析1
1、dev_init
(1)信号量
- init_MUTEX(&lock);//将信号量初始化为1,其示就是互斥锁
(2)miscdevice
static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,//动态次设备号.name = DEVICE_NAME,.fops = &dev_fops,};
(3)gpio_request
(4)printk
2、ioctl
(1)为什么需要ioctl(input output control,输入输出控制)?
- 这个函数让设备进行输入输出,但为何不用read和write?(因为read和write有缺陷,驱动和应用的交互有麻烦。)
- 缺陷:写驱动的人定义亮灭,但应用层的人怎么知道呢?
(2)ioctl怎么用
六、蜂鸣器驱动源码分析2
硬件操作有关的代码
- misc类设备与蜂鸣器驱动
- 整理--Misc类设备驱动
- linux驱动杂项设备类misc
- misc杂项设备驱动
- misc设备驱动
- MISC设备 --pwd_audio驱动
- MISC设备驱动
- misc设备驱动模型
- Linux misc 设备驱动
- 字符设备驱动之蜂鸣器与PWM——FS2410
- linux驱动开发之路(三)——嵌入式 Linux 的蜂鸣器控制实验(misc设备)
- 6-1 misc设备驱动开发与实例
- linux misc混杂设备驱动
- linux misc混杂设备驱动 .
- misc设备驱动模拟代码
- Linux misc设备驱动理解
- linux设备驱动之混杂设备misc
- 【linux驱动分析】misc设备驱动
- Modelsim高级脚本Do仿真
- oracle 创建用户,表空间,给权限,设置表空间自动增长
- SystemUI 7.0学习笔记四-Recents
- KMP模板
- Service 与 Thread 的区别
- misc类设备与蜂鸣器驱动
- 1.0 BS结构软件类型介绍
- 2017中兴算法挑战赛(迪杰斯特拉)
- JAVA 之 file 的 getPath、getAbsolutePath和getCanonicalPath的不同
- 类模板
- Treap的实现方法 [BZOJ 3224]
- MP3每一帧的采样个数和采样率如何理解?(神文)
- salesforce中如何自定义picklist值的顺序
- 概念理解