• misc类设备与蜂鸣器驱动==Linux驱动开发6


    一、板载蜂鸣器驱动测试

    • 应用编写:打开文件 + ioctl。
    #include 
    #include 
    #incldue <fcntl.h>
    
    #define DEVNAME "/dev/buzzer"
    
    #define PWM_IOCTL_SET_FREQ 	1
    #define PWM_IOCTL_STOP 		0
    
    int 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    二、misc 类设备介绍

    1、何为misc

    • (1)中文名:杂项设备/杂散设备。
    • (2)位于/sys/class/misc 中。
    • (3)有一套驱动框架,内核实现一部分(misc.c),驱动实现一部分(x210-buzzer.c)。
    • (4)misc 是对原始字符设备注册接口的一个类层次的封装,很多典型字符设备可以归到 misc 类,使用 misc 驱动框架来管理。

    2、misc 类驱动框架架构

    • (1)内核开发者实现部分,关键点有两个:一个是类的创建,另一个是开放给驱动开发者的接口。
    • (2)设备工程师具体实现部分。

    三、misc驱动框架源码分析1

    1、misc 源码框架基础

    • (1)misc 源码框架本身也是一个模块,内核启动时自动加载。
    • (2)misc 源码框架的主要工作:注册 misc 类(class_create),使用老接口(register_chrdev) 注册字符设备驱动(主设备号 10),开放 misc_register 给驱动工程师。

    2、misc 类设备的注册

    • (1)驱动工程师需要借助 misc 来加载自己的驱动时,只需要调用 misc_register 接口注册自 己的设备即可,其余不用管。
    • (2)misc_list 链表的作用:内核定义了一个 misc_list 链表用来记录所有内核中注册了的杂 散类设备,当我们向内核注册一个 misc 类设备时,内核就会向 misc_list 链表中 insert 一个节点。

    四、misc 驱动框架源码分析 2

    1、open 函数分析

    • (1)open 函数经过层层调用,最终调用来 file_operations 里面的 open 函数。

    2、misc 在 proc 下的展现

    • (1)调用 proc_create。

    3、内核互斥锁

    • (1)何为互斥锁:一种特殊的信号量,用来对特定的代码段实行段保护。
    • (2)定义:DEFINE_MUTEX
    • (3)上锁 mutex_lock 和解锁 mutex_unlock。
    • (4)内核防止竞争状态的手段:原子操作、自旋锁、互斥锁、信号量。
    • (5)原子访问主要用来做计数、自旋锁后面讲中断会讲、互斥锁和信号量很相似。互斥锁 出现比信号量晚,实现上比信号量优秀,尽量使用互斥锁。

    五、蜂鸣器驱动源码分析 1

    1、dev_init

    • (1)信号量。 (2)miscdevice。 (3)gpio_request。 (4)printk。

    2、ioctl

    • (1)为什么需要 ioctl:ioctl 即可实现读,也可实现写,且除了命令外还可加参数。
    • (2)ioctl 怎么用:见驱动源码。
    #include 
    #include 
    #include 
    #include 
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include  
    #include 
    
    #define DEVICE_NAME	"buzzer"
    
    #define PWM_IOCTL_SET_FREQ	1
    #define PWM_IOCTL_STOP		0
    
    typedef unsigned long u_long;
     
    static struct semaphore lock;
    
    //被ioctl调用// TCFG0 在 Uboot 中设置,这里不再重复设置
    static void PWM_Set_Freq(unsigned long freq)
    {
    	u_long tcon,tcnt,tcfg1,pclk;
    	struct clk* clk_p;
    	
    	s3c_gpio_cfgpin(S5PV210_GPD0(2),S3C_GPIO_SFN(2));//设置 GPD0_2 为 PWM 输出
    	tcon=__raw_readl(S3C2410_TCON);
    	tcfg=__raw_readl(S3C2410_TCFG1);
    	
    	tcfg1&=~(0xf<<8);//mux=1/16
    	tcfg1|=(0x4<<8);
    	__raw_write(tcfg1,S3C2410_TCFG1);
    	clk_p=clk_get(NULL,"pclk");
    	pclk=clk_get_rate(clk_p);
    	tcnt=(pclk/16/16)/freq;
    	__raw_write(tcnt,S3C2410_TCNTB(2));
    	__raw_write(tcnt/2,S3C2410_TCMPB(2));//占空比0.5
    
    	tcon &= ~(0xf<<12);
    	tcon |= (0xb<<12);
    	__raw_writel(tcon, S3C2410_TCON);
    	tcon &= ~(2<<12);
    	__raw_writel(tcon, S3C2410_TCON); 
    }
    // 被ioctl调用
    void PWM_Stop(void)
    {
    	s3c_gpio_cfgpin(S5PV210_GP0(2),S3C_GPIO_SFN(0));//将GPD0_2设置为input	
    }
    static int x210_pwm_open(struct inode* inode,struct file* file)
    {
    	if(!down_trylock(&lock))//上锁
    		return 0;
    	else
    		return -EBUSY;	
    }
    static int x210_pwm_close(struct inode* inode,struct file* file,unsigned int cmd,unsigned long arg)
    {
    	ip(&lock);//解锁
    	return 0;
    }
    
    //PWM:GPF14->PWM0
    static 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 int __init dev_init(void)
    {
    	.minor=MISC_DYNAMIC_MINOR,
    	.name=DEVICE_NAME,
    	.fops=&dev_fops,
    }
    
    //设备安装函数
    static int __init dev_init(void)
    {
    	int ret=-1;
    	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);//gpio初始化
    	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);//注销设备
    	gpio_free(S5PV210_GPD0(2));//释放资源
    }
    
    module_init(dev_init); 
    module_exit(dev_exit); 
    
    MODULE_LICENSE("GPL"); 
    MODULE_AUTHOR("www.9tripod.com");
    MODULE_DESCRIPTION("x210 PWM Driver");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
  • 相关阅读:
    数组:移除元素
    卡尔曼滤波介绍
    RocketMq(三)-springboot项目访问
    绑定样式--class样式(字符串法、对象法、数组法)、style样式(直接绑定法、对象法、数组法)
    跨境物流FBM的主要流程是怎样的?
    MybatisX快速生成代码(mybatis plus模板)
    1.32 Cubemx_STM32F429串口中断+空闲中断
    做接口测试如何上次文件
    经典c程序100例==31--40
    使用基于SSIM的CNN进行环路滤波
  • 原文地址:https://blog.csdn.net/weixin_47397155/article/details/126003470