SlideShare a Scribd company logo
1 of 31
Chapter 3 字元裝置驅動程式
(char device driver)
Speaker :呂宗螢
Adviser :梁文耀 老師
Date : 2007/1/29
嵌入式及平行系統2
裝置編號
字元裝置的存取,是透過它們在檔案系統裡上的名
稱
 特殊檔 (special file)
• 位於 /dev/ 下,用 ls -l 查看時,第一欄, c 代表字元
裝置, b 代表區塊裝置
 裝置檔 (device file)
 檔案系統樹的節點 (node)
 內定裝置編號列表於 /proc/devices
嵌入式及平行系統3
裝置編號:主編號 & 次編號
 主編號 (major number) :裝置所配合驅動程
式。 ex , /dev/null 與 /dev/zero 都是由 driver 1 控管
 核心容許多個驅動程式共用同一個主編號
 次編號 (minor number) :你的驅動程式所實作的裝置
 在舊版主次編號範圍均為 0~255 , kernel 2.6 則沒有
主 次
crw-rw-rw- 1 root root 1, 3 Apr 11 2002 null
crw------- 1 root root 10, 1 Apr 11 2002 psaux
crw-------   1 root root 4, 1 Oct 28 03:04 tty1
crw-rw-rw- 1 root tty 4, 64 Apr 11 2002 ttys0
crw-rw---- 1 root uucp 4, 65 Apr 11 2002 ttyS1
crw--w---- 1 vcsa tty 7, 1 Apr 11 2002 vcs1
crw--w---- 1 vcsa tty 7, 129 Apr 11 2002 vcsa1
crw-rw-rw- 1 root root 1, 5 Apr 11 2002 zero
嵌入式及平行系統4
建立裝置編號
裝置編號型別: dev_t
#include <linux/types.h>
總長 32bit 無號數,其中 12bit 主編號, 20bit 次編
號
建立裝置編號
#include <linux/kdev_t.h>
 MAJOR(dev_t dev);
 MINOR(dev_t dev);
• 將 dev_t 的主次編號取出來
 MKDEV(int major, int minor)
• 建立裝置編號
嵌入式及平行系統5
裝置編號的配置與釋放
 #include <linux/fs.h>
 int register_chrdev_region(dev_t first, unsigned int count, char
*name);
 配置裝置編號 ( 自定範圍 )
• first :想配置的裝置編號的起點
• count :申請的連續裝置編號總數
• name :獲得此編號範圍的裝置名稱
• 回傳值 0 成功,負值錯誤代碼
 int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned
int count, char *name)
 動態配置裝置編號
• dev :取得配置範圍的第一個裝置編號
• firstminor :申請的第一個次編號 (0)
 void unregister_chrdev_region(dev_t first, unsigned int count)
 釋放裝置編號
嵌入式及平行系統6
file 結構
#include <linux/fs.h>
定義於 struct file
代表己開啟的檔案 (open file)
open() 時自動建立
close() 時才會釋放 ( 需沒有任何行程持有該 file 指
標 )
ps: 閱讀時, file 是結構, filp(file pointer) 是指向
struct file 的指標
嵌入式及平行系統7
file 結構欄位 (1)
 mode_t f_mode;
• 代表檔案的存取模式。
• 可讀: FMODE_READ ,可寫 FMODE_WRITE ,可讀可寫:
FMODE_READ | FMODE_WRITE
• 驅動程式在 open 或 ioctl 作業方法時會檢查此欄位來確定權限
,故不用在 read 或 write 時做檢查
 loff_t f_pos;
• 目前的讀寫位置。
• 64-bit
• read 和 write 作業方法應該透過引數傳來的指標 (loff_t *) 來更新
讀寫位置,不應直接修改 file->f_pos
 unsigned int f_flags;
• 檔案旗標的組合
• 定義於 <linux/fcntl.h> , ex : O_NONBLOCK 、 O_SYNC 、
O_RDONLY
• ex :只需檢查 O_NONBLOCK ,就知道是否要求進行
nonblocking operation
嵌入式及平行系統8
file 結構欄位 (2)
 struct file_operations *f_op;
 指向一個 file_operations 結構,該結構含有一組函式指標,
指向用在本 file 上的各項作業方法
 open 時,核心自動指向一個 file_operations
 核心不會快取 file->f_op ,意味著驅動程式隨時可抽換己註冊
的作業方法
 void *private_data;
 open() 系統呼叫時先設定為 NULL ,才去呼叫驅動程式的
open 作業方法
 可自由決定是否使用, ex 用來保存需要跨越多次系統呼叫的
狀態資訊
 release 作業方法記得釋放此指標指向的記憶體
 struct dentry *f_dentry;
 file 所屬的目錄項 (directory entry)
 file->f_dentry->d_inode
嵌入式及平行系統9
inode 結構
代表檔案
一個檔案可被開啟很多次,而有很多個代表 FD(file
descriptor) 的 file 結構,但全指向同一個檔案,即
inode 結構
dev_t i_rdev;
 含有實際的裝置編號
struct cdev *i_cdev;
 指向一個 struct cdev ,該結構用來表示字元裝置
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);
 用來取得 inode 的主次編號
嵌入式及平行系統10
File_operations
#include <linux/fs.h>
用 OOP 來比喻 file 是物件
(object) , file_operations 就是用來操作 file 物件
的方法 (method)
__user 字串代表指向一個 user-space 位址,不可
直接取值 (dereference)
嵌入式及平行系統11
File_operations 結構 (1)
struct module *owner
 指向擁有本 file_operations 結構的模組
 THIS_MODULE( 定義於 <linux/module.h>)
loff_t (*llseek) (struct file *, loff_t, int);
 定位作業:改變檔案存取的位置,下次讀寫從新位
置開始
 loff_t :至少 64bit
 回傳值:正值代表新存取位置,負值錯誤,
 此函式指標如指向 NULL ,則會改變檔案存取點的
系統呼叫,都有可能造成 file 中的位置指標改到無
法預期的位置
嵌入式及平行系統12
File_operations 結構 (2)
 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 讀取作業
 回傳值,正值代表已成功讀取的位元組個數
 若函式指標指向 NULL ,呼叫 read 時,則會回傳 -
EINVAL(Invalid argument)
 ssize_t (*aio_read) (struct kiocb *, char __user *, size_t,
loff_t);
 異步讀取作業
 不一定能在函式返回前傳輸完畢所有要讀取的資料
 若函式指標指向 NULL ,則會改以 read 取代
 ssize_t (*write) (struct file *, const char __user *, size_t
,loff_t *);
 ssize_t (*aio_write) (struct kiocb *, const char __user *,
size_t, loff_t);
 意思同 read 作業,只是變成 write 作業
嵌入式及平行系統13
File_operations 結構 (3)
 int (*readdir) (struct file *, void *, filldir_t);
 讀取檔案系統上的目錄
 unsigned int (*poll) (struct file *, struct poll_table_struct *);
 查詢裝置的 I/O 狀態。
 poll() 、 epoll() 、 select() 系統呼叫都會作業此法;用來查詢某個已開啟的檔案下次讀寫
是否會造成停頓 (block)
 若函式指向 NULL ,則核心會假設裝置永遠都可以順暢讀寫,不會 block
 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
 執行裝置專屬指令( device-specific command) , ex :格式化軟碟
 若應用程式要求驅動程式沒提供的 ioctl 指令,則會回傳 -ENOTTY(No such ioctl for
device)
 int (*mmap) (struct file *, struct vm_area_struct *);
 記憶體映射操作 (memory mapping) ,將裝置上的記憶體映射到行程的位址空間
 若 NULL ,回傳 – ENODEY
 int (*open) (struct inode *, struct file *);
 開啟檔案,並沒強制要求
 NULL 時一樣可開啟檔案,但驅動程式收不到通知
 int (*flush) (struct file *);
 完工作業,當行程關閉它手中的裝置檔 FD 時,會觸動一次 flush 作業方法,而它應該執
行 ( 並等待 ) 任何常未完成的作業
 NULL 時,則會忽略應用程式要求
嵌入式及平行系統14
File_operations 結構 (4)
 int (*release) (struct inode *, struct file *);
 釋放裝置檔
 只在所有分身都被關閉時,最後一次 close() 才會觸動 releapse
 int (*fsync) (struct file *, struct dentry *, int datasync);
 int (*aio_fsync) (struct kiocb *, int datasync);
 出清留滯資料,讓應用程式用來將留滯在記憶體中的資料全數確實寫入裝置
 NULL 時,則 fsync() 系統呼叫,會傳回 -EINVAL
 int (*fasync) (int, struct file *, int);
 異步作業通知,核心發現 FASYNC 旗標有改變時,會呼叫此作業方法來通知驅
動程式
 int (*lock) (struct file *, int, struct file_lock *);
 檔案鎖定
 驅動程式而言,反而幾乎不必要
 ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
 分散式讀取 (scatter read) 與累積式寫出 (gather write)
 應用程式偶而需要一次讀入多個記憶區的資料,或是將資料一次寫到多個記憶
區,就能讓應用程式直接進行多記憶區的資料傳輸,而不必分次傳輸
 若為 NULL ,則會以 read 和 write 來取代 
嵌入式及平行系統15
File_operations 結構 (5)
 ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
 以最少的抄寫動作,將資料從一個 FD 傳輸到另一個 FD ,也能從
FD 讀出資料給核心
 ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 當核心從 sendfile 獲得一整個記憶頁的資料,便會呼叫目標檔的
sendpage ,將資料寫入該檔案。
 unsigned long (*get_unmapped_area)(struct file *, unsigned long,
unsigned long, unsigned long, unsigned long);
 在行程的位址空間中找出一個適當的位置,用來對映目標裝置上的
記憶區段
 int (*check_flags)(int);
 讓模組可檢查 fcntl(F_SETFL…) 收到旗標
 int (*dir_notify)(struct file *filp, unsigned long arg);
 應用程式使用 fcntl() 索取目錄變更通知,便會呼叫此作業方法。
嵌入式及平行系統16
File_operations 宣告
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
嵌入式及平行系統17
註冊字元裝置
 struct cdev ,代表字元裝置
 #include <linux/cdev.h>
 cdev_alloc();
 配置一個 cdev 的結構
struct cdev *my_codv = cdev_alloc();
my_cdev->ops = &my_fops;
my_cdev->owner = THIS_MODULE;
 void cdev_init(struct cdev *dev, struct file_operations *fops);
 如果驅動程式需要裝 cdev 嵌在你自己設計的一個特殊資料結構時使用
 int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
 將 cdev 加入核心
 cdev_add() 返回時,裝置就當場生效,核心隨時有可能呼叫它的作業方法,故
必須完全準備委當才使用
• dev :設定好的 cdev 結構
• num :是第一個裝置編號
• count :裝置編號的總數
 void cdev_del(struct cdev *dev);
 註銷 cdev
嵌入式及平行系統18
註冊字元裝置範例
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
嵌入式及平行系統19
open 作業方法
 檢查裝置特有的錯誤 (ex :沒放光碟片 .. 等 )
 如果目標裝置首次被開啟,則應該進行初始化程序
 更新 f_op 指標
 配置任何要放在 filp->privated_data 的的資料結構
 container_of(pointer, container_type, container_field);( 因為 inode 引數的 i_cdev ,指向
一個 cdev 結構 )
 #include <linux/kernel.h>
 pointer :指向一個名為 container_field
 container_typer :該欄位所屬之型別
 回傳一個指向容器的結構的指標
 int (*open)(struct inode *inode, struct file *filp);
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev); /* ignore errors */
}
return 0; /* success */
}
嵌入式及平行系統20
release 作業方法
釋放 open 儲存於 filp->private_data 的任何東西
在最後一次關閉時,將目標裝置關機
只有在最後一次 close() 時,才會呼叫 release
int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}
嵌入式及平行系統21
要求記憶體空間
void *kmalloc(size_t size, int flags);
 配置 size 個位元組記憶體
 成功回傳指向該記憶體指標,失敗為 NULL
 flag 引數是描述如何配置記憶體
• GFP_KERNEL :核心記憶體配置。可能休眠
• GFP_USER :配置記憶體給 user-space 行程。可能
休眠 ( 可參閱,第 8 章 p236)
void kfree(void *ptr);
 釋放 kmalloc() 配置的記憶體
嵌入式及平行系統22
read 與 write
 ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t
*offp);
 ssize_t write(struct file *filp, const char __user *buff,size_t count, loff_t
*offp);
 filp : file 結構的指標
 count :是要被傳輸的資料量
 buff :指向一塊 user-space 暫存區
• read 用於存放裝置讀出的資料
• write 含有要被寫入至裝置的資料
 f_pos(long offset type) :使用者正在存取檔案的位置
 回傳值 (signed size type)
 核心不能夠直接取值 (dereference)
 user-space 指標在 kernel 模式下不一樣是有效的
 即使 user-space 與 kernel-space 在同一位址空間,但 user-space
記憶體是換頁式的,發生系統呼叫時,可能導致 page fault ,而這
在 kernel 模式是不充許的
 user-space 指標必定來自某一個 user-space 的應用程式,該程式
可能有錯,甚至是惡意的
read=kernel->user
write=user->kernel
嵌入式及平行系統23
read 與 write(2)
 # include <asm/uaccess.h>
 unsigned long copy_to_user(void __user *to, const void
*from, unsigned long count);
 將資料從 kernel-space -> user-space
 unsigned long copy_from_user(void *to, const void __user
*from, unsigned long count);
 將資料從 user-space -> kernel-space
 這兩個在傳輸時會檢查 user-space 的指標是否有效。如果無
效,則不會傳輸動作。傳輸時才遇到無效位址,則只有部份
資料會完成傳輸
 回傳值 0 為成功完成,正值為尚未完成傳輸的資料量
 如不想檢查 user-space 指標
 __copy_to_user()
 __copy_from_user()
嵌入式及平行系統24
read 作業方法引數
嵌入式及平行系統25
read 作業方法
若回傳值等於當初傳給 read() 系統呼叫的 count 引
數,那表示當初要求傳的資料己經全數傳輸成功
若回傳值大於 0 ,但小於 count ,則表示只順利傳
輸部份資料
若回傳值為 0 ,代表檔案結尾 EOF
若回傳值為 -1 ,則發生某種錯誤
 (<linux/errno.h> 定義各種錯誤代碼 )
嵌入式及平行系統26
Scull 裝置的記憶佈局
嵌入式及平行系統27
read 作業方法範例 (1)
ssize_t scull_read(struct file *filp, char user *buf, size_t count, loff_t *f_pos){
struct scull_dev *dev = filp->private_data;
struct scull_qset *dptr; /* the first listitem */
int quantum = dev->quantum, qset = dev->qset;
int itemsize = quantum * qset; /* how many bytes in the listitem */
int item, s_pos, q_pos, rest;
ssize_t retval = 0;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
if (*f_pos >= dev->size)
goto out;
if (*f_pos + count > dev->size)
count = dev->size - *f_pos;
/* find listitem, qset index, and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum; q_pos = rest % quantum;
嵌入式及平行系統28
read 作業方法範例 (2)
/* follow the list up to the right position (defined elsewhere) */
dptr = scull_follow(dev, item);
if (dptr = = NULL || !dptr->data || ! dptr->data[s_pos])
goto out; /* don't fill holes */
/* read only up to the end of this quantum */
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
out:
up(&dev->sem);
return retval;
}
嵌入式及平行系統29
write 作業方法
若回傳值等於 count ,表示要求的資料量己全數寫
入 scull 裝置
若回傳值大於 0 ,但小於 count ,表示只有部份資
料被寫入裝置
若回傳值為0,表示沒寫入任何資料
若回傳值為負,表示發生錯誤
嵌入式及平行系統30
write 作業方法範例 (1)
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos){
struct scull_dev *dev = filp->private_data;
struct scull_qset *dptr;
int quantum = dev->quantum, qset = dev->qset;
int itemsize = quantum * qset;
int item, s_pos, q_pos, rest;
ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
/* find listitem, qset index and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum; q_pos = rest % quantum;
/* follow the list up to the right position */
dptr = scull_follow(dev, item);
if (dptr = = NULL)
goto out;
if (!dptr->data) {
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if (!dptr->data)
goto out;
memset(dptr->data, 0, qset * sizeof(char *));
}
嵌入式及平行系統31
write 作業方法範例 (2)
if (!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if (!dptr->data[s_pos])
goto out;
}
/* write only up to the end of this quantum */
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
/* update the size */
if (dev->size < *f_pos)
dev->size = *f_pos;
out:
up(&dev->sem);
return retval;
}

More Related Content

What's hot

Data Structure
Data Structure Data Structure
Data Structure Ibrahim MH
 
C++ 프로그래밍 2014-2018년 기말시험 기출문제
C++ 프로그래밍 2014-2018년 기말시험 기출문제C++ 프로그래밍 2014-2018년 기말시험 기출문제
C++ 프로그래밍 2014-2018년 기말시험 기출문제Lee Sang-Ho
 
Run Go applications on Pico using TinyGo
Run Go applications on Pico using TinyGo Run Go applications on Pico using TinyGo
Run Go applications on Pico using TinyGo Yu-Shuan Hsieh
 
関数型言語ElixirのIoTシステム開発への展開
関数型言語ElixirのIoTシステム開発への展開関数型言語ElixirのIoTシステム開発への展開
関数型言語ElixirのIoTシステム開発への展開Hideki Takase
 
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得roboard
 
Constructors and destructors
Constructors and destructorsConstructors and destructors
Constructors and destructorsVineeta Garg
 
array of object pointer in c++
array of object pointer in c++array of object pointer in c++
array of object pointer in c++Arpita Patel
 
Classes and data abstraction
Classes and data abstractionClasses and data abstraction
Classes and data abstractionHoang Nguyen
 
10. 資料永續與交換
10. 資料永續與交換10. 資料永續與交換
10. 資料永續與交換Justin Lin
 
exception handling in java.ppt
exception handling in java.pptexception handling in java.ppt
exception handling in java.pptVarshini62
 
C程式-函式與巨集
C程式-函式與巨集C程式-函式與巨集
C程式-函式與巨集艾鍗科技
 
4章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 24章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 2mao999
 
Selection & Making Decisions in c
Selection & Making Decisions in cSelection & Making Decisions in c
Selection & Making Decisions in cyndaravind
 
Introduction to UBI
Introduction to UBIIntroduction to UBI
Introduction to UBIRoy Lee
 
2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar
2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar
2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminarInterop Tokyo ShowNet NOC Team
 
高位合成でDeep learning
高位合成でDeep learning高位合成でDeep learning
高位合成でDeep learningMori Labo.
 
【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介Yuma Ohgami
 

What's hot (20)

Ch3 gnu make
Ch3 gnu makeCh3 gnu make
Ch3 gnu make
 
Data Structure
Data Structure Data Structure
Data Structure
 
C++
C++C++
C++
 
C++ 프로그래밍 2014-2018년 기말시험 기출문제
C++ 프로그래밍 2014-2018년 기말시험 기출문제C++ 프로그래밍 2014-2018년 기말시험 기출문제
C++ 프로그래밍 2014-2018년 기말시험 기출문제
 
Run Go applications on Pico using TinyGo
Run Go applications on Pico using TinyGo Run Go applications on Pico using TinyGo
Run Go applications on Pico using TinyGo
 
関数型言語ElixirのIoTシステム開発への展開
関数型言語ElixirのIoTシステム開発への展開関数型言語ElixirのIoTシステム開発への展開
関数型言語ElixirのIoTシステム開発への展開
 
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
 
Constructors and destructors
Constructors and destructorsConstructors and destructors
Constructors and destructors
 
array of object pointer in c++
array of object pointer in c++array of object pointer in c++
array of object pointer in c++
 
Classes and data abstraction
Classes and data abstractionClasses and data abstraction
Classes and data abstraction
 
10. 資料永續與交換
10. 資料永續與交換10. 資料永續與交換
10. 資料永續與交換
 
exception handling in java.ppt
exception handling in java.pptexception handling in java.ppt
exception handling in java.ppt
 
C程式-函式與巨集
C程式-函式與巨集C程式-函式與巨集
C程式-函式與巨集
 
Class and object
Class and objectClass and object
Class and object
 
4章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 24章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 2
 
Selection & Making Decisions in c
Selection & Making Decisions in cSelection & Making Decisions in c
Selection & Making Decisions in c
 
Introduction to UBI
Introduction to UBIIntroduction to UBI
Introduction to UBI
 
2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar
2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar
2021年度ShowNetの作り方・コンセプトと設計思想_ShowNet2021 seminar
 
高位合成でDeep learning
高位合成でDeep learning高位合成でDeep learning
高位合成でDeep learning
 
【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介
 

Viewers also liked

A deep dive into energy efficient multi core processor
A deep dive into energy efficient multi core processorA deep dive into energy efficient multi core processor
A deep dive into energy efficient multi core processorZongYing Lyu
 
Libckpt transparent checkpointing under unix
Libckpt transparent checkpointing under unixLibckpt transparent checkpointing under unix
Libckpt transparent checkpointing under unixZongYing Lyu
 
Everyone needs life insurance
Everyone needs life insuranceEveryone needs life insurance
Everyone needs life insuranceInfiniteYou
 
Programme on recently recruited clerks of UCB/DCC/State Cooperative Banks
Programme on recently recruited clerks of UCB/DCC/State Cooperative BanksProgramme on recently recruited clerks of UCB/DCC/State Cooperative Banks
Programme on recently recruited clerks of UCB/DCC/State Cooperative Banksvamnicom123
 
經濟部訴願委員會第A410501007號決定書
經濟部訴願委員會第A410501007號決定書經濟部訴願委員會第A410501007號決定書
經濟部訴願委員會第A410501007號決定書Max Chang
 
1st group!!
1st group!! 1st group!!
1st group!! ichaa17
 
Ici final project report
Ici final project reportIci final project report
Ici final project reportJıa Yıı
 
Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...
Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...
Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...experiannederland
 
Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)
Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)
Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)Nurul Aron
 
A&p 1 lab practical 3 - review
A&p 1   lab practical 3 - reviewA&p 1   lab practical 3 - review
A&p 1 lab practical 3 - reviewSisa Fable
 
JOJOB_forum PA Challenge a #SCE2014-1
JOJOB_forum PA Challenge a #SCE2014-1JOJOB_forum PA Challenge a #SCE2014-1
JOJOB_forum PA Challenge a #SCE2014-1Cristina Costanzo
 
behavior tips! for school kids !
behavior tips! for school kids !behavior tips! for school kids !
behavior tips! for school kids !Ramya Aggarwal
 

Viewers also liked (20)

Ch5 堆疊與佇列
Ch5 堆疊與佇列Ch5 堆疊與佇列
Ch5 堆疊與佇列
 
A deep dive into energy efficient multi core processor
A deep dive into energy efficient multi core processorA deep dive into energy efficient multi core processor
A deep dive into energy efficient multi core processor
 
Libckpt transparent checkpointing under unix
Libckpt transparent checkpointing under unixLibckpt transparent checkpointing under unix
Libckpt transparent checkpointing under unix
 
Vue.js
Vue.jsVue.js
Vue.js
 
Cs437 lecture 7-8
Cs437 lecture 7-8Cs437 lecture 7-8
Cs437 lecture 7-8
 
Creative & Digital Business Briefing - October 2016
Creative & Digital Business Briefing - October 2016Creative & Digital Business Briefing - October 2016
Creative & Digital Business Briefing - October 2016
 
Everyone needs life insurance
Everyone needs life insuranceEveryone needs life insurance
Everyone needs life insurance
 
Manual
Manual Manual
Manual
 
Programme on recently recruited clerks of UCB/DCC/State Cooperative Banks
Programme on recently recruited clerks of UCB/DCC/State Cooperative BanksProgramme on recently recruited clerks of UCB/DCC/State Cooperative Banks
Programme on recently recruited clerks of UCB/DCC/State Cooperative Banks
 
經濟部訴願委員會第A410501007號決定書
經濟部訴願委員會第A410501007號決定書經濟部訴願委員會第A410501007號決定書
經濟部訴願委員會第A410501007號決定書
 
1st group!!
1st group!! 1st group!!
1st group!!
 
Ici final project report
Ici final project reportIci final project report
Ici final project report
 
Creative, Digital & Design Business Briefing — October 2015
Creative, Digital & Design Business Briefing — October 2015Creative, Digital & Design Business Briefing — October 2015
Creative, Digital & Design Business Briefing — October 2015
 
Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...
Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...
Experian Lunchsessie 25 juli: Loyaliteit begint met een eerste acquirerende s...
 
Agenda and list
Agenda and list Agenda and list
Agenda and list
 
Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)
Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)
Year 7 energy_resources_and_electrical_circuits_mark_scheme (1)
 
A&p 1 lab practical 3 - review
A&p 1   lab practical 3 - reviewA&p 1   lab practical 3 - review
A&p 1 lab practical 3 - review
 
JOJOB_forum PA Challenge a #SCE2014-1
JOJOB_forum PA Challenge a #SCE2014-1JOJOB_forum PA Challenge a #SCE2014-1
JOJOB_forum PA Challenge a #SCE2014-1
 
behavior tips! for school kids !
behavior tips! for school kids !behavior tips! for school kids !
behavior tips! for school kids !
 
Appul
AppulAppul
Appul
 

Similar to Device Driver - Chapter 3字元驅動程式

1, shell intro
1, shell intro1, shell intro
1, shell introted-xu
 
Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業ZongYing Lyu
 
Aisanux安装光盘分析
Aisanux安装光盘分析Aisanux安装光盘分析
Aisanux安装光盘分析Guangyao Cheng
 
0911 juluosdev a_journey_of_filesystem_on_jos
0911 juluosdev a_journey_of_filesystem_on_jos0911 juluosdev a_journey_of_filesystem_on_jos
0911 juluosdev a_journey_of_filesystem_on_josWaylin Ch
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practicelitaocheng
 
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)rvillegasg
 
5, system admin
5, system admin5, system admin
5, system adminted-xu
 
Shell(bash) Scripting
Shell(bash) ScriptingShell(bash) Scripting
Shell(bash) ScriptingRobby Lee
 
Erlang jiacheng
Erlang jiachengErlang jiacheng
Erlang jiachengAir-Smile
 
Linux commands ppt
Linux commands pptLinux commands ppt
Linux commands pptxiaotingting
 
MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程Lixun Peng
 
[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階Simen Li
 
C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4Tao He
 
S1: InnoDB AIO原理及相关bug分析
S1: InnoDB AIO原理及相关bug分析S1: InnoDB AIO原理及相关bug分析
S1: InnoDB AIO原理及相关bug分析Hui Liu
 
函数调用关系工具-2011-孙光福
函数调用关系工具-2011-孙光福函数调用关系工具-2011-孙光福
函数调用关系工具-2011-孙光福Wu Liang
 

Similar to Device Driver - Chapter 3字元驅動程式 (20)

Overlayfs and VFS
Overlayfs and VFSOverlayfs and VFS
Overlayfs and VFS
 
1, shell intro
1, shell intro1, shell intro
1, shell intro
 
Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業
 
第9章文件
第9章文件第9章文件
第9章文件
 
Aisanux安装光盘分析
Aisanux安装光盘分析Aisanux安装光盘分析
Aisanux安装光盘分析
 
gnutool
gnutoolgnutool
gnutool
 
Gnu
GnuGnu
Gnu
 
0911 juluosdev a_journey_of_filesystem_on_jos
0911 juluosdev a_journey_of_filesystem_on_jos0911 juluosdev a_journey_of_filesystem_on_jos
0911 juluosdev a_journey_of_filesystem_on_jos
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practice
 
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
 
5, system admin
5, system admin5, system admin
5, system admin
 
Shell(bash) Scripting
Shell(bash) ScriptingShell(bash) Scripting
Shell(bash) Scripting
 
Erlang jiacheng
Erlang jiachengErlang jiacheng
Erlang jiacheng
 
Linux commands ppt
Linux commands pptLinux commands ppt
Linux commands ppt
 
MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程
 
作業系統
作業系統作業系統
作業系統
 
[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階
 
C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4
 
S1: InnoDB AIO原理及相关bug分析
S1: InnoDB AIO原理及相关bug分析S1: InnoDB AIO原理及相关bug分析
S1: InnoDB AIO原理及相关bug分析
 
函数调用关系工具-2011-孙光福
函数调用关系工具-2011-孙光福函数调用关系工具-2011-孙光福
函数调用关系工具-2011-孙光福
 

More from ZongYing Lyu

Performance improvement techniques for software distributed shared memory
Performance improvement techniques for software distributed shared memoryPerformance improvement techniques for software distributed shared memory
Performance improvement techniques for software distributed shared memoryZongYing Lyu
 
Architecture of the oasis mobile shared virtual memory system
Architecture of the oasis mobile shared virtual memory systemArchitecture of the oasis mobile shared virtual memory system
Architecture of the oasis mobile shared virtual memory systemZongYing Lyu
 
Web coding principle
Web coding principleWeb coding principle
Web coding principleZongYing Lyu
 
提高 Code 品質心得
提高 Code 品質心得提高 Code 品質心得
提高 Code 品質心得ZongYing Lyu
 
Consistency protocols
Consistency protocolsConsistency protocols
Consistency protocolsZongYing Lyu
 
Compiler optimization
Compiler optimizationCompiler optimization
Compiler optimizationZongYing Lyu
 
MPI use c language
MPI use c languageMPI use c language
MPI use c languageZongYing Lyu
 
Parallel program design
Parallel program designParallel program design
Parallel program designZongYing Lyu
 

More from ZongYing Lyu (12)

Performance improvement techniques for software distributed shared memory
Performance improvement techniques for software distributed shared memoryPerformance improvement techniques for software distributed shared memory
Performance improvement techniques for software distributed shared memory
 
Architecture of the oasis mobile shared virtual memory system
Architecture of the oasis mobile shared virtual memory systemArchitecture of the oasis mobile shared virtual memory system
Architecture of the oasis mobile shared virtual memory system
 
Web coding principle
Web coding principleWeb coding principle
Web coding principle
 
提高 Code 品質心得
提高 Code 品質心得提高 Code 品質心得
提高 Code 品質心得
 
SCRUM
SCRUMSCRUM
SCRUM
 
Consistency protocols
Consistency protocolsConsistency protocols
Consistency protocols
 
Compiler optimization
Compiler optimizationCompiler optimization
Compiler optimization
 
MPI use c language
MPI use c languageMPI use c language
MPI use c language
 
Cvs
CvsCvs
Cvs
 
Parallel program design
Parallel program designParallel program design
Parallel program design
 
MPI
MPIMPI
MPI
 
OpenMP
OpenMPOpenMP
OpenMP
 

Device Driver - Chapter 3字元驅動程式

  • 1. Chapter 3 字元裝置驅動程式 (char device driver) Speaker :呂宗螢 Adviser :梁文耀 老師 Date : 2007/1/29
  • 2. 嵌入式及平行系統2 裝置編號 字元裝置的存取,是透過它們在檔案系統裡上的名 稱  特殊檔 (special file) • 位於 /dev/ 下,用 ls -l 查看時,第一欄, c 代表字元 裝置, b 代表區塊裝置  裝置檔 (device file)  檔案系統樹的節點 (node)  內定裝置編號列表於 /proc/devices
  • 3. 嵌入式及平行系統3 裝置編號:主編號 & 次編號  主編號 (major number) :裝置所配合驅動程 式。 ex , /dev/null 與 /dev/zero 都是由 driver 1 控管  核心容許多個驅動程式共用同一個主編號  次編號 (minor number) :你的驅動程式所實作的裝置  在舊版主次編號範圍均為 0~255 , kernel 2.6 則沒有 主 次 crw-rw-rw- 1 root root 1, 3 Apr 11 2002 null crw------- 1 root root 10, 1 Apr 11 2002 psaux crw-------   1 root root 4, 1 Oct 28 03:04 tty1 crw-rw-rw- 1 root tty 4, 64 Apr 11 2002 ttys0 crw-rw---- 1 root uucp 4, 65 Apr 11 2002 ttyS1 crw--w---- 1 vcsa tty 7, 1 Apr 11 2002 vcs1 crw--w---- 1 vcsa tty 7, 129 Apr 11 2002 vcsa1 crw-rw-rw- 1 root root 1, 5 Apr 11 2002 zero
  • 4. 嵌入式及平行系統4 建立裝置編號 裝置編號型別: dev_t #include <linux/types.h> 總長 32bit 無號數,其中 12bit 主編號, 20bit 次編 號 建立裝置編號 #include <linux/kdev_t.h>  MAJOR(dev_t dev);  MINOR(dev_t dev); • 將 dev_t 的主次編號取出來  MKDEV(int major, int minor) • 建立裝置編號
  • 5. 嵌入式及平行系統5 裝置編號的配置與釋放  #include <linux/fs.h>  int register_chrdev_region(dev_t first, unsigned int count, char *name);  配置裝置編號 ( 自定範圍 ) • first :想配置的裝置編號的起點 • count :申請的連續裝置編號總數 • name :獲得此編號範圍的裝置名稱 • 回傳值 0 成功,負值錯誤代碼  int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)  動態配置裝置編號 • dev :取得配置範圍的第一個裝置編號 • firstminor :申請的第一個次編號 (0)  void unregister_chrdev_region(dev_t first, unsigned int count)  釋放裝置編號
  • 6. 嵌入式及平行系統6 file 結構 #include <linux/fs.h> 定義於 struct file 代表己開啟的檔案 (open file) open() 時自動建立 close() 時才會釋放 ( 需沒有任何行程持有該 file 指 標 ) ps: 閱讀時, file 是結構, filp(file pointer) 是指向 struct file 的指標
  • 7. 嵌入式及平行系統7 file 結構欄位 (1)  mode_t f_mode; • 代表檔案的存取模式。 • 可讀: FMODE_READ ,可寫 FMODE_WRITE ,可讀可寫: FMODE_READ | FMODE_WRITE • 驅動程式在 open 或 ioctl 作業方法時會檢查此欄位來確定權限 ,故不用在 read 或 write 時做檢查  loff_t f_pos; • 目前的讀寫位置。 • 64-bit • read 和 write 作業方法應該透過引數傳來的指標 (loff_t *) 來更新 讀寫位置,不應直接修改 file->f_pos  unsigned int f_flags; • 檔案旗標的組合 • 定義於 <linux/fcntl.h> , ex : O_NONBLOCK 、 O_SYNC 、 O_RDONLY • ex :只需檢查 O_NONBLOCK ,就知道是否要求進行 nonblocking operation
  • 8. 嵌入式及平行系統8 file 結構欄位 (2)  struct file_operations *f_op;  指向一個 file_operations 結構,該結構含有一組函式指標, 指向用在本 file 上的各項作業方法  open 時,核心自動指向一個 file_operations  核心不會快取 file->f_op ,意味著驅動程式隨時可抽換己註冊 的作業方法  void *private_data;  open() 系統呼叫時先設定為 NULL ,才去呼叫驅動程式的 open 作業方法  可自由決定是否使用, ex 用來保存需要跨越多次系統呼叫的 狀態資訊  release 作業方法記得釋放此指標指向的記憶體  struct dentry *f_dentry;  file 所屬的目錄項 (directory entry)  file->f_dentry->d_inode
  • 9. 嵌入式及平行系統9 inode 結構 代表檔案 一個檔案可被開啟很多次,而有很多個代表 FD(file descriptor) 的 file 結構,但全指向同一個檔案,即 inode 結構 dev_t i_rdev;  含有實際的裝置編號 struct cdev *i_cdev;  指向一個 struct cdev ,該結構用來表示字元裝置 unsigned int iminor(struct inode *inode); unsigned int imajor(struct inode *inode);  用來取得 inode 的主次編號
  • 10. 嵌入式及平行系統10 File_operations #include <linux/fs.h> 用 OOP 來比喻 file 是物件 (object) , file_operations 就是用來操作 file 物件 的方法 (method) __user 字串代表指向一個 user-space 位址,不可 直接取值 (dereference)
  • 11. 嵌入式及平行系統11 File_operations 結構 (1) struct module *owner  指向擁有本 file_operations 結構的模組  THIS_MODULE( 定義於 <linux/module.h>) loff_t (*llseek) (struct file *, loff_t, int);  定位作業:改變檔案存取的位置,下次讀寫從新位 置開始  loff_t :至少 64bit  回傳值:正值代表新存取位置,負值錯誤,  此函式指標如指向 NULL ,則會改變檔案存取點的 系統呼叫,都有可能造成 file 中的位置指標改到無 法預期的位置
  • 12. 嵌入式及平行系統12 File_operations 結構 (2)  ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);  讀取作業  回傳值,正值代表已成功讀取的位元組個數  若函式指標指向 NULL ,呼叫 read 時,則會回傳 - EINVAL(Invalid argument)  ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);  異步讀取作業  不一定能在函式返回前傳輸完畢所有要讀取的資料  若函式指標指向 NULL ,則會改以 read 取代  ssize_t (*write) (struct file *, const char __user *, size_t ,loff_t *);  ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);  意思同 read 作業,只是變成 write 作業
  • 13. 嵌入式及平行系統13 File_operations 結構 (3)  int (*readdir) (struct file *, void *, filldir_t);  讀取檔案系統上的目錄  unsigned int (*poll) (struct file *, struct poll_table_struct *);  查詢裝置的 I/O 狀態。  poll() 、 epoll() 、 select() 系統呼叫都會作業此法;用來查詢某個已開啟的檔案下次讀寫 是否會造成停頓 (block)  若函式指向 NULL ,則核心會假設裝置永遠都可以順暢讀寫,不會 block  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);  執行裝置專屬指令( device-specific command) , ex :格式化軟碟  若應用程式要求驅動程式沒提供的 ioctl 指令,則會回傳 -ENOTTY(No such ioctl for device)  int (*mmap) (struct file *, struct vm_area_struct *);  記憶體映射操作 (memory mapping) ,將裝置上的記憶體映射到行程的位址空間  若 NULL ,回傳 – ENODEY  int (*open) (struct inode *, struct file *);  開啟檔案,並沒強制要求  NULL 時一樣可開啟檔案,但驅動程式收不到通知  int (*flush) (struct file *);  完工作業,當行程關閉它手中的裝置檔 FD 時,會觸動一次 flush 作業方法,而它應該執 行 ( 並等待 ) 任何常未完成的作業  NULL 時,則會忽略應用程式要求
  • 14. 嵌入式及平行系統14 File_operations 結構 (4)  int (*release) (struct inode *, struct file *);  釋放裝置檔  只在所有分身都被關閉時,最後一次 close() 才會觸動 releapse  int (*fsync) (struct file *, struct dentry *, int datasync);  int (*aio_fsync) (struct kiocb *, int datasync);  出清留滯資料,讓應用程式用來將留滯在記憶體中的資料全數確實寫入裝置  NULL 時,則 fsync() 系統呼叫,會傳回 -EINVAL  int (*fasync) (int, struct file *, int);  異步作業通知,核心發現 FASYNC 旗標有改變時,會呼叫此作業方法來通知驅 動程式  int (*lock) (struct file *, int, struct file_lock *);  檔案鎖定  驅動程式而言,反而幾乎不必要  ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);  ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);  分散式讀取 (scatter read) 與累積式寫出 (gather write)  應用程式偶而需要一次讀入多個記憶區的資料,或是將資料一次寫到多個記憶 區,就能讓應用程式直接進行多記憶區的資料傳輸,而不必分次傳輸  若為 NULL ,則會以 read 和 write 來取代 
  • 15. 嵌入式及平行系統15 File_operations 結構 (5)  ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);  以最少的抄寫動作,將資料從一個 FD 傳輸到另一個 FD ,也能從 FD 讀出資料給核心  ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);  當核心從 sendfile 獲得一整個記憶頁的資料,便會呼叫目標檔的 sendpage ,將資料寫入該檔案。  unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);  在行程的位址空間中找出一個適當的位置,用來對映目標裝置上的 記憶區段  int (*check_flags)(int);  讓模組可檢查 fcntl(F_SETFL…) 收到旗標  int (*dir_notify)(struct file *filp, unsigned long arg);  應用程式使用 fcntl() 索取目錄變更通知,便會呼叫此作業方法。
  • 16. 嵌入式及平行系統16 File_operations 宣告 struct file_operations scull_fops = { .owner = THIS_MODULE, .llseek = scull_llseek, .read = scull_read, .write = scull_write, .ioctl = scull_ioctl, .open = scull_open, .release = scull_release, };
  • 17. 嵌入式及平行系統17 註冊字元裝置  struct cdev ,代表字元裝置  #include <linux/cdev.h>  cdev_alloc();  配置一個 cdev 的結構 struct cdev *my_codv = cdev_alloc(); my_cdev->ops = &my_fops; my_cdev->owner = THIS_MODULE;  void cdev_init(struct cdev *dev, struct file_operations *fops);  如果驅動程式需要裝 cdev 嵌在你自己設計的一個特殊資料結構時使用  int cdev_add(struct cdev *dev, dev_t num, unsigned int count);  將 cdev 加入核心  cdev_add() 返回時,裝置就當場生效,核心隨時有可能呼叫它的作業方法,故 必須完全準備委當才使用 • dev :設定好的 cdev 結構 • num :是第一個裝置編號 • count :裝置編號的總數  void cdev_del(struct cdev *dev);  註銷 cdev
  • 18. 嵌入式及平行系統18 註冊字元裝置範例 struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the current array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */ }; static void scull_setup_cdev(struct scull_dev *dev, int index) { int err, devno = MKDEV(scull_major, scull_minor + index); cdev_init(&dev->cdev, &scull_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &scull_fops; err = cdev_add (&dev->cdev, devno, 1); /* Fail gracefully if need be */ if (err) printk(KERN_NOTICE "Error %d adding scull%d", err, index); }
  • 19. 嵌入式及平行系統19 open 作業方法  檢查裝置特有的錯誤 (ex :沒放光碟片 .. 等 )  如果目標裝置首次被開啟,則應該進行初始化程序  更新 f_op 指標  配置任何要放在 filp->privated_data 的的資料結構  container_of(pointer, container_type, container_field);( 因為 inode 引數的 i_cdev ,指向 一個 cdev 結構 )  #include <linux/kernel.h>  pointer :指向一個名為 container_field  container_typer :該欄位所屬之型別  回傳一個指向容器的結構的指標  int (*open)(struct inode *inode, struct file *filp); int scull_open(struct inode *inode, struct file *filp) { struct scull_dev *dev; /* device information */ dev = container_of(inode->i_cdev, struct scull_dev, cdev); filp->private_data = dev; /* for other methods */ /* now trim to 0 the length of the device if open was write-only */ if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) { scull_trim(dev); /* ignore errors */ } return 0; /* success */ }
  • 20. 嵌入式及平行系統20 release 作業方法 釋放 open 儲存於 filp->private_data 的任何東西 在最後一次關閉時,將目標裝置關機 只有在最後一次 close() 時,才會呼叫 release int scull_release(struct inode *inode, struct file *filp) { return 0; }
  • 21. 嵌入式及平行系統21 要求記憶體空間 void *kmalloc(size_t size, int flags);  配置 size 個位元組記憶體  成功回傳指向該記憶體指標,失敗為 NULL  flag 引數是描述如何配置記憶體 • GFP_KERNEL :核心記憶體配置。可能休眠 • GFP_USER :配置記憶體給 user-space 行程。可能 休眠 ( 可參閱,第 8 章 p236) void kfree(void *ptr);  釋放 kmalloc() 配置的記憶體
  • 22. 嵌入式及平行系統22 read 與 write  ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);  ssize_t write(struct file *filp, const char __user *buff,size_t count, loff_t *offp);  filp : file 結構的指標  count :是要被傳輸的資料量  buff :指向一塊 user-space 暫存區 • read 用於存放裝置讀出的資料 • write 含有要被寫入至裝置的資料  f_pos(long offset type) :使用者正在存取檔案的位置  回傳值 (signed size type)  核心不能夠直接取值 (dereference)  user-space 指標在 kernel 模式下不一樣是有效的  即使 user-space 與 kernel-space 在同一位址空間,但 user-space 記憶體是換頁式的,發生系統呼叫時,可能導致 page fault ,而這 在 kernel 模式是不充許的  user-space 指標必定來自某一個 user-space 的應用程式,該程式 可能有錯,甚至是惡意的 read=kernel->user write=user->kernel
  • 23. 嵌入式及平行系統23 read 與 write(2)  # include <asm/uaccess.h>  unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);  將資料從 kernel-space -> user-space  unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);  將資料從 user-space -> kernel-space  這兩個在傳輸時會檢查 user-space 的指標是否有效。如果無 效,則不會傳輸動作。傳輸時才遇到無效位址,則只有部份 資料會完成傳輸  回傳值 0 為成功完成,正值為尚未完成傳輸的資料量  如不想檢查 user-space 指標  __copy_to_user()  __copy_from_user()
  • 25. 嵌入式及平行系統25 read 作業方法 若回傳值等於當初傳給 read() 系統呼叫的 count 引 數,那表示當初要求傳的資料己經全數傳輸成功 若回傳值大於 0 ,但小於 count ,則表示只順利傳 輸部份資料 若回傳值為 0 ,代表檔案結尾 EOF 若回傳值為 -1 ,則發生某種錯誤  (<linux/errno.h> 定義各種錯誤代碼 )
  • 27. 嵌入式及平行系統27 read 作業方法範例 (1) ssize_t scull_read(struct file *filp, char user *buf, size_t count, loff_t *f_pos){ struct scull_dev *dev = filp->private_data; struct scull_qset *dptr; /* the first listitem */ int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum * qset; /* how many bytes in the listitem */ int item, s_pos, q_pos, rest; ssize_t retval = 0; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (*f_pos >= dev->size) goto out; if (*f_pos + count > dev->size) count = dev->size - *f_pos; /* find listitem, qset index, and offset in the quantum */ item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum;
  • 28. 嵌入式及平行系統28 read 作業方法範例 (2) /* follow the list up to the right position (defined elsewhere) */ dptr = scull_follow(dev, item); if (dptr = = NULL || !dptr->data || ! dptr->data[s_pos]) goto out; /* don't fill holes */ /* read only up to the end of this quantum */ if (count > quantum - q_pos) count = quantum - q_pos; if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) { retval = -EFAULT; goto out; } *f_pos += count; retval = count; out: up(&dev->sem); return retval; }
  • 29. 嵌入式及平行系統29 write 作業方法 若回傳值等於 count ,表示要求的資料量己全數寫 入 scull 裝置 若回傳值大於 0 ,但小於 count ,表示只有部份資 料被寫入裝置 若回傳值為0,表示沒寫入任何資料 若回傳值為負,表示發生錯誤
  • 30. 嵌入式及平行系統30 write 作業方法範例 (1) ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos){ struct scull_dev *dev = filp->private_data; struct scull_qset *dptr; int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum * qset; int item, s_pos, q_pos, rest; ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ if (down_interruptible(&dev->sem)) return -ERESTARTSYS; /* find listitem, qset index and offset in the quantum */ item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; /* follow the list up to the right position */ dptr = scull_follow(dev, item); if (dptr = = NULL) goto out; if (!dptr->data) { dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL); if (!dptr->data) goto out; memset(dptr->data, 0, qset * sizeof(char *)); }
  • 31. 嵌入式及平行系統31 write 作業方法範例 (2) if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); if (!dptr->data[s_pos]) goto out; } /* write only up to the end of this quantum */ if (count > quantum - q_pos) count = quantum - q_pos; if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) { retval = -EFAULT; goto out; } *f_pos += count; retval = count; /* update the size */ if (dev->size < *f_pos) dev->size = *f_pos; out: up(&dev->sem); return retval; }