日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

misc类设备

發布時間:2025/3/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 misc类设备 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1:什么是misc驅動模型

Linux包含了許多的設備驅動類型,而不管分類有多細,總會有些漏網的,這就是我們經常說到的“其他的”等等。
在Linux里面,把無法歸類的五花八門的設備定義為混雜設備(用miscdevice結構體來描述)。Linux/內核所提供的miscdevice有很強的包容性。如NVRAM,看門狗,DS1286等實時時鐘,字符LCD,AMD 768隨機數發生器。

miscdevice共享一個主設備號MISC_MAJOR(10),但此設備號不同,所有的miscdevice設備形成一個鏈表,對設備訪問時內核根據次設備號查找對應的 miscdevice設備,然后調用其中的file_operations結構體中注冊的文件操作接口進程操作。

2:為什么要有misc驅動模型

第一,節省主設備號:
使用普通字符設備,不管該驅動的主設備號是靜態還是動態分配,都會消耗一個主設備號,這太浪費了。而且如果你的這個驅動最終會提交到內核主線版本上的話,需要申請一個專門的主設備號,這也麻煩。
如果使用misc驅動的話就好多了。因為內核中已經為misc驅動分配了一個主設備號。當系統中擁有多個misc設備驅動時,那么它們的主設備號相同,而用子設備號來區分它們。

第二,使用簡單:
有時候驅動開發人員需要開發一個功能較簡單的字符設備驅動,導出接口讓用戶空間程序方便地控制硬件,只需要使用misc子系統提供的接口即可快速地創建一個misc設備驅動。
當使用普通的字符設備驅動時,如果開發人員需要導出操作接口給用戶空間的話,需要自己去注冊字符驅動,并創建字符設備class以自動在/dev下生成設備節點,相對麻煩一點。而misc驅動則無需考慮這些,基本上只需要把一些基本信息通過struct miscdevice交給misc_register()去處理即可。

本質上misc驅動也是一個字符設備驅動,可能相對特殊一點而已。在drivers/char/misc.c的misc驅動初始化函數misc_init()中實際上使用了MISC_MAJOR(主設備號為10)并調用register_chrdev()去注冊了一個字符設備驅動。同時也創建了一個misc_class,使得最后可自動在/dev下自動生成一個主設備號為10的字符設備。總的來講,如果使用misc驅動可以滿足要求的話,那么這可以為開發人員剩下不少麻煩。

所以說misc驅動模型讓我們很簡單的在底層實現了字符設備驅動,并且在在應用層給予了一定的接口,節省了主設備號;其實就相當于一個雜貨鋪,亂七八糟的字符設備驅動模型都可以往里面

堆。

3:驅動模型代碼實現:
  misc驅動的實現代碼在driver/char/misc.c目錄下,

misc_init函數:

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

?

misc_init

  class_create 創建了一個名為misc的類

  register_chrdev(MISC_MAJOR,"misc",&misc_fops) ?使用register_chrdev注冊了一個字符設備驅動,主設備號為MISC_MAJOR(10);

static const struct file_operations misc_fops = {.owner = THIS_MODULE,.open = misc_open, };

misc類型驅動提供了一個統一.open函數misc_open函數;

misc_open 這個函數的實質是通過inode找到misc類的次設備號minor,然后在通過次設備號和misc鏈表的次設備號進行匹配,匹配好以后取出

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

?

?

在include/linux/miscdevice.h中定義了miscdevice ?結構體,所有的misc模型驅動設備;都在內核圍護的一個misc_list鏈表中;

內核維護一個misc_list鏈表,misc設備在misc_register注冊的時候鏈接到這個鏈表,在misc_deregister中解除鏈接。

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

?

misc_register函數

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_register

  misc->this_device = device_create(misc_class, misc->parent, dev,?misc, "%s", misc->name);

?調用這個函數來初創建設備;

?

misc_deregister函數來取消注冊;

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

?

4:代碼實戰:

拿一段x210_buzzer的代碼進行分析

module_init(dev_init);

module_exit(dev_exit);

看一下dev_init函數(首先初始化好dev_fops結構體、misc結構體)

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

?

這個函數中做了三件事:

  init_MUTEX ?     初始化信號量

  misc_register    注冊驅動

  gpio_request    申請gpio

這樣misc設備驅動已經寫好了,在補充一下具體fops中的硬件的操作方法即可;

--------------------------------------------------------------------------------------------------

三個函數分別為:x210_pwm_close、x210_pwm_open、x210_pwm_ioctl

x210_pwm_open,嘗試lock如果成功則返回0,表示可以使用,如果不成功則返回EBUSY

static int x210_pwm_open(struct inode *inode, struct file *file) {if (!down_trylock(&lock))return 0;elsereturn -EBUSY;}

?

x210_pwm_close,解鎖返回0

static int x210_pwm_close(struct inode *inode, struct file *file) {up(&lock);return 0; }

最關鍵的是x210_pwm_ioctl函數

這個函數是真正的提供給應用層操作buzzer的函數;

函數原型:

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

使用內核的ioctl函數可以對很多驅動程序的參數進行設置,如串口波特率、buzzer的頻率等等;

這個函數主要的兩個參數是:unsigned int, unsigned long

unsigned int傳的是cmd,unsigned long 傳的是參數;

當命令為PWM_IOCTL_SET_FREQ時,調用PWM_Set_Freq函數設置頻率

當命令為PWM_IOCTL_STOP時,調用PWM_Stop函數;

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; } void PWM_Stop( void ) {//將GPD0_2設置為inputs3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(0)); }

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

?

總結

以上是生活随笔為你收集整理的misc类设备的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。