首页 > 代码库 > linux驱动开发之misc类设备介绍
linux驱动开发之misc类设备介绍
1、什么是misc设备?
misc是英文的简称,中文名一般叫做杂项设备/杂散设备。
我们知道大部分的设备都有一个明确的分类class,有一些设备进行分类时不太好分,我们不知道一些设备到底应该分到哪一类设备中去,所以最后将这些不知道分到哪类中的设备给分到misc设备中,也就是分到了杂散类中。像蜂鸣器还有ADC设备都被分到了misc设备杂散类设备中。杂散类设备对应的是一个类的概念。随意进到系统中的/sys/class目录中就会看到一个misc目录,这个misc就是杂散类设备,进入到misc目录中,我们可以看到很多设备被丢入到了杂散类设备中。
其实led也可以丢到misc杂散类设备中的,像buzzer也可以放到别的设备类中,所以这种东西并不是一定的,有些人就是不按照常规做事,见到时也不要奇怪。
杂散类设备是典型的字符设备,所以归到misc杂散类设备中的全部都是字符类设备。在后面我们也会看到misc杂散类设备本身就是被作为字符设备来来注册到内核中的,主设备号是10,是固定的表示misc设备,次设备号才是来区分具体杂散类设备的。比如九鼎的蜂鸣器驱动的主设备号是10,次设备号是61,adc驱动的主设备号是10,次设备号是131.就像我们以前实现led的驱动一样,我们将板子上的四个led都归到了leds类中了,每个led的主设备号都是一样,次设备号是不一样的,主设备号一样表示同一类,次设备号不一样表示这类设备中的不同个体,来进行区分led1,led2,led3,led4。杂散类设备的主设备号就是10.
想要自动创建设备文件节点,就需要用udev或者mdev,想要udev或者mdev自动创建设备文件节点给一些设备驱动,那么就要将这些设备驱动给归到一个class设备驱动类中。内核之所以发明misc杂散类设备就是为将一些不知道该怎么归类的设备给放到misc中,将来创建设备节点的时候,可以使用udev或者mdev的机制来进行创建,不需要自己手动的去mknode创建设备文件节点,以及在驱动代码中进行创建类等。我们只需要创建设备类就行。
misc有一套驱动框架,内核实现了一部分(misc.c,在/drvier/char/misc/misc.c),驱动实现了一部分(x210-buzzer.c,这部分就是调用misc驱动框架中内核实现的那部分中的misc_register函数来进行创建设备,Misc_register函数中间接的调用了device_create函数创建设备)。内核实现的一部分中就创建出了misc类,我们驱动开发者只需要调用内核实现的接口misc_register函数,从而间接的调用device_create函数创建设备。我们只需要创建设备,misc类已经不用我恩去创建了。misc类已经由misc驱动框架提供了。
misc设备其实就是一种字符设备。很多典型的字符设备都可以归到misc设备中。
2、misc类设备的驱动架构
(1)内核开发者实现了一部分,具体工程师实现了一部分。内核开发着实现的misc设备的一部分是/drvier/char/misc/misc.c中,主要是misc类的创建。如代码
static int __init misc_init(void) { int err; #ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_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; }
和给驱动开发者提供的misc_regiter函数接口。主要就是创建misc设备
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; }
驱动开发者实现的部分是x210-buzzer.c
#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 0 static 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/16 tcfg1 &= ~(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设置为input s3c_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; else return -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); //注册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 D
本文出自 “whylinux” 博客,谢绝转载!
linux驱动开发之misc类设备介绍