深入理解Linux字元裝置驅動
文章從上層應用訪問字元裝置驅動開始,一步步地深入分析Linux字元裝置的軟體層次、組成框架和互動、如何編寫驅動、裝置檔案的建立和mdev原理,對Linux字元裝置驅動有全面的講解。
本文整合之前發表的《Linux字元裝置驅動剖析》和《 Linux 裝置檔案的建立和mdev》兩篇文章,基於linux字元裝置驅動的所有相關知識給讀者一個完整的呈現。
一、從最簡單的應用程式入手
1.很簡單,open裝置檔案,read、write、ioctl,最後close退出。如下:
二、/dev目錄與檔案系統
2. /dev是根檔案系統下的一個目錄檔案,/代表根目錄,其掛載的是根檔案系統的yaffs格式,通過讀取/根目錄這個檔案,就能分析list出其包含的各個目錄,其中就包括dev這個子目錄。即在/根目錄(也是一個檔案,其真實存在於flash介質)中有一項這樣的資料:
是否目錄 偏移 大小 名稱 -- --
1 0xYYYY 0Xmmm dev -- --
Ls/ 命令即會使用/掛載的yaffs檔案系統來讀取出根目錄檔案的內容,然後list出dev(是一個目錄)。即這時還不需要去讀取dev這個目錄檔案的內容。Cd dev即會分析dev掛載的檔案系統的超級塊的資訊,superblock,而不再理會在flash中的dev目錄檔案的資料。
3. /dev在根檔案系統構建的時候會掛載為tmpfs. Tmpfs是一個基於虛擬記憶體的檔案系統,主要使用RAM和SWAP(Ramfs只是使用實體記憶體)。即以後讀寫dev這個目錄的操作都轉到tmpfs的操作,確切地講都是針對RAM的操作,而不再是通過yaffs檔案系統的讀寫函式去訪問flash介質。Tmpfs基於RAM,所以在掉電後回消失。因此/dev目錄下的裝置檔案都是每次linux啟動後建立的。
掛載過程:/etc/init.d/rcS
Mount –a 會讀取/etc/fstab的內容來掛載,其內容如下:
4. /dev/NULL和/dev/console是在製作根檔案系統的時候靜態建立的,其他裝置檔案都是系統載入根檔案系統和各種驅動初始化過程中自動建立的,當然也可以通過命令列手動mknod裝置檔案。
三、裝置檔案的建立
5. /dev目錄下的裝置檔案基本上都是通過mdev來動態建立的。mdev是一個使用者態的應用程式,位於busybox工具箱中。其建立過程包括:
1) 驅動初始化或者匯流排匹配後會呼叫驅動的probe介面,該介面會呼叫device_create(裝置類, 裝置號, 裝置名);在/sys/class/裝置類目錄生成唯一的裝置屬性檔案(包括裝置號和裝置名等資訊),並且傳送uvent事件(KOBJ_ADD和環境變數,如路徑等資訊)到使用者空間(通過socket方式)。
2) mdev是一個work_thread執行緒,收到事件後會分析出/sys/class/裝置類的對應檔案,最終呼叫mknod動態來建立裝置檔案,而這個裝置檔案內容主要是裝置號(這個裝置檔案對應的inode會記錄檔案的屬性是一個裝置(其他屬性還包括目錄,一般檔案,符號連結等))。應用程式open(device_name,…)最重要的一步就是通過檔案系統介面來獲得該裝置檔案的內容—裝置號。
6. 如果初始化過程中沒有呼叫device_create介面來建立裝置檔案,則需要手動通過命令列呼叫mknod介面來建立裝置檔案,方可在應用程式中訪問。
7. mknod介面分析,通過系統呼叫後對應呼叫sys_mknod,其是vfs層的介面。
Sys_mknod(裝置名, 裝置號)
vfs通過逐一路徑link_path_walk,分析出dev掛載了tmpfs,所以呼叫tmpfs->mknod
shmem_mknod(structinode *dir, struct dentry *dentry, int mode, dev_t dev)
inode = shmem_get_inode(dir->i_sb,dir, mode, dev, VM_NORESERVE);
inode = new_inode(sb);
switch (mode & S_IFMT) {
default:
inode->i_op =&shmem_special_inode_operations;
init_special_inode(inode,mode, dev);//以下是函式展開
break;
case S_IFREG://file
case S_IFDIR://DIR
case S_IFLNK://dentry填入inode資訊,這時對應的dentry和inode都已經存在於記憶體中。
d_instantiate(dentry, inode);
可見,tmpfs的目錄和檔案都是像ramfs一樣一般都存在於記憶體中。通過ls命令來獲取目錄的資訊則由dentry資料結構的內容來獲取,而檔案的資訊由inode資料結構的內容來提供。Inode包括裝置檔案的裝置號i_rdev,檔案屬性(i_mode: S_ISCHR),inode操作集i_fop(對於裝置檔案來說就是如何open這個inode)。
四、open裝置檔案
9. open裝置檔案的最終目的是為了獲取到該裝置驅動的file_operations操作集,而該介面集是struct file的成員,open返回file資料結構指標:
struct file {
conststruct file_operations *f_op;
unsignedint f_flags;//可讀,可寫等
…
};
以下是led裝置驅動的操作介面。open("/dev/LED",O_RDWR)就是為了獲得led_fops。
static conststruct file_operations led_fops = {
.owner =THIS_MODULE,
.open =led_open,
.write = led_write,
};
10. 仔細看應用程式int fd =open("/dev/LED",O_RDWR),open的返回值是int,並不是file,其實是為了作業系統和安全考慮。fd位於應用層,而file位於核心層,它們都同屬程序相關概念。在Linux中,同一個檔案(對應於唯一的inode)可以被不同的程序開啟多次,而每次開啟都會獲得file資料結構。而每個程序都會維護一個已經開啟的file陣列,fd就是對應file結構的陣列下標。因此,file和fd在程序範圍內是一一對應的關係。
11. open介面分析,通過系統呼叫後對應呼叫sys_open,其是vfs層的介面
Sys_open(/dev/led)
SYSCALL_DEFINE3(open,const char __user *, filename, int, flags, int, mode)
do_sys_open(AT_FDCWD,/dev/tty, flags, mode);
//path_init返回時nd->dentry即為搜尋路徑檔名的起點
//link_path_walk一步步建立開啟路徑的各個目錄的dentry和inode
其中inode->i_fop在mknod的init_special_inode呼叫中被賦值為def_chr_fops。以下該變數的定義,因此, open(inode, f)即呼叫到chrdev_open。其可以看出是字元裝置所對應的檔案系統介面,我們姑且稱其為字元裝置檔案系統。
conststruct file_operations def_chr_fops = {
.open = chrdev_open,
};
繼續分析chrdev_open:
Kobj_lookup(cdev_map,inode->i_rdev, &idx)即是通過裝置的裝置號(inode->i_rdev)在cdev_map中查詢裝置對應的操作集file_operations.關於如何查詢,我們在理解字元裝置驅動如何註冊自己的file_operations後再回頭來分析這個問題。
五、字元裝置驅動的註冊
12. 字元裝置對應cdev資料結構:
struct cdev {
struct kobject kobj; // 每個 cdev 都是一個 kobject
struct module*owner; // 指向實現驅動的模組
const structfile_operations *ops; // 操縱這個字元裝置檔案的方法
struct list_headlist; //對應的字元裝置檔案的inode->i_devices 的連結串列頭
dev_t dev; // 起始裝置編號
unsigned intcount; // 裝置範圍號大小
};
13. led裝置驅動初始化和裝置驅動註冊
1) cdev_init是初始化cdev結構體,並將led_fops填入該結構。
2) cdev_add
3) cdev_map是一個全家指標變數,型別如下:
4) kobj_map使用hash散列表來儲存cdev資料結構。通過註冊裝置的主裝置號major來獲得cdev_map->probes陣列的索引值i(i = major % 255),然後把一個型別為struct probe的節點物件加入到probes[i]所管理的連結串列中,probes[i]->data即是cdev資料結構,而probes[i]->dev和range代表字元裝置號和範圍。
六、再述open裝置檔案
14. 通過第五步的字元裝置的註冊過程,應該對Kobj_lookup查詢led_ops是很容易理解的。至此,已經獲得led裝置驅動的led_ops。接著立刻呼叫file->f_ops->open即呼叫了led_open,在該函式中會對led用到的GPIO進行ioremap並設定GPIO方向、上下拉等硬體初始化。
15. 最後,chrdev_open一步步返回,最後到
do_sys_open的struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);返回。
Fd_install(fd, f)即是在當前程序中將存有led_ops的file指標填入程序的file陣列中,下標是fd。最後將fd返回給使用者空間。而使用者空間只要傳入fd即可找到對應的file資料結構。
七、裝置操作
16. 這裡以裝置寫為例,主要是控制led的亮和滅。
write(fd,val,1)系統呼叫後對應sys_write,其對應所有的檔案寫,包括目錄、一般檔案和裝置檔案,一般檔案有位置偏移的概念,即讀寫之後,當前位置會發生變化,所以如要跳著讀寫,就需要fseek。對於字元裝置檔案,沒有位置的概念。所以我們重點跟蹤vfs_write的過程。
1) fget_light在當前程序中通過fd來獲得file指標
2) vfs_write
3) 對於led裝置,file->f_op->write即是led_write。
在該介面中實現對led裝置的控制。
八、再論字元裝置驅動的初始化
綜上所述,字元裝置的初始化包括兩個主要環節:
1) 字元裝置驅動的註冊,即通過cdev_add向系統註冊cdev資料結構,提供file_operations操作集和裝置號等資訊,最終file_operations存放在全域性指標變數cdev_map指向的Hash表中,其可以通過裝置號索引並遍歷得到。
2) 通過device_create(裝置類, 裝置號, 裝置名)在sys/class/裝置類中建立裝置屬性檔案併發送uevent事件,而mdev利用該資訊自動呼叫mknod在/dev目錄下建立對應的裝置檔案,以便應用程式訪問。
那麼如何通過通過device_create來建立裝置檔案呢,mdev的原理又是什麼呢?我們接著分析。
九、裝置類相關知識
裝置類是虛擬的,並沒有直接對應的物理實物,只是為了更好地管理同一類裝置匯出到使用者空間而產生的目錄和檔案。整個過程涉及到sysfs檔案系統,該檔案系統是為了展示linux裝置驅動模型而構建的檔案系統,是基於ramfs,linux根目錄中的/sysfs即掛載了sysfs檔案系統。
Struct kobject資料結構是sysfs的基礎,kobject在sysfs中代表一個目錄,而linux的驅動(struct driver)、裝置(struct device)、裝置類(struct class)均是從kobject進行派生的,因此他們在sysfs中都對應於一個目錄。而資料結構中附屬的struct device_attribute、driver_attribute、class_attribute等屬性資料結構在sysfs中則代表一個普通的檔案。
Struct kset是struct kobject的容器,即Struct kset可以成為同一類struct kobject的父親,而其自身也有kobject成員,因此其又可能和其他kobject成為上一級kset的子成員。
十、兩種建立裝置檔案的方式
在裝置驅動中cdev_add將struct file_operations和裝置號註冊到系統後,為了能夠自動產生驅動對應的裝置檔案,需要呼叫class_create和device_create,並通過uevent機制呼叫mdev(嵌入式linux由busybox提供)來呼叫mknod建立裝置檔案。當然也可以不呼叫這兩個介面,那就手工通過命令列mknod來建立裝置檔案。
十一、裝置類和裝置相關資料結構
1. include/linux/kobject.h
struct kobject {
constchar *name;//名稱
structlist_head entry;//kobject連結串列
structkobject *parent;//即所屬kset的kobject
structkset *kset;//所屬kset
structkobj_type *ktype;//屬性操作介面
…
};
struct kset {
struct list_head list;//管理同屬於kset的kobject
struct kobject kobj;//可以成為上一級父kset的子目錄
const struct kset_uevent_ops *uevent_ops;//uevent處理介面
};
假設Kobject A代表一個目錄,kset B代表幾個目錄(包括A)的共同的父目錄。
則A.kset=B; A.parent=B.kobj.
2.include/linux/device.h
struct class {//裝置類
const char *name;//裝置類名稱
struct module *owner;//建立裝置類的module
structclass_attribute *class_attrs;//裝置類屬性
struct device_attribute *dev_attrs;//裝置屬性
struct kobject *dev_kobj;//kobject再sysfs中代表一個目錄
….
struct class_private *p;//裝置類得以註冊到系統的連線件
};
3.drivers/base/base.h
struct class_private {
//該裝置類同樣是一個kset ,包含下面的class_devices;同時在class_subsys填充父kset
struct kset class_subsys;
structklist class_devices;//裝置類包含的裝置(kobject)
…
structclass *class;//指向裝置類資料結構,即要建立的本級目錄資訊
};
4.include/linux/device.h
structdevice {//裝置
structdevice *parent;//sysfs/devices/中的父裝置
structdevice_private *p;//裝置得以註冊到系統的連線件
structkobject kobj;//裝置目錄
constchar *init_name;//裝置名稱
structbus_type *bus;//裝置所屬匯流排
structdevice_driver *driver; //裝置使用的驅動
structklist_node knode_class;//連線到裝置類的klist
structclass *class;//所屬裝置類
conststruct attribute_group **groups;
…
}
5. drivers/base/base.h
struct device_private {
structklist klist_children;//連線子裝置
structklist_node knode_parent;//加入到父裝置連結串列
structklist_node knode_driver;//加入到驅動的裝置連結串列
structklist_node knode_bus;//加入到匯流排的連結串列
structdevice *device;//對應裝置結構
};
6. 解釋
class_private是class的私有結構,class通過class_private註冊到系統中;device_private是device的私有結構,device通過device_private註冊到系統中。註冊到系統中也是將相應的資料結構加入到系統已經存在的連結串列中,但是這些連結的細節並不希望暴露給使用者,也沒有必要暴露出來,所以才有private的結構。而class和device則通過sysfs向用戶層提供資訊。
十二、建立裝置類目錄檔案
1. 在驅動通過cdev_add將struct file_operations介面集和設備註冊到系統後,即利用class_create介面來建立裝置類目錄檔案。
led_class = class_create(THIS_MODULE,"led_class");
__class_create(owner, name,&__key);
cls->name = name;//裝置類名
cls->owner= owner;//所屬module
retval =__class_register(cls, key);
structclass_private *cp;
//將類的名字led_class賦值給對應的kset
kobject_set_name(&cp->class_subsys.kobj,"%s", cls->name);
// 填充class_subsys所屬的父kset:ket:sysfs/class.
cp->class_subsys.kobj.kset= class_kset;
//填充class屬性操作介面
cp->class_subsys.kobj.ktype= &class_ktype;
cp->class = cls;//通過cp可以找到class
cls->p = cp;//通過class可以找到cp
//建立led_class裝置類目錄
kset_register(&cp->class_subsys);
//在led_class目錄建立class屬性檔案
add_class_attrs(class_get(cls));
2. 繼續展開kset_register
kset_register(&cp->class_subsys);
kobject_add_internal(&k->kobj);
// parent即class_kset.kobj, 即/sysfs/class對應的目錄
parent =kobject_get(kobj->parent);
create_dir(kobj);
//建立一個led _class裝置類目錄
sysfs_create_dir(kobj);
該介面是sysfs檔案系統介面,代表建立一個目錄,不再展開。
3. 上述提到的class_kset 在class_init被建立
class_kset= kset_create_and_add("class", NULL, NULL);
第三個傳參為NULL,代表預設在/sysfs/建立class目錄。
十三、建立裝置目錄和裝置屬性檔案
1.利用class_create介面來建立裝置類目錄檔案後,再利用device_create介面來建立具體裝置目錄和裝置屬性檔案。
led_device =device_create(led_class, NULL, led_devno, NULL, "led");
device_create_vargs
dev->devt = devt;//裝置號
dev->class= class;//裝置類led_class
dev->parent =parent;//父裝置,這裡是NULL
kobject_set_name_vargs(&dev->kobj,fmt, args)//裝置名”led”
device_register(dev)註冊裝置
2. 繼續展開device_register(dev)
device_initialize(dev);
dev->kobj.kset= devices_kset;//裝置所屬/sysfs/devices/
device_add(dev)
device_private_init(dev)//初始化device_private
dev_set_name(dev,"%s", dev->init_name);//賦值dev->kobject的名稱
setup_parent(dev,parent);//建立device和父裝置的kobject的聯絡
//kobject_add在/sysfs/devices/目錄下建立裝置目錄led,kobject_add是和kset_register相似的介面,只不過前者針對kobject,後者針對kset。
kobject_add(&dev->kobj,dev->kobj.parent, NULL);
kobject_add_varg
kobj->parent= parent;
kobject_add_internal(kobj)
create_dir(kobj);//建立裝置目錄
//在剛建立的/sysfs/devices/led目錄下建立uevent屬性檔案,名稱是”uevent”
device_create_file(dev,&uevent_attr);
//在剛建立的/sysfs/devices/led目錄下建立dev屬性檔案,名稱是”dev”,該屬性檔案的內容就是裝置號
device_create_file(dev,&devt_attr);
//在/sysfs/class/led_class/目錄下建立led裝置的符號連線,所以開啟/sysfs/class/led_class/led/目錄也能看到dev屬性檔案,讀出裝置號。
device_add_class_symlinks(dev);
//建立device屬性檔案,包括裝置所屬匯流排的屬性和attribute_group屬性
device_add_attrs()
bus_add_device(dev)//將裝置加入匯流排
//觸發uevent機制,並通過呼叫mdev來建立裝置檔案。
kobject_uevent(&dev->kobj,KOBJ_ADD);
//匹配裝置和匯流排的驅動,匹配成功就呼叫驅動的probe介面,不再展開
bus_probe_device(dev);
3. 展開kobject_uevent(&dev->kobj, KOBJ_ADD);
kobject_uevent_env(kobj,action, NULL);
kset= top_kobj->kset;
uevent_ops = kset->uevent_ops; //即device_uevent_ops
//subsystem即裝置所屬的裝置類的名稱”led_class”
subsystem= uevent_ops->name(kset, kobj);
//devpath即/sysfs/devices/led/
devpath= kobject_get_path(kobj, GFP_KERNEL);
//新增各種環境變數
add_uevent_var(env,"ACTION=%s", action_string);
add_uevent_var(env,"DEVPATH=%s", devpath);
add_uevent_var(env,"SUBSYSTEM=%s", subsystem);
uevent_ops->uevent(kset,kobj, env);
add_uevent_var(env,"MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env,"MINOR=%u", MINOR(dev->devt));
add_uevent_var(env,"DEVNAME=%s", name);
add_uevent_var(env,"DEVTYPE=%s", dev->type->name);
//還會增加匯流排相關的一些屬性環境變數等等。
#ifdefined(CONFIG_NET)//如果是PC的linux會通過socket的方式嚮應用層傳送uevent事件訊息,但在嵌入式linux中不啟用該機制。
#endif
argv [0] = uevent_helper;//即/sbin/mdev
argv [1] = (char *)subsystem;//”led_class”
argv [2] = NULL;
add_uevent_var(env,"HOME=/");
add_uevent_var(env,
"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
call_usermodehelper(argv[0], argv,
env->envp, UMH_WAIT_EXEC);
4. 上述提到的devices_kset在devices_init被建立
devices_kset= kset_create_and_add("devices", &device_uevent_ops, NULL);
第三個傳參為NULL,代表預設在/sysfs/建立devices目錄
5. 上述裝置屬性檔案
staticstruct device_attribute devt_attr =
__ATTR(dev, S_IRUGO, show_dev, NULL);
static ssize_t show_dev(struct device*dev, struct device_attribute *attr,
char *buf){{
returnprint_dev_t(buf, dev->devt); //即返回裝置的裝置號
}
6.devices裝置目錄響應uevent事件的操作
staticconst struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
};
7.call_usermodehelper是從核心空間呼叫使用者空間程式的介面。
8. 對於嵌入式系統來說,busybox採用的是mdev,在系統啟動指令碼rcS 中會使用命令
echo /sbin/mdev >/proc/sys/kernel/hotplug
uevent_helper[]陣列即讀入/proc/sys/kernel/hotplug檔案的內容,即 “/sbin/mdev”
十四、建立裝置檔案
輪到mdev出場了,以上描述都是在sysfs檔案系統中建立目錄或者檔案,而應用程式訪問的裝置檔案則需要建立在/dev/目錄下。該項工作由mdev完成。
Mdev的原理是解釋/etc/mdev.conf檔案定義的命名裝置檔案的規則,並在該規則下根據環境變數的要求來建立裝置檔案。Mdev.conf由使用者層指定,因此更具靈活性。本文無意展開對mdev配置指令碼的分析。
Busybox/util-linux/mdev.c
int mdev_main(int argc UNUSED_PARAM, char**argv)
xchdir("/dev");
if (argv[1] &&strcmp(argv[1], "-s")//系統啟動時mdev –s才會執行這個分支
else
action= getenv("ACTION");
env_path= getenv("DEVPATH");
G.subsystem= getenv("SUBSYSTEM");
snprintf(temp, PATH_MAX,"/sys%s", env_path);//到/sysfs/devices/led目錄
make_device(temp,/*delete:*/ 0);
strcpy(dev_maj_min,"/dev");
//讀出dev屬性檔案,得到裝置號
open_read_close(path,dev_maj_min + 1, 64);
….
mknod(node_name,rule->mode | type, makedev(major, minor))
最終我們會跟蹤到mknod在/dev/目錄下建立了裝置檔案。
我們追求:
1.從上電第一行程式碼、系統第一行程式碼、模組第一行程式碼、應用第一行程式碼,深入講解嵌入式軟體生命週期。
2 深刻理解硬體體系,以面向物件思維剖析各種匯流排和驅動框架。
3 聚焦軟體層次設計和框架設計
4 知其然,知其所以然
更多的嵌入式linux和android、物聯網、汽車自動駕駛等領域原創技術分享請關注微信公眾號:
相關推薦
深入理解Linux字元裝置驅動
文章從上層應用訪問字元裝置驅動開始,一步步地深入分析Linux字元裝置的軟體層次、組成框架和互動、如何編寫驅動、裝置檔案的建立和mdev原理,對Linux字元裝置驅動有全面的講解。本文整合之前發表的《L
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字元裝置驅動註冊三種方法以及核心分析
Linux驅動是使用者訪問底層硬體的橋樑,驅動有可以簡單分成三類:字元裝置、塊裝置、網路裝置。其中最多的是字元裝置,其中字元裝置的註冊方法主要有三種:雜項設備註冊、早期字元設備註冊、標準字元設備註冊。以及詳細介紹各類方法註冊。 開發環境: PC:WMwork
linux字元裝置驅動模型
一.雜項裝置驅動模型 雜項的主裝置號固定為10,只有255個次裝置號。可以直接生成驅動核心。 1.需要確定每個模型都會用到的檔案操作方法集合指標 2.確定核心的結構體 static struct miscdevice abc 確定三個引數,第一個為次裝置號,第二個是次裝
Linux字元裝置驅動
一、字元裝置基礎 字元裝置:是指只能一個位元組一個位元組進行讀寫操作的裝置,不能隨機讀取裝置中的某一資料、讀取資料要按照先後資料。字元裝置是面向流的裝置,常見的字元裝置有滑鼠、鍵盤、串列埠、控制檯和LED等。 一般每個字元裝置或者塊裝置都會在/dev目錄(可以是任意目錄,這樣是為了統一)下對應一個裝置檔案
1--linux字元裝置驅動
1. 編寫一個簡單的字元裝置框架 *****hello.c***** #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <
從零開始寫linux字元裝置驅動程式(一)(基於友善之臂tiny4412開發板)
從這篇博文開始,我將開始手把手教會大家寫linux裝置驅動程式這是開篇,如何來寫第一個字元裝置驅動程式。首先,寫一個最簡單的字元裝置驅動程式需要什麼?或者說我們需要了解什麼?1、每一個字元裝置至少需要有一個裝置號2、裝置號 = 主裝置號 + 次裝置號3、同一類裝置的主裝置號一
Linux 字元裝置驅動結構(三)—— file、inode結構體及chardevs陣列等相關知識解析
先看下面這張圖,這是Linux 中虛擬檔案系統、一般的裝置檔案與裝置驅動程式值間的函式呼叫關係; 上面這張圖展現了一個應用程式呼叫字元裝置驅動的過程, 在裝置驅動程式的設計中,一般而言,會關心 file 和 inode 這兩個結構體
linux字元裝置驅動程式scull例項
這個例子還是比較完整的講述了字元驅動開發的過程,尤其字元驅動程式的設計流程,包括測試在內。 【1.系統環境】 該驅動程式在UBUNTU10.04LTS編譯通過,系統核心為linux-2.6.32-24(可使用uname -r 命令來檢視當前核心的版本號) 由於安裝UBUNTU10.04LTS時,沒有安裝LI
Linux 字元裝置驅動開發--記憶體讀寫操作
學習Linux的累計時間已經有兩年多了,工作關係,學習的過程總是斷斷續續的,現在整理一下,下面要分享的是一個簡單的linux驅動程式,將記憶體當作一個虛擬的裝置去讀寫,沒有什麼實際的用處,像hello wold!程式一樣,我們簡單體會一下linux驅動程式的特點,Linux
linux字元裝置驅動開發模板及Makefile
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> //
linux字元裝置驅動模板(新標準)
//////////////gpio驅動模板//////////////////////////////static int major = 0;static void gpio_setup_cdev(struct cdev *dev, int minor, struct f
Linux字元裝置驅動程式的一個簡單示例
一.原始碼: // memdev.c #define MEMDEV_MAJOR 254 /*預設的mem的主裝置號*/ #define MEMDEV_NR_DEVS 2 /*裝置數*/ #define MEMDEV_SIZE 4096 /*mem裝置描述結構體
Linux 字元裝置驅動結構(三)—— file、inode結構體及chardevs陣列等相關知識解析[轉載]
先看下面這張圖,這是Linux 中虛擬檔案系統、一般的裝置檔案與裝置驅動程式值間的函式呼叫關係; 上面這張圖展現了一個應用程式呼叫字元裝置驅動的過程, 在裝置驅動程式的設計中,一般而言,會關心 file 和 inode 這兩個結構體
Linux字元裝置驅動剖析
一、先看看裝置應用程式 1.很簡單,open裝置檔案,read、write、ioctl,最後close退出。如下: intmain(int argc ,char *argv[]){ unsigned char val[1] = 1; int fd =open("/
linux字元裝置驅動一般模板
#include <linux/miscdevice.h> //標頭檔案有很多,可以根據具體的情況新增刪除,這裡給一個例子。 #include <linux/delay.h> #include <asm/irq.h> #include
Linux 字元裝置驅動結構(一)—— cdev 結構體、裝置號相關知識解析[轉載]
一、字元裝置基礎知識1、裝置驅動分類 linux系統將裝置分為3類:字元裝置、塊裝置、網路裝置。使用驅動程式:字元裝置:是指只能一個位元組一個位元組讀寫的裝置,不能隨機讀取裝置記憶體中的某一資料,讀取資料需要按照先後資料。字元裝置是面向流的裝置,常見的字元裝置有滑鼠
Linux 字元裝置驅動結構(四)—— file_operations 結構體知識解析
前面在 Linux 字元裝置驅動開發基礎 (三)—— 字元裝置驅動結構(中) ,我們已經介紹了兩種重要的資料結構 struct inode{...}與 struct file{...} ,下面來介紹另一個比較重要資料結構 struct _file_oper