1. 程式人生 > >linux 字元裝置和misc裝置

linux 字元裝置和misc裝置

字元裝置

2.6版本前使用的結構體和函式

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp">typedef __kernel_dev_t      dev_t;//字元裝置的裝置號  
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)//註冊字元裝置到核心中,疑問1  
static inline void unregister_chrdev(unsigned int major, const char *name)//登出字元裝置  
MAJOR(dev_t dev)//計算主裝置號  
MINOR(dev_t dev)//計算次裝置號  
MKDEV(int major,int minor)//根據major和minor算得dev_t  
struct file_operations{  
.....  
} 
在使用以上函式註冊字元裝置的時候比較簡單,拿misc的實現函式舉例,已知了dev_t的主裝置號,所以可以直接呼叫register_chrdev將該設備註冊到核心中。  
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");//dev下建立misc類,後面在具體裝置進行misc_register是再執行device_creat註冊具體的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;
}

2.6版本後使用的結構體和函式

dev_t;//字元裝置的裝置號  
MAJOR(dev_t dev)//計算主裝置號  
MINOR(dev_t dev)//計算次裝置號  
MKDEV(int major,int minor)//根據major和minor算得dev_t  
struct cdev {      //新增了cdev結構體,可以看到cdev除了包含了dev_t成員,還有kobj相關成員,2.6正是引入了kobj模型  
struct kobject kobj;  
struct module *owner;  
const struct file_operations *ops;  
struct list_head list;  
dev_t dev;  
unsigned int count;  
};  
void cdev_init(struct cdev *, const struct file_operations *);//初始化cdev,主要是賦值cdev的ops成員  
struct cdev *cdev_alloc(void);//動態分配一個cdev結構體,此時是程式中只定義了一個cdev指標的時候使用,如果定義了一個cdev結構體,使用cdev_init  
void cdev_put(struct cdev *p);//釋放alloc的cdev  
int cdev_add(struct cdev *, dev_t, unsigned);//向系統註冊字元裝置  
void cdev_del(struct cdev *);  
extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const charchar *);//動態向系統申請裝置號<span style="font-family: Arial, Helvetica, sans-serif;">dev_t</span>  
extern int register_chrdev_region(dev_t, unsigned, const charchar *);//已知dev_t時靜態申請  
struct file_operations{  
.....  
}  
可以看出2.6以後的版本在註冊字元裝置時稍複雜些,還是舉個例子,可以看到在2.6以後的版本中註冊字元裝置的過程是:申請裝置號dev_t->cdev初始化->註冊cdev到系統中,對比2.6以前的版本多了針對cdev的操作過程。
static int __init pc8736x_gpio_init(void)  
{  
    int rc;  
    dev_t devid;  
  
......  
    if (major) {  
        devid = MKDEV(major, 0);  
        rc = register_chrdev_region(devid, PC8736X_GPIO_CT, DEVNAME);  
    } else {  
        rc = alloc_chrdev_region(&devid, 0, PC8736X_GPIO_CT, DEVNAME);  
        major = MAJOR(devid);  
    }  
  
    if (rc < 0) {  
        dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc);  
        goto undo_request_region;  
    }  
    if (!major) {  
        major = rc;  
        dev_dbg(&pdev->dev, "got dynamic major %d\n", major);  
    }  
  
    pc8736x_init_shadow();  
  
    /* ignore minor errs, and succeed */  
    cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops);  
    cdev_add(&pc8736x_gpio_cdev, devid, PC8736X_GPIO_CT);  
  
    return 0;  
  
undo_request_region:  
    release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE);  
undo_platform_dev_add:  
    platform_device_del(pdev);  
undo_platform_dev_alloc:  
    platform_device_put(pdev);  
  
    return rc;  
}

misc裝置

misc使用的結構體和函式

misc裝置其實也是字元裝置,主不過misc裝置驅動在字元裝置的基礎上又進行了一次封裝,使使用者可以更方便的使用。

struct miscdevice  {  
    int minor;  
    const charchar *name;  
    const struct file_operations *fops;//還是字元裝置中的檔案操作結構體,只不過misc結構體對其又封裝了一次  
    struct list_head list;  
    struct device *parent;  
    struct device *this_device;  
    const charchar *nodename;  
    mode_t mode;  
};  
int misc_register(struct miscdevice * misc)  
還是舉個例子來看下,使用者在註冊misc裝置的時候只需要:初始化file_operations結構體->初始化miscdevice結構體->呼叫misc_register將miscdevice註冊到系統中就ok了。  
static const struct file_operations mmtimer_fops = {  
.owner = THIS_MODULE,  
.mmap =mmtimer_mmap,  
.unlocked_ioctl = mmtimer_ioctl,  
.llseek = noop_llseek,  
};  
static struct miscdevice mmtimer_miscdev = {  
SGI_MMTIMER,  
MMTIMER_NAME,  
&mmtimer_fops  
};  
static int __init mmtimer_init(void)  
{  
    cnodeid_t node, maxn = -1;  
  
......  
    if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, IRQF_PERCPU, MMTIMER_NAME, NULL)) {  
        printk(KERN_WARNING "%s: unable to allocate interrupt.",  
            MMTIMER_NAME);  
        goto out1;  
    }  
  
    if (misc_register(&mmtimer_miscdev)){  
        printk(KERN_ERR "%s: failed to register device\n",  
               MMTIMER_NAME);  
        goto out2;  
    }  
......  
  
    return 0;  
  
out3:  
    kfree(timers);  
    misc_deregister(&mmtimer_miscdev);  
out2:  
    free_irq(SGI_MMTIMER_VECTOR, NULL);  
out1:  
    return -1;  
}  
那麼到了這裡就會有疑問,為什麼linux還費勁的又造了一個misc裝置呢?為什麼不直接都使用字元裝置驅動呢?
為什麼要有misc裝置
首先的好處就是方便,快捷,使用者可以只初始化2個結構體,然後呼叫一個函式就可以建立一個misc裝置了,本質上來說他也是個字元裝置。
還有應該就是註冊misc裝置節約了主裝置號的佔用,linux中只提供了256個主裝置號,本身核心中一些驅動已經佔用了部分,試想如果有一大波裝置都想以字元設備註冊進核心,必然導致主裝置號不夠用的情況,而misc裝置在初始化時佔用主裝置號10,當裝置驅動以misc設備註冊進核心的時候,只為其分配次裝置號,主裝置號不變。
為什麼要有misc裝置的觀點從知乎上看來的,自己思考了下,總結下來,後面如果再想到會繼續新增。


疑問1:該函式在fs.h中宣告為static inline,靜態的行內函數,既然是靜態的,不是應該不能被其他檔案內的函式呼叫?
其實該函式宣告在.h檔案中,那麼,只要c檔案包含了該標頭檔案就可以呼叫了,也就是說在編譯時,呼叫該函式的地方會被編譯器將實際程式碼直接展開在該c檔案中,那麼在該c檔案中該函式是static的,其他c檔案沒包含該標頭檔案的是不可以使用該函式的。

相關推薦

linux 字元裝置misc裝置

字元裝置 2.6版本前使用的結構體和函式 <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span>&l

Linux系統中/dev/mtd與/dev/mtdblock的區別,即MTD字元裝置裝置的區別

1. /dev/mtdN 是Linux 中的MTD架構中,系統自己實現的mtd分割槽所對應的字元裝置,其裡面添加了一些ioctl,支援很多命令,如MEMGETINFO,MEMERASE等。 而mtd-util中的flash_eraseall等工具,就是以這些ioctl為基礎而

[Linux]字元裝置裝置的區別

前言: 最根本區別在於它們是否可以被隨機訪問,字元裝置可以不定長度依循先後順序存取資料;塊裝置可以隨機存取。 裝置檔案分為Block Device Driver和Character Device Drive兩類。Character Device Drive又被稱為字元裝

linux主裝置號裝置

    Linux的裝置管理是和檔案系統緊密結合的,把裝置和檔案關聯起來,這樣系統呼叫可以直接用操作檔案一樣的方法來操作裝置。各種裝置都以檔案的形式存放在/dev目錄下,稱為裝置檔案。應用程式可以開啟、關閉和讀寫這些裝置檔案,完成對裝置的操作,就像操作普通的資料檔案一樣。為了管理這些裝置,系統為裝置編了號,每

字元裝置 input 裝置--input裝置的註冊

5.2input裝置的註冊   input是一個虛擬的裝置,在Linux系統中,鍵盤、滑鼠、觸控式螢幕 和 遊戲杆 都要由input裝置統一管理。   input裝置是個字元裝置,如何註冊裝置驅動,要 從input裝置的初始化函式input_init開始。 5.2.1主從裝

misc裝置i2c裝置建立的節點路徑

misc裝置: ./sys/class/misc/sim_i2c_port/sim_i2c_addr ./sys/devices/virtual/misc/sim_i2c_port/sim_i2c_a

PTN裝置SDH裝置有什麼區別?可以互通嗎?

從字面上解釋,PTN叫做packet translate network(包傳送網),而SDH叫做同步數字體系。 從傳輸單元上看,PTN傳送的最小單元是IP報文,而SDH傳輸的是時隙,最小單元是E1即2M電路。PTN的報文大小有彈性,而SDH的電路頻寬是固定的。這就是PTN

linux字元介面圖形介面切換方法

1、硬碟安裝的linux,在系統圖形介面啟動後,可使用Ctrl+Alt+F1~6切換到字元介面,再用Ctrl+Alt+F7切換到圖形介面。 對於使用虛擬機器安裝的linux,由於虛擬機器遮蔽了Ctrl+Alt鍵,必須使用其他熱鍵:Ctrl+Alt+shift+F1~6切換

Anroid BLE藍芽(手機分別作為中心裝置外圍裝置

        藍芽是一種短距的無線通訊技術,可實現固定裝置、移動裝置之間的資料交換。一般將藍芽3.0之前的BR/EDR藍芽稱為傳統藍芽,而將藍芽4.0規範下的LE藍芽稱為低功耗藍芽。BLE藍芽模組主要應用領域    1、移動擴充套件裝置    2、汽車電子裝置    3、健

linux註冊字元裝置解除安裝字元裝置函式

註冊一個字元裝置的方法是使用: int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); 這裡, major 是感興趣的主編號, name 是驅動的名

Linux字元裝置驅動模型--字元裝置的註冊

當我們編寫字元裝置驅動程式的時候,在進行字元裝置物件cdev的分配、初始化,裝置號的註冊這些初始化階段之後,就可以將它加入到系統中,這樣才能使用這個字元裝置。將一個字元裝置加入到系統中呼叫的函式時cdev_add,核心原始碼如下: int cdev_add(struct cdev *

Linux 字元裝置驅動結構(二)—— 自動建立裝置節點

      上一篇我們介紹到建立裝置檔案的方法,利用cat /proc/devices檢視申請到的裝置名,裝置號。 第一種是使用mknod手工建立:mknod filename type major minor 第二種是自動建立裝置節點:利用u

Linux 字元裝置驅動結構(一)—— cdev 結構體、裝置號相關知識解析

一、字元裝置基礎知識 1、裝置驅動分類       linux系統將裝置分為3類:字元裝置、塊裝置、網路裝置。使用驅動程式: 字元裝置:是指只能一個位元組一個位元組讀寫的裝置,不能隨機讀取裝置記憶體中的某一資料,讀取資料需要按照先後資料。

linux 字元裝置框架使用 初級

#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/cdev.h

Linux字元裝置驅動註冊三種方法以及核心分析

       Linux驅動是使用者訪問底層硬體的橋樑,驅動有可以簡單分成三類:字元裝置、塊裝置、網路裝置。其中最多的是字元裝置,其中字元裝置的註冊方法主要有三種:雜項設備註冊、早期字元設備註冊、標準字元設備註冊。以及詳細介紹各類方法註冊。 開發環境: PC:WMwork

linux字元裝置驅動模型

一.雜項裝置驅動模型 雜項的主裝置號固定為10,只有255個次裝置號。可以直接生成驅動核心。 1.需要確定每個模型都會用到的檔案操作方法集合指標 2.確定核心的結構體 static struct miscdevice abc 確定三個引數,第一個為次裝置號,第二個是次裝

Linux下SPIIIC驅動免在裝置樹上新增裝置資訊的編寫方法

      編寫i2c或spi驅動時,一般需要往裝置樹上(或者板級檔案)新增節點資訊,這裡提供一種直接在驅動中新增裝置資訊的方法,使驅動更方便移植。 i2c的驅動模板如下 #include <linux/module.h> #include <linux

Linux驅動開發04:塊裝置驅動網路裝置驅動

介紹 因為塊裝置驅動和網路裝置驅動實際中用得較少,所以只給出驅動模板,我也沒有具體測試,等到實際用到是再研究吧,溜了溜了。 塊裝置驅動模板 struct xxx_dev { int size; struct request_q

Linux字元裝置中的兩個重要結構體(file、inode)

對於Linux系統中,一般字元裝置和驅動之間的函式呼叫關係如下圖所示 上圖描述了使用者空間應用程式通過系統呼叫來呼叫程式的過程。一般而言在驅動程式的設計中,會關係 struct file 和 struct inode 這兩個結構體。 使用者空間使用open()系統呼叫函式開啟一個字元裝置時( int fd

Linux字元裝置驅動

一、字元裝置基礎 字元裝置:是指只能一個位元組一個位元組進行讀寫操作的裝置,不能隨機讀取裝置中的某一資料、讀取資料要按照先後資料。字元裝置是面向流的裝置,常見的字元裝置有滑鼠、鍵盤、串列埠、控制檯和LED等。 一般每個字元裝置或者塊裝置都會在/dev目錄(可以是任意目錄,這樣是為了統一)下對應一個裝置檔案