misc裝置驅動模型及執行個體解析

來源:互聯網
上載者:User

1、misc裝置驅動模型

      本節我們來看一下misc裝置驅動模型的有關內容,首先是看看它的裝置結構體,定義在include/linux/miscdevice.h中:

struct miscdevice  {int minor;    //次裝置號,若為 MISC_DYNAMIC_MINOR 自動分配const char *name; //裝置名稱const struct file_operations *fops;//裝置檔案操作結構體struct list_head list;//misc_list鏈表頭struct device *parent;struct device *this_device;const char *nodename;mode_t mode;};

      結構體中的部分成員我們是一目瞭然的,主要是來看看有疑惑的幾點:

1、為什麼只有次裝置號呢?一個裝置不是有主、次裝置號嗎?

      其實,我想大家應該能夠想到了,此時沒有明確指定,那就說明應該是使用預設值。

2、主裝置號的預設值是多少呢?難道所有註冊為misc的裝置都有相同的主裝置號?怎麼區分各個裝置呢?

      這個主裝置號是10.的確,所有註冊為misc的裝置都有相同的主裝置號:10.在使用過程中我們主要是通過次裝置號來區分各個裝置。這一點不難理解,核心將所有註冊為misc的裝置都歸為一大類。

3、結構體中的list_head結構體類型的list成員的作用是什麼呢?

      核心自己會維護一個misc_list鏈表,所有註冊為misc的裝置都必須掛在這個鏈表上,這個list就是該鏈表的鏈表頭。

4、結構體中的兩個device結構體類型指標作用是什麼呢?

      作用就是建立裝置檔案,稍候就可以看到了!

5、我們如何定義自己的misc類型的裝置呢?

      可如下定義:

static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};

       其中的裝置檔案操作結構體和字元裝置類似,這裡就不再細講。

6、定義了自己的misc裝置,那麼我們如何向核心註冊/登出裝置呢?

     使用如下兩個函數:

int misc_register(struct miscdevice * misc);//在載入模組時會自動建立裝置檔案,是主裝置號為10的字元裝置int misc_deregister(struct miscdevice *misc);//在卸載模組時會自動刪除裝置檔案

      好了,至此,整個裝置驅動的流程就完了,接下來深入瞭解一下misc裝置模型的工作原理。

       首先看看misc初始化函數:

static int __init misc_init(void){int err;#ifdef CONFIG_PROC_FS/*如果使用proc檔案系統,則建立misc項*/proc_create("misc", 0, NULL, &misc_proc_fops);#endif/*在/sys/class/目錄下建立一個名為misc的類*/misc_class = class_create(THIS_MODULE, "misc");err = PTR_ERR(misc_class);if (IS_ERR(misc_class))goto fail_remove;err = -EIO;/*咦,怎麼misc裝置驅動調用字元驅動的註冊函數呢?裝置的主裝置號為MISC_MAJOR,為10*/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子系統*/  subsys_initcall(misc_init); 

        接下來看看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);/*遍曆已經註冊的misc,如果和當前準備註冊的相同(依據次裝置號來判斷),就返回裝置忙*/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);/*建立裝置檔案,這裡就是使用miscdevice結構體中兩個device類型指標的地方,  當然,這是和linux裝置驅動模型相關的*/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 */ /*到這一步也就註冊成功了,將新註冊的misc裝置加入到核心維護的misc_list鏈表中*/list_add(&misc->list, &misc_list); out:mutex_unlock(&misc_mtx);return err;}

登出函數:

int misc_deregister(struct miscdevice *misc){int i = DYNAMIC_MINORS - misc->minor - 1;if (WARN_ON(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;}

       到這裡,差不多misc裝置驅動模型就差不多了。

2、misc裝置驅動執行個體

      這裡貼一個簡單的misc裝置驅動程式,方便大家對照上面的理論部分進行分析,此驅動程式是友善之臂6410開發板的LED驅動程式,可以看看:

#include <linux/miscdevice.h>#include <linux/delay.h>#include <asm/irq.h>//#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/string.h>#include <linux/list.h>#include <linux/pci.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <asm/unistd.h>#include <mach/map.h>#include <mach/regs-clock.h>#include <mach/regs-gpio.h>#include <plat/gpio-cfg.h>#include <mach/gpio-bank-e.h>#include <mach/gpio-bank-k.h>#define DEVICE_NAME "leds"static long sbc2440_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){switch(cmd) {unsigned tmp;case 0:case 1:if (arg > 4) {return -EINVAL;}tmp = readl(S3C64XX_GPKDAT);tmp &= ~(1 << (4 + arg));tmp |= ( (!cmd) << (4 + arg) );writel(tmp, S3C64XX_GPKDAT);return 0;default:return -EINVAL;}}static struct file_operations dev_fops = {.owner= THIS_MODULE,.unlocked_ioctl= sbc2440_leds_ioctl,};static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};static int __init dev_init(void){int ret;{unsigned tmp;tmp = readl(S3C64XX_GPKCON);tmp = (tmp & ~(0xffffU<<16))|(0x1111U<<16);writel(tmp, S3C64XX_GPKCON);tmp = readl(S3C64XX_GPKDAT);tmp |= (0xF << 4);writel(tmp, S3C64XX_GPKDAT);}ret = misc_register(&misc);printk (DEVICE_NAME"\tinitialized\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("FriendlyARM Inc.");

      好了,今天就到此結束,呵呵!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.