linux 字元裝置和misc裝置
字元裝置
2.6版本前使用的結構體和函式
在使用以上函式註冊字元裝置的時候比較簡單,拿misc的實現函式舉例,已知了dev_t的主裝置號,所以可以直接呼叫register_chrdev將該設備註冊到核心中。<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{ ..... }
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版本後使用的結構體和函式
可以看出2.6以後的版本在註冊字元裝置時稍複雜些,還是舉個例子,可以看到在2.6以後的版本中註冊字元裝置的過程是:申請裝置號dev_t->cdev初始化->註冊cdev到系統中,對比2.6以前的版本多了針對cdev的操作過程。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{ ..... }
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下SPI和IIC驅動免在裝置樹上新增裝置資訊的編寫方法
編寫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目錄(可以是任意目錄,這樣是為了統一)下對應一個裝置檔案