設(shè)備驅(qū)動(dòng)分類
字符設(shè)備:可一個(gè)一個(gè)字節(jié)讀取的設(shè)備惑惶,一般要實(shí)現(xiàn)open close read write ioctl等操作带斑,
內(nèi)核為字符設(shè)備對(duì)應(yīng)一個(gè)文件如"/dev/consloe"鄙煤,對(duì)字符設(shè)備的操作通過操作設(shè)備文件實(shí)現(xiàn),不可隨機(jī)讀寫
塊設(shè)備 : 類似字符設(shè)備媚送,可以容納文件系統(tǒng)吩愧,存儲(chǔ)大量信息,每次傳輸一個(gè)或多個(gè)塊极阅。也可像字符設(shè)備一樣
每次讀取一個(gè)字節(jié)胃碾,可隨機(jī)讀寫
網(wǎng)絡(luò)設(shè)備 : 負(fù)責(zé)主機(jī)之間數(shù)據(jù)交換,實(shí)現(xiàn)套接字接口
insmod 將模塊加入正在運(yùn)行的內(nèi)核中
rmmod 將未使用的模塊從內(nèi)核中刪除筋搏, 不可刪除正在使用的模塊仆百。
靜態(tài)加載:內(nèi)核啟動(dòng)時(shí)加載
動(dòng)態(tài)加載:內(nèi)核運(yùn)行時(shí)加載
模塊基本框架
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
int __init xxx_init(void)
{ /* 模塊加載時(shí)初始化 */
retrun 0;
}
void __exit xxx_exit(void)
{ /* 模塊卸載時(shí)銷毀工作 */
}
module_init(xxx_init);
module_exit(xxx_exit);
"linux/string.h"
"linux/slab_def.h" 內(nèi)存分配函數(shù)實(shí)現(xiàn)
內(nèi)核沒有C庫,沒有內(nèi)存保護(hù)機(jī)制拆又,內(nèi)核棧腥逖(需固定常駐內(nèi)存空間32位機(jī)8kb, 64位機(jī)16kb),重視可移植性
ARM (Advanced RISC Manchines)
###使用busybox構(gòu)建根文件系統(tǒng)帖族,make menuconfig配置(需要的時(shí)候細(xì)看)###
升級(jí)內(nèi)核:
1,下載內(nèi)核源碼解壓栈源,make menuconfig
2, make / make modules / make modules_install / make install / reboot
3, 使用uname - r 查看內(nèi)核版本
驅(qū)動(dòng)模塊的組成
1,頭文件
#include <linux/module.h> // 加載模塊時(shí)需要的符號(hào)和函數(shù)定義
#include <linux/init.h> // 包含模塊加載函數(shù)和模塊釋放函數(shù)的宏定義
2竖般,模塊參數(shù)(optional) 驅(qū)動(dòng)加載時(shí)甚垦,需要傳遞給驅(qū)動(dòng)模塊的參數(shù)
3,4,模塊加載和卸載函數(shù)(必須)
5艰亮,模塊許可聲明(必須) MODULE_LICENSE("xxx");
"GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MPL/GPL", "Proprietary"
編譯模塊
ifeq($(KERNELRELEASE), )
KERNELDIR ? = / linuxdir /
PWD : = $(shell pwd)
modules : $(MAKE) - C $(KERNELDIR) M = $(PWD) modules
modules_install : $(MAKE) - C $(KERNELDIR) M = $(PWD) modules_install
clean : rm - rf *.o *~core.depend.*.cmd *.ko *.mod.c.tmp_versions
else
obj - m : = hello.o
endif
modutils 工具操作模塊
1闭翩,insmod 加載模塊, insmod hello.ko,
或可在 / var / log / messages 文件中demsg | tail 查看加載的打印信息迄埃,
傳參 insmod modules.ko param1 = value1 param2 = value2
2疗韵,rmmod 卸載模塊
3,modprobe
4侄非,lsmod 列出模塊
5蕉汪,modinfo 查詢模塊的相關(guān)信息
模塊加載后查看信息
/ proc / modules
cat modules| grep xxx
包含模塊名,使用的內(nèi)存逞怨,引用計(jì)數(shù)者疤,分隔符,活躍狀態(tài)叠赦,加載到內(nèi)核中的地址
/ proc / devices 如果是設(shè)備模塊會(huì)有變化
/ sys / module / 增加模塊的基本信息
/ sys / module / 增加一個(gè)模塊的目錄
定義模塊參數(shù)
static long a = 1;
static int b = 1;
module_param(a, long, S_IRUGO); //參數(shù)名驹马,參數(shù)類型,參數(shù)讀寫權(quán)限
module_param(b, int, S_IRUGO);
類型:byte, short, ushort, int, uint, long, ulong, bool, charp(字符指針類型)
file module.ko 查看模塊文件格式
ELF header; 描述文件基本屬性除秀,如文件版本糯累,目標(biāo)機(jī)器型號(hào),程序入口地址
.text
.data;存放初始化的數(shù)據(jù)
.Section Table;描述文件包含的段的信息册踩,如段名寇蚊,長(zhǎng)度,偏移棍好,讀寫權(quán)限即其他
.symtab ;符號(hào)表允耿,映射函數(shù)到真實(shí)內(nèi)存地址的數(shù)據(jù)結(jié)構(gòu)借笙,模塊加載階段系統(tǒng)賦予真實(shí)的內(nèi)存地址
將模塊添加到內(nèi)核中
1,將去驅(qū)動(dòng)程序文件放到linux源碼目錄中
2较锡,在目錄的Kconfig文件中添加新驅(qū)動(dòng)程序?qū)?yīng)的編譯選項(xiàng)
3业稼,在目錄的Makefile文件中添加新驅(qū)動(dòng)程序的編譯語句
一個(gè)字符設(shè)備或塊設(shè)備都有一個(gè)主設(shè)備號(hào)和此設(shè)備號(hào),統(tǒng)稱為設(shè)備號(hào)蚂蕴。
主設(shè)備號(hào):表示一個(gè)特定的驅(qū)動(dòng)程序
次設(shè)備號(hào):表示使用該驅(qū)動(dòng)的各設(shè)備
typedef u_long dev_t; //32位計(jì)算機(jī)低散,高12位為主設(shè)備號(hào),低20位位次設(shè)備號(hào)
使用宏獲取主次設(shè)備號(hào)
linux / include / kdev_t.h
register_chrdev_region() 靜態(tài)分配設(shè)備號(hào)骡楼,容易造成沖突熔号;
使用alloc_chrdev_region() 動(dòng)態(tài)分配設(shè)備號(hào);
fs / char_dev.c
unregister_chrdev_region()
讀取 / proc / devices 獲取設(shè)備的設(shè)備號(hào)
cdev 結(jié)構(gòu)鸟整,描述字符設(shè)備引镊,是所有字符設(shè)備的抽象 每個(gè)字符設(shè)備在/dev下都有一個(gè)設(shè)備文件,
打開設(shè)備文件,系統(tǒng)產(chǎn)生一個(gè)inode節(jié)點(diǎn)弟头。通過inode的i_cdev字段找到cdev 結(jié)構(gòu)體吩抓,
通過cdev的ops指針,就可以找到設(shè)備的操作函數(shù)赴恨。 file_operations結(jié)構(gòu)體存儲(chǔ)操作指針
內(nèi)核使用inode結(jié)構(gòu)表示文件 用戶空間和內(nèi)核空間的數(shù)據(jù)交換采用專用函數(shù)
copy_to_user(),
copy_from_user(),
put_user(),
get_user()
atomic_t 原子變量類型 原子整形操作疹娶,原子位操作
自旋鎖 struct spinlock_t;
是一種忙等待,鎖住的時(shí)候一直循環(huán)檢測(cè)條件是否滿足伦连,短時(shí)間輕量級(jí)的鎖機(jī)制
不可遞歸使用
spinlock_t lock = SPIN_LOCK_UNLOCK;
spin_lock_init(&lock); //動(dòng)態(tài)初始化鎖
spin_lock(&lock);
spin_unlock(&lock);
內(nèi)核信號(hào)量
沒有獲得信號(hào)量的函數(shù)可能睡眠雨饺,故只有能夠睡眠的進(jìn)程才可以使用信號(hào)量,中斷處理程序不可使用除师;
用在進(jìn)程對(duì)被保護(hù)資源的占用時(shí)間比進(jìn)程上下文切換長(zhǎng)很多(睡眠需要進(jìn)程切換上下文)
struct semaphore
{
spinlock_t lock; //保護(hù)count
unsigned int count; //0 信號(hào)量被使用沛膳,無等待進(jìn)程,<0 至少有一個(gè)進(jìn)程等待,>0 空閑;
struct list_head wait_list; //睡眠等待進(jìn)程隊(duì)列
};
sema_init();
down(); //獲取信號(hào)量,不可被喚醒
down_interruptible(); //可被喚醒
up(); // 釋放信號(hào)量
完成量
一個(gè)線程發(fā)送一個(gè)信號(hào)通知另一個(gè)線程開始完成某個(gè)任務(wù)
struct completion
{
unsigned int done; //0 將擁有完成量的線程置于等待狀態(tài), >0等待完成量的函數(shù)可以立刻執(zhí)行
wait_queue_head_t wait; //等待隊(duì)列鏈表汛聚,存放正在睡眠的進(jìn)程連邊
};
init_completion();
wait_for_completion(); //等待锹安,不會(huì)被信號(hào)中斷的等待
complete(); //喚醒完成量
complete_all();
等待隊(duì)列
struct wait_queue_head
{
spinlock_t lock;
struct list_head task_list;
}
定義系統(tǒng)調(diào)用
asmlinkage int sys_xxx(...){}
編譯進(jìn)內(nèi)核并啟動(dòng),會(huì)增加新的系統(tǒng)調(diào)用__NR_xxx;
調(diào)用方法 syscall(__NR_xxx, ...);
{
DEFINE_WAIT(wait); // 初始化一個(gè)wait_queue_head
prepare_to_wait(p_wait_list, &wait, TASK_INTERRUPTIBLE);//當(dāng)前進(jìn)程進(jìn)入阻塞隊(duì)列
schedule();//重新調(diào)度
finish_wait(p_wait_list, &wait);//進(jìn)程被喚醒從阻塞隊(duì)列退出
}
wake_up(p_wait_list);//喚醒等待隊(duì)列的進(jìn)程
中斷分類
硬中斷:隨機(jī)性倚舀,突發(fā)性叹哭,外部事件觸發(fā)硬件產(chǎn)生,可屏蔽
軟中斷:確定性痕貌,由程序執(zhí)行中斷指令產(chǎn)生的风罩。處理器執(zhí)行到錯(cuò)誤的指令代碼;由軟件產(chǎn)生中斷
外部中斷:由硬件觸發(fā)舵稠,可屏蔽
內(nèi)部中斷:硬件出錯(cuò)或運(yùn)算出錯(cuò)引起的超升,不可屏蔽
同步中斷:中斷來了不會(huì)打斷當(dāng)前執(zhí)行的指令,一般由程序錯(cuò)誤引起
異步中斷:硬件產(chǎn)生哺徊,隨時(shí)的室琢,此中斷處理程序和內(nèi)核是異步執(zhí)行的,不會(huì)影響落追,如接收網(wǎng)絡(luò)數(shù)據(jù)
申請(qǐng)/釋放中斷線
request_irq();
free_irq();
ioremap();//將物理端口地址轉(zhuǎn)換為內(nèi)核地址
static int __init button_init(void){
int ret;
set_irq_type(K1_IRQ, IRQ_TYPE_EDGE_FALLING);
ret = request_irq(K1_IRQ, isr_button, SA_INTERRUPT, DEVICE_NAME, NULL);
if (ret){
printk("K1_IRQ: could not register interrupt\n");
return ret;
}
printk(DEVICE_NAME "initialized\n");
return 0;
}
static irqreturn_t isr_button(int irq, void* dev_id, struct pt_regs*regs){
unsigned long GPGDAT;
GPGDAT = (unsigned long)ioremap(0x56000064, 4);
if (irq == K1_IRQ){
if ((*(volatile unsigned long*)GPGDAT) & 1 == 0){
printk("K1 is pressed\n");
}
}
return 0;
}
static void __exit button_exit(void){
free_irq(K1_IRQ, NULL);
printk(DEVICE_NAME"exit\n");
}
內(nèi)核內(nèi)存動(dòng)態(tài)分配
1盈滴,分配的時(shí)候不會(huì)清空存儲(chǔ)空間的原有數(shù)據(jù),分配連續(xù)物理內(nèi)存空間
static inline void* kmalloc(size_t size, gfp_t flags);
kfree();
size 內(nèi)核先分配一系列大小不同的內(nèi)存池轿钠,選取合大小的內(nèi)存
flags 控制分配的行為
2巢钓,分配虛擬地址連續(xù)的內(nèi)存,物理地址不連續(xù)疗垛,開銷大症汹,用來申請(qǐng)大內(nèi)存,小內(nèi)存
使用__get_free_pages();
void *vmalloc(unsigned long size);
void vfree(const void*addr);
3继谚,后備高速緩存slab烈菌,固定大小的內(nèi)存池阵幸,用于需要頻繁創(chuàng)建和銷毀
struct kmem_cache *kmem_cache_create(const char* name, size_t size/*塊數(shù)目 */, size_t align,
unsigned long flags, void (*ctor)(void*));
void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags);
void kmem_cache_free(struct kmem_cache * cache, void*objp);
void kmem_cache_destroy(struct kmem_cache *cache);
4,頁面分配芽世,物理地址和虛擬地址轉(zhuǎn)換
5挚赊,將I/O端口映射到I/O內(nèi)存空間訪問
#define request_mem_region(start/*起始IO物理地址*/,n/*字節(jié)長(zhǎng)度*/,name) \
__request_region(&iomem_resource,(start),(n),(name),0)
#define release_mem_region(start, n) __release_region(&iomem_resource,(start),(n))
void __iomem *ioremap(unsigned long phys_addr, unsigned long size/*整個(gè)IO端口大小*/);
void iounmap(volatile void __iomem *addr);
ioread8();iowrite8();//16 32
ioreadxx_rep();//多次讀取
iowritexx_rep();//多次寫入
6,I/O端口訪問
#define request_region(start/*I/O端口地址*/,n/*端口數(shù)*/,name) \
__request_region(&ioport_resource,(start),(n),(name),0)
struct resource *__request_region(struct resource *parent, resource_size_t start,
resource_size_t n, const char*name, int flags);
#define release_region(start,n) __release_region(&ioport_resource, (start),(n))
void __release_region(struct resource*parent, resource_size_t start, resource_size_t n);
static inline u8 inb(u16 port);
static inline void outb(u8 v, u16 port);// b w l
設(shè)備驅(qū)動(dòng)模型:設(shè)備和驅(qū)動(dòng)組成的層次結(jié)構(gòu)
sysfs文件系統(tǒng)济瓢,存在于內(nèi)存中荠割,內(nèi)核通過此文件系統(tǒng)將信息導(dǎo)出到用戶空間中,
是內(nèi)核對(duì)象(kobject)旺矾、屬性(kobj_type)及他們的相互關(guān)系的一種表現(xiàn)機(jī)制蔑鹦,可以從sysfs文件系統(tǒng)中讀出內(nèi)核數(shù)據(jù),
可將用戶空間的數(shù)據(jù)寫入內(nèi)核箕宙。/sys/
設(shè)備啟動(dòng)時(shí)嚎朽,設(shè)備驅(qū)動(dòng)模型注冊(cè)kobject對(duì)象,并在sysfs文件系統(tǒng)中產(chǎn)生相應(yīng)目錄
drwxr-xr-x 2 root root 0 Jul 17 20:50 block/
drwxr-xr-x 39 root root 0 May 15 08:30 bus/
drwxr-xr-x 60 root root 0 May 15 08:30 class/
drwxr-xr-x 4 root root 0 May 15 08:30 dev/
drwxr-xr-x 42 root root 0 May 15 08:30 devices/
drwxr-xr-x 5 root root 0 May 15 08:30 firmware/
drwxr-xr-x 8 root root 0 May 15 08:30 fs/
drwxr-xr-x 2 root root 0 Jul 17 20:50 hypervisor/
drwxr-xr-x 11 root root 0 May 15 08:30 kernel/
drwxr-xr-x 137 root root 0 May 15 08:30 module/
drwxr-xr-x 2 root root 0 Jul 17 20:50 power/
如block/ 每個(gè)子目錄對(duì)應(yīng)一個(gè)塊設(shè)備柬帕,記錄各種屬性
每一個(gè)目錄都與一個(gè)kobject對(duì)象對(duì)應(yīng)哟忍,是組成設(shè)備驅(qū)動(dòng)模型的基本結(jié)構(gòu)
最底層目錄是一個(gè)設(shè)備、驅(qū)動(dòng)或其他內(nèi)容陷寝,一個(gè)目錄包含一些屬性锅很,以文件的方式表示ktype
kobject_init();
kobject_get();//增加引用計(jì)數(shù),不為0的時(shí)候凤跑,對(duì)象必須存在
kobject_put();//減少引用計(jì)數(shù)爆安,為0時(shí),系統(tǒng)將釋放資源
kobject_set_name();
kobject_rename();
kobject_add();//在sysfs文件系統(tǒng)中創(chuàng)建一個(gè)目錄
kobject {name,entry/*指向下一個(gè)kobject*/,parent/*指向父kobject*/,kset,ktype,sysfs_dirent/*對(duì)應(yīng)的sysfs的
文件目錄*/,kref,state_initialized,state_in_sysfs,state_add_uevent_sent,state_remove_uevent_sent}
kobj_type {release,sysfs_ops, attribute}
attribute {name , owner, mode /*mode_t */}
sysfs_ops {show/*讀屬性 */,store/*寫屬性 */}
添加非默認(rèn)屬性
sysfs_create_file();
sysfs_remove_file();
kset {list/*kobject鏈表*/,lock, kobject/*表明本身是一個(gè)*/,kset_uevent_ops/*熱插拔事件 */}
kobject通過kset組織成層次化的結(jié)構(gòu)仔引。是具有相同類型kobject集合扔仓,如驅(qū)動(dòng)程序一樣放在/sys/drivers/目錄下,
目錄drivers是一個(gè)kset對(duì)象咖耘,包含系統(tǒng)中驅(qū)動(dòng)程序?qū)?yīng)的目錄当辐,驅(qū)動(dòng)程序的目錄由kobject表示
一個(gè)熱插拔事件是從內(nèi)核空間發(fā)送到用戶空間的通知,表明系統(tǒng)某些部分的配置已經(jīng)變化鲤看。用戶空間收到通知,調(diào)用相應(yīng)的
程序耍群,處理配置的變化义桂。
當(dāng)驅(qū)動(dòng)程序?qū)object注冊(cè)到設(shè)備驅(qū)動(dòng)模型時(shí),內(nèi)核產(chǎn)生熱插拔事件蹈垢,即kobject_add慷吊,kobject_del,熱插拔事件產(chǎn)生時(shí)
內(nèi)核根據(jù)kobject的kset指針找到所屬kset結(jié)構(gòu)體曹抬,執(zhí)行kset中的熱插拔函數(shù)
任何熱插拔程序需要的信息可以通過環(huán)境變量來傳遞
kset_uevent_ops {filter/*決定是否向用戶空間發(fā)信號(hào) */, name/*獲取子系統(tǒng)名字 */, uevent/*在熱插拔程序執(zhí)行前
溉瓶,向環(huán)境變量寫入值 */}
kset_init();
kset_register();
kset_unregister();
kset_get();
kset_put();
設(shè)備驅(qū)動(dòng)模型三大組件:總線,設(shè)備,驅(qū)動(dòng)
此模型中堰酿,所有設(shè)備通過總線連接疾宏,是物理總線的抽象,包含虛擬總線触创。驅(qū)動(dòng)程序附屬在總線上坎藐。
bus_type
總線目錄下包含設(shè)備目錄、驅(qū)動(dòng)目錄哼绑、總線屬性岩馍,設(shè)備和驅(qū)動(dòng)相互綁定
device
設(shè)備結(jié)構(gòu)體包含設(shè)備的通用信息
device_driver
一個(gè)設(shè)備對(duì)應(yīng)一個(gè)最合適的設(shè)備驅(qū)動(dòng)程序,一個(gè)設(shè)備驅(qū)動(dòng)程序可能適用多個(gè)設(shè)備抖韩,設(shè)備驅(qū)動(dòng)模型會(huì)自動(dòng)探測(cè)新設(shè)備的產(chǎn)生蛀恩,并
分配最合適的驅(qū)動(dòng)程序
平臺(tái)設(shè)備模型
優(yōu)勢(shì):平臺(tái)設(shè)備模型將設(shè)備本身的資源注冊(cè)進(jìn)內(nèi)核,由內(nèi)核統(tǒng)一管理茂浮。提高驅(qū)動(dòng)和資源管理的獨(dú)立性双谆,可移植性好,安全
平臺(tái)設(shè)備:處理器上集成的額外功能的附加設(shè)備
platform_device {name,id,device/*設(shè)備 */,num_resources,resource/*申請(qǐng)的資源 */}
資源類型:IORESOURCE_IO, IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
platform_add_devices();//分配平臺(tái)設(shè)備使用的資源励稳,將資源掛到資源樹上佃乘;初始化device設(shè)備斯够,將設(shè)備注冊(cè)到系統(tǒng)
platform_get_resource();
platform_driver{probe,remove,shutdown,suspend,suspend_late,resume_early,resume,driver/*設(shè)備驅(qū)動(dòng) */}
包含設(shè)備驅(qū)動(dòng)和對(duì)平臺(tái)設(shè)備的一些操作
內(nèi)核啟動(dòng)時(shí)骂远,會(huì)注冊(cè)設(shè)備平臺(tái)設(shè)備驅(qū)動(dòng)程序。適當(dāng)時(shí)候通過匹配將設(shè)備和驅(qū)動(dòng)連接起來
platform_match();//找到驅(qū)動(dòng)時(shí)觸發(fā)probe()函數(shù)峰伙,可在其中申請(qǐng)?jiān)O(shè)備所需資源
platform_driver_register();
platform_driver_unregister();
混雜設(shè)備:由于設(shè)備號(hào)比較緊張新翎,一些設(shè)備可以使用同一個(gè)主設(shè)備程帕,不同的次設(shè)備號(hào)。主設(shè)備通常時(shí)10地啰,是特殊的字符設(shè)備
miscdevice{minor/*次設(shè)備號(hào)*/,name,file_operations,list,parent,this_device}
misc_register();
misc_unregister();
IDR機(jī)制:整數(shù)ID管理機(jī)制愁拭,實(shí)質(zhì)是將一個(gè)整數(shù)ID和一個(gè)指針關(guān)聯(lián)起來
FrameBuffer
幀緩沖,位于內(nèi)核空間亏吝,通過FrameBuffer能透明的訪問不同的顯示設(shè)備岭埠,是硬件設(shè)備顯示緩存區(qū)的抽象。
通過操作FrameBuffer直接對(duì)顯存進(jìn)行操作蔚鸥。將其映射到用戶地址空間惜论,寫操作會(huì)立即反應(yīng)再屏幕上
是標(biāo)準(zhǔn)的字符設(shè)備,主設(shè)備號(hào)是29止喷,次設(shè)備號(hào)是0~31馆类,對(duì)應(yīng)/dev/fb0~31, 默認(rèn)/dev/fb指向0號(hào)設(shè)備弹谁。
cp /dev/fb0 myscreen.png // 截屏乾巧, 緩沖區(qū)是普通的內(nèi)存設(shè)備句喜,可以直接對(duì)其進(jìn)行讀寫
LCD顯示原理,F(xiàn)rameBuffer驅(qū)動(dòng)分配一塊內(nèi)存做顯存沟于,對(duì)LCD控制器做一些設(shè)置咳胃。LCD顯示器從顯存中獲取數(shù)據(jù)。將其顯示在
顯示器上社裆。
填充fb_info結(jié)構(gòu)拙绊,register_framebuffer(fb_info*),將fbinfo注冊(cè)到內(nèi)核泳秀,實(shí)現(xiàn)其fs_ops中的接口
fb.h fbmem.c
struct fb_var_screeninfo;//描述圖形卡的特性标沪,用戶設(shè)置
struct fb_fix_screeninfo;//定義了圖形卡的硬件特性不可改變
struct fb_info;//當(dāng)前圖形卡FrameBuffer設(shè)備的獨(dú)立狀態(tài),只對(duì)內(nèi)核可見
struct fb_cmap;//定義幀緩沖設(shè)備的顏色表嗜傅,通過ioctl()的FBIOGETCMAP和FBIOPUTCMAP命令設(shè)置colormap
struct fb_ops;//定義操作函數(shù)
1金句,編寫初始化函數(shù)
初始化LCD控制器,通過寫寄存器設(shè)置顯示模式和顯示顏色數(shù)吕嘀,分配LCD顯示緩沖违寞。起始地址保存在控制器寄存器中。
初始化一個(gè)fb_info結(jié)構(gòu)偶房,將其注冊(cè)進(jìn)內(nèi)核
2趁曼,編寫fb_ops
實(shí)現(xiàn)fb_ops的函數(shù)
LCD驅(qū)動(dòng)程序以平臺(tái)設(shè)備的方式實(shí)現(xiàn)
實(shí)例 s3c2410.h/s3c2410.c
s3c_device_lcd/devs.c
input 子系統(tǒng)
驅(qū)動(dòng)層->核心層(input.c)->處理層->用戶空間層
struct input_dev;//物理輸入設(shè)備的基本數(shù)據(jù)結(jié)構(gòu),包含設(shè)備相關(guān)信息
struct input_handler;//事件處理結(jié)構(gòu)體棕洋,定義如何處理事件的邏輯
struct input_handle;//用來創(chuàng)建input_dev和input_handler之間關(guān)系