当前位置: 首页 > news >正文

5.5 misc驱动框架

1. misc类设备驱动框架

linux内核中的杂项设备(Miscellaneous Devices)是一种通用的设备类型。现在的硬件设备多种多样,有很多设备不好对他们进行一个单独的分类,所以就将这些设备全部归属于misc类设备,比如adc、buzzer等设备归属于misc类设备中。杂项设备的主设备号固定为10.

2. misc类设备驱动框架分析

2.1 miscdevice 结构体


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

2.2 misc驱动框架源码

源码在kernel/drivers/char/misc.c中:

/** linux/drivers/char/misc.c** Generic misc open routine by Johan Myreen** Based on code from Linus** Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's*   changes incorporated into 0.97pl4*   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)*   See busmouse.c for particulars.** Made things a lot mode modular - easy to compile in just one or two* of the misc drivers, as they are now completely independent. Linus.** Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>** Fixed a failing symbol register to free the device registration*		Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96** Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96** Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96** Handling of mouse minor numbers for kerneld:*  Idea by Jacques Gelinas <jack@solucorp.qc.ca>,*  adapted by Bjorn Ekwall <bj0rn@blox.se>*  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>** Changes for kmod (from kerneld):*	Cyrus Durgin <cider@speakeasy.org>** Added devfs support. Richard Gooch <rgooch@atnf.csiro.au>  10-Jan-1998*/#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>/** Head entry for the doubly linked miscdevice list*/
static LIST_HEAD(misc_list);
static DEFINE_MUTEX(misc_mtx);/** Assigned numbers, used for dynamic minors*/
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
{mutex_lock(&misc_mtx);return seq_list_start(&misc_list, *pos);
}static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{return seq_list_next(v, &misc_list, pos);
}static void misc_seq_stop(struct seq_file *seq, void *v)
{mutex_unlock(&misc_mtx);
}static int misc_seq_show(struct seq_file *seq, void *v)
{const struct miscdevice *p = list_entry(v, struct miscdevice, list);seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");return 0;
}static const struct seq_operations misc_seq_ops = {.start = misc_seq_start,.next  = misc_seq_next,.stop  = misc_seq_stop,.show  = misc_seq_show,
};static int misc_seq_open(struct inode *inode, struct file *file)
{return seq_open(file, &misc_seq_ops);
}static const struct file_operations misc_proc_fops = {.owner	 = THIS_MODULE,.open    = misc_seq_open,.read    = seq_read,.llseek  = seq_lseek,.release = seq_release,
};
#endifstatic int misc_open(struct inode * inode, struct file * file)
{int minor = iminor(inode);struct miscdevice *c;int err = -ENODEV;const struct file_operations *old_fops, *new_fops = NULL;mutex_lock(&misc_mtx);list_for_each_entry(c, &misc_list, list) {if (c->minor == minor) {new_fops = fops_get(c->fops);		break;}}if (!new_fops) {mutex_unlock(&misc_mtx);request_module("char-major-%d-%d", MISC_MAJOR, minor);mutex_lock(&misc_mtx);list_for_each_entry(c, &misc_list, list) {if (c->minor == minor) {new_fops = fops_get(c->fops);break;}}if (!new_fops)goto fail;}err = 0;old_fops = file->f_op;file->f_op = new_fops;if (file->f_op->open) {file->private_data = c;err=file->f_op->open(inode,file);if (err) {fops_put(file->f_op);file->f_op = fops_get(old_fops);}}fops_put(old_fops);
fail:mutex_unlock(&misc_mtx);return err;
}static struct class *misc_class;static const struct file_operations misc_fops = {.owner		= THIS_MODULE,.open		= misc_open,
};/***	misc_register	-	register a miscellaneous device*	@misc: device structure*	*	Register a miscellaneous device with the kernel. If the minor*	number is set to %MISC_DYNAMIC_MINOR a minor number is assigned*	and placed in the minor field of the structure. For other cases*	the minor number requested is used.**	The structure passed is linked into the kernel and may not be*	destroyed until it has been unregistered.**	A zero is returned on success and a negative errno code for*	failure.*/int misc_register(struct miscdevice * misc)
{struct miscdevice *c;dev_t dev;int err = 0;INIT_LIST_HEAD(&misc->list);mutex_lock(&misc_mtx);list_for_each_entry(c, &misc_list, list) {if (c->minor == misc->minor) {mutex_unlock(&misc_mtx);return -EBUSY;}}if (misc->minor == MISC_DYNAMIC_MINOR) {int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);if (i >= DYNAMIC_MINORS) {mutex_unlock(&misc_mtx);return -EBUSY;}misc->minor = DYNAMIC_MINORS - i - 1;set_bit(i, misc_minors);}dev = MKDEV(MISC_MAJOR, misc->minor);misc->this_device = device_create(misc_class, misc->parent, dev,misc, "%s", misc->name);if (IS_ERR(misc->this_device)) {int i = DYNAMIC_MINORS - misc->minor - 1;if (i < DYNAMIC_MINORS && i >= 0)clear_bit(i, misc_minors);err = PTR_ERR(misc->this_device);goto out;}/** Add it to the front, so that later devices can "override"* earlier defaults*/list_add(&misc->list, &misc_list);out:mutex_unlock(&misc_mtx);return err;
}/***	misc_deregister - unregister a miscellaneous device*	@misc: device to unregister**	Unregister a miscellaneous device that was previously*	successfully registered with misc_register(). Success*	is indicated by a zero return, a negative errno code*	indicates an error.*/int misc_deregister(struct miscdevice *misc)
{int i = DYNAMIC_MINORS - misc->minor - 1;if (list_empty(&misc->list))return -EINVAL;mutex_lock(&misc_mtx);list_del(&misc->list);device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));if (i < DYNAMIC_MINORS && i >= 0)clear_bit(i, misc_minors);mutex_unlock(&misc_mtx);return 0;
}EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);static char *misc_devnode(struct device *dev, mode_t *mode)
{struct miscdevice *c = dev_get_drvdata(dev);if (mode && c->mode)*mode = c->mode;if (c->nodename)return kstrdup(c->nodename, GFP_KERNEL);return NULL;
}static int __init misc_init(void)
{int err;#ifdef CONFIG_PROC_FSproc_create("misc", 0, NULL, &misc_proc_fops);
#endifmisc_class = class_create(THIS_MODULE, "misc");err = PTR_ERR(misc_class);if (IS_ERR(misc_class))goto fail_remove;err = -EIO;if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))goto fail_printk;misc_class->devnode = misc_devnode;return 0;fail_printk:printk("unable to get major %d for misc devices\n", MISC_MAJOR);class_destroy(misc_class);
fail_remove:remove_proc_entry("misc", NULL);return err;
}
subsys_initcall(misc_init);

(1)int misc_register(struct miscdevice * misc); misc设备注册

(2)int misc_deregister(struct miscdevice *misc); misc设备卸载

3. misc设备驱动实例

蜂鸣器驱动(buzzer)

#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_FREQ		1
#define PWM_IOCTL_STOP			0static struct semaphore lock;// TCFG0在Uboot中设置,这里不再重复设置
// Timer0输入频率Finput=pclk/(prescaler1+1)/MUX1
//                     =66M/16/16
// TCFG0 = tcnt = (pclk/16/16)/freq;
// PWM0输出频率Foutput =Finput/TCFG0= freq
static 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->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 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");

相关文章:

  • SIEMENS 标准程序解读 ---> Fanuc(法那科)机器手通讯交互程序
  • csp基础之进制转换器
  • `shallowReactive` 与 `shallowRef`:浅层响应式 API
  • RA4M2开发涂鸦模块CBU(3)----定时器GPT-PWM调光
  • 【软考高级系统架构论文】论企业集成平台的理解与应用
  • Springfox使用详解
  • CPU Cache 的映射与寻址
  • Vue+spring boot前后端分离项目搭建---小白入门
  • Qt + C++ 入门2(界面的知识点)
  • UML:状态图介绍与绘制
  • 【FineDance】舞蹈多样性的得来
  • 通过 Lambda + API Gateway + 外部 API 实现。
  • 在 MyBatis 的xml中,什么时候大于号和小于号可以不用转义
  • 使用Node.js开发服务端接口
  • quartz 表达式最近10次执行时间接口编写
  • 【设计模式】3.装饰模式
  • leetcode332.重新安排行程:优先队列与DFS实现欧拉路径的行程规划
  • AIGC工具平台-SadTalker音频对口型数字人
  • Linux 内核中 TCP 协议栈的输出实现:tcp_output.c 文件解析
  • 2D曲线点云平滑去噪
  • 学生网站建设的总结与评价/app推广策略
  • html5做网页/惠州百度关键词优化
  • wordpress图文直播插件/网络优化是干什么的
  • 相城专业的网站建设/凤凰军事新闻最新消息
  • 网站建设属于什么科目/西seo优化排名
  • 独立购物网站建设/网络seo优化