標籤:
Android系統中, 驅動程式因商業需求分為運行在使用者空間的hardware層以及運行在核心空間的驅動程式, 大多情況下核心驅動都需要提供使用者空間訪問的介面。
Linux核心空間到使用者空間的介面有主要有以下幾種類型
1.系統調用
系統調用是指系統實現的所有系統調用所構成的集合,即程式介面。
linux系統調用分為:進程式控制制,檔案系統控制,系統控制,記憶體管理,網路管理,使用者管理,進程管理等類型
linux作業系統中,系統調用的ID通常在arch/{體繫結構}/include/asm/目錄的unistd.h檔案中.
可增加系統調用為使用者空間提供提供者,用於系統調用是UNIX標準的內容,所以一般情況下不這樣做。
2.字元裝置節點
字元裝置進行I/O操作不經過作業系統的緩衝區,每次操作只傳輸一個字元,可以通過字元裝置檔案來訪問
檔案操作file_operations表示對一個檔案的操作,其定義在/kernel/include/linux/fs.h
........
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
........
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f);
};
........
// 字元裝置的註冊函數
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
// 字元裝置的銷毀函數
static inline void unregister_chrdev(unsigned int major, const char *name)
{
__unregister_chrdev(major, 0, 256, name);
}
........
對於一般的檔案,可以通過通用的檔案操作,如open,read,write,ioctl,mmap,release等,
對於簡單的字元裝置,也是驅動的裝置節點,它的檔案操作與一般的檔案不一樣,需要單獨實現。
字元裝置的驅動程式,可以基於字元裝置的驅動程式架構來構建,也可基於特定的字元裝置架構來構建.
基於字元裝置的驅動程式架構來建設:
直接實現對字元裝置的註冊函數進行註冊,此時定義的字元裝置一般具有一個唯一的主裝置號.
在註冊具體的字元裝置時,構建file_operations中的各個成員函數指標
基於特定的字元裝置驅動程式架構來構建:(Misc驅動程式,幀緩衝驅動程式,TTY驅動程式等)
這些驅動程式的架構通常對字元裝置驅動架構進行封裝,實現自己的架構,並且具有了自己的註冊機制。
在具體的驅動程式的實現中,通過這種驅動程式架構的註冊函數進行註冊,實現相關的函數。
此時,驅動程式的架構一般已經實現了主裝置號,具體的驅動程式實現的是次裝置號。
在使用者空間通過/dev/中裝置節點調用驅動程式順序:使用者空間-->字元裝置驅動程式的架構-->該類驅動程式的架構-->具體驅動程式的實現。
3.塊裝置節點(光碟片,硬碟,磁碟片)
塊裝置採用隨機訪問的方式傳輸資料,並且資料總是具有固定大小的快,為了提高資料轉送效率,塊裝置驅動程式內部採用塊緩衝技術.
塊裝置的操作在/kernel/include/linux/blkdev.h中定義
struct block_device_operations {
int (*open) (struct block_device *, fmode_t);
void (*release) (struct gendisk *, fmode_t);
int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*direct_access) (struct block_device *, sector_t,
void **, unsigned long *);
unsigned int (*check_events) (struct gendisk *disk,
unsigned int clearing);
/* ->media_changed() is DEPRECATED, use ->check_events() instead */
int (*media_changed) (struct gendisk *);
void (*unlock_native_capacity) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);
int (*getgeo)(struct block_device *, struct hd_geometry *);
/* this callback is with swap_lock and sometimes page table lock held */
void (*swap_slot_free_notify) (struct block_device *, unsigned long);
struct module *owner;
};
註冊與登出/kernel/include/linux/fs.h
extern int register_blkdev(unsigned int, const char *);
extern void unregister_blkdev(unsigned int, const char *);
對於塊裝置,由於也是裝置節點,也可以使用檔案介面來訪問,一般不直接存取塊裝置節點,而是使用檔案系統來訪問。可用df或mount來查看掛載情況
Android塊裝置在/dev/block/目錄中
4.網路裝置
網路裝置沒有檔案系統的節點,使用socket機制,通過專有的資料結構進行訪問,系統內部支援資料的收發。
網路裝置與字元裝置和塊裝置最大的區別在於網路裝置沒有檔案系統的節點。
一般網路驅動程式不會由應用程式調用,而是由linux核心的網路模組調用,使用者空間程式通過socket等通用網路介面,間接調用網路驅動程式。
訪問網路裝置時,需要用到socket相關的幾個函數:socket(),bind(),listen(),accept(),connect()等
socket()和open一樣,傳回型別也是一個檔案描述符,表示一個在進程中開啟的檔案。可以用通常的檔案操作來對這個檔案描述符進行操作。
網路裝置的核心定義在/kernel/include/linux/netdevice.h
........
struct net_device {
charname[IFNAMSIZ];
struct hlist_nodename_hlist;
char *ifalias;
........
};
........
int register_netdev(struct net_device *dev); // 註冊函數
void unregister_netdev(struct net_device *dev);// 撤銷函數
........
5.proc檔案系統(ramconsole驅動)
proc檔案在/proc目錄中,用於查看有關硬體,進程的狀態,也可以通過操作proc檔案系統進行控制工作
proc檔案系統的建立函數定義在/kernel/include/linux/proc_fs.h
struct proc_dir_entry { // 表示一個目錄項的入口
unsigned int low_ino;
umode_t mode;
nlink_t nlink;
kuid_t uid;
kgid_t gid;
loff_t size;
const struct inode_operations *proc_iops; // 檔案系統操作
const struct file_operations *proc_fops; // 檔案系統節點操作
........
};
6.sys檔案系統
sys檔案系統與proc有些類似,除了查看和設定核心參數功能之外,還有位linux統一裝置模型作為管理之用
sys檔案系統只有讀和寫兩個介面,不支援參數傳遞,大規模資料區塊操作等複雜的操作
sys檔案系統在linux檔案系統的/sys/目錄中,如/sys/bus/為匯流排目錄結構,/sys/class為按功能分類裝置模型
通過cat與echo重新導向來查看與設定/sys目錄
7.無使用者空間介面
AndroidM 核心空間到使用者空間介面類型