【1.input子系統框架(drivers\input)】
如何得出某個驅動所遵循的框架?
1) 經過網絡搜索
2) 本身想辦法跟內核代碼!
2.1 定位此驅動是屬於哪一種類型的(觸摸屏驅動爲字符設備)
2.2 搜索register_chrdev獲得,input.c
2.3 分析input.c文件node
/*入口函數*/
subsys_initcall(input_init);
input_init
/*1.建立一個設備類*/
class_register(
&input_class);
/*2.申請主設備號,註冊操做方法,註冊字符設備*/
register_chrdev(
13,
"input",
&input_fops);
static
const
struct file_operations input_fops
= {
.owner
= THIS_MODULE,
.open
= input_open_file,
};
2.4 分析如何來用input子系統linux
app
: open(
"/dev/xxx",...)
==
==
==
==
==
==
==
==
==
==
==
==
==
==
=
vfs
: sys_open
...
...
input.c
struct file_operations input_fops
.open
= input_open_file,
/*1.根據次設備號,從input_table數組中,取出一個input_handler結構體*/
handler
= input_table[iminor(inode)
>>
5];
//2
/*2.取出input_handler裏面的操做方法*/
if (handler)
new_fops
= fops_get(handler
-
>fops);
//evdev_fops
old_fops
= file
-
>f_op;
file
-
>f_op
= new_fops;
//file中的f_op覆蓋了
/*3.執行底層的open函數*/
new_fops
-
>open(inode, file);
//事件處理層的操做方法裏面的open函數evdev_open
evdev_open
2.5 根據handler = input_table[iminor(inode) >> 5];
猜想,有某段代碼將input_handler放入了input_table[iminor(inode) >> 5]
搜索input_table,看在哪裏放了數組
module_init(evdev_init);
evdev_init
//driver/input/evdev.c
/*註冊一個handler*/
input_register_handler(
struct input_handler
*handler)
/*將input_handler放入input_table數組中*/
input_table[handler
-
>minor
>>
5]
= handler;
static
struct input_handler evdev_handler
= {
.event
= evdev_event,
.connect
= evdev_connect,
.disconnect
= evdev_disconnect,
.fops
=
&evdev_fops,
.minor
= EVDEV_MINOR_BASE,
.name
=
"evdev",
.id_table
= evdev_ids,
};
【input子系統框架講解】
1.input子系統的核心層(input.c)
功能:1)給用戶提供接口(register_chrdev,cdev,file_operations結構體)
2)給用input子系統內部組件提供接口,創建三者之間的聯繫網絡
/*入口函數*/
subsys_initcall(input_init);
input_init
/*1.建立一個設備類*/
class_register(
&input_class);
/*2.申請主設備號,註冊操做方法,註冊字符設備*/
register_chrdev(
13,
"input",
&input_fops);
static
const
struct file_operations input_fops
= {
.owner
= THIS_MODULE,
.open
= input_open_file,
};
2.input子系統的事件處理層(evdev.c)
功能:專門用來爲設備驅動層上報事件的app
/*入口函數*/
module_init(evdev_init);
evdev_init
//driver/input/evdev.c
/*註冊一個handler*/
input_register_handler(
struct input_handler
*handler)
/*將input_handler放入input_table數組中*/
input_table[handler
-
>minor
>>
5]
= handler;
//64/32 =2
static
struct input_handler evdev_handler
= {
//表示事件處理句柄
.event
= evdev_event,
//上報事件的時候,會調用此函數
.connect
= evdev_connect,
//創建鏈接的時候,會調用此函數
.disconnect
= evdev_disconnect,
.fops
=
&evdev_fops,
//事件處理方法(xxx_read)
.minor
= EVDEV_MINOR_BASE,
//64
.name
=
"evdev",
.id_table
= evdev_ids,
};
static
const
struct file_operations evdev_fops
= {
.owner
= THIS_MODULE,
.read
= evdev_read,
//當應用程序來讀數據的時候,便會調用此函數
.write
= evdev_write,
.poll
= evdev_poll,
.open
= evdev_open,
.release
= evdev_release,
.unlocked_ioctl
= evdev_ioctl,
.fasync
= evdev_fasync,
.flush
= evdev_flush
};
3.input子系統的設備驅動層(s3c2410_ts.c爲例子)(是驅動工做人員的主要任務)
功能:1)跟硬件交互,操做硬件,獲取硬件的外部事件
2)提交事件給事件處理層框架
/*入口函數*/
module_init(s3c2410ts_init);
s3c2410ts_init
/*註冊一個平臺驅動*/
platform_driver_register(
&s3c_ts_driver);
static
struct platform_driver s3c_ts_driver
= {
.driver
= {
.name
=
"samsung-ts",
.owner
= THIS_MODULE,
#
ifdef CONFIG_PM
.pm
=
&s3c_ts_pmops,
#
endif
},
.id_table
= s3cts_driver_ids,
.probe
= s3c2410ts_probe,
.remove
= __devexit_p(s3c2410ts_remove),
};
/*匹配成功,則調用平臺驅動中的probe函數*/
s3c2410ts_probe
/*猜想*/
/*1.獲取資源*/
/*1.1 獲取平臺數據*/
info
= pdev
-
>dev.platform_data;
/*1.2 使能時鐘*/
ts.clock
= clk_get(dev,
"adc");
clk_enable(ts.clock);
/*1.3 獲取中斷資源*/
ts.irq_tc
= ret
= platform_get_irq(pdev,
0);
/*1.4 獲取IO內存資源*/
res
= platform_get_resource(pdev, IORESOURCE_MEM,
0);
/*1.5 映射*/
ts.io
= ioremap(res
-
>start, resource_size(res));
/*1.6 註冊中斷*/
ret
= request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
"s3c2410_ts_pen", ts.input);
/*2. 申請ADC服務*/
/*3. 初始化硬件(初始化觸摸屏控制器)*/
/*4. 構建一個struct input_dev結構體*/
struct input_dev
*
input_dev;
//表示一個輸入設備
/*4.1 設置input_dev*/
/*4.2 註冊input_dev,註冊到子系統(input子系統中)*/
input_register_device(ts.input);
【input子系統裏面涉及的幾個重要結構體】
struct
input_dev
//用來表示一個輸入設備
{
unsigned
long evbit[BITS_TO_LONGS(EV_CNT)];
//事件類型
unsigned
long keybit[BITS_TO_LONGS(KEY_CNT)];
//按鍵類當中什麼按鍵
unsigned
long relbit[BITS_TO_LONGS(REL_CNT)];
//相對位移的什麼事件
unsigned
long absbit[BITS_TO_LONGS(ABS_CNT)];
//絕對位移的什麼事件
...
};
struct
input_handler
//用來表示一個事件處理句柄
{
/*上報事件*/
void (
*event)(
struct input_handle
*handle,
unsigned
int type,
unsigned
int code,
int value);
/*創建鏈接的*/
int (
*connect)(
struct input_handler
*handler,
struct input_dev
*dev,
const
struct input_device_id
*id);
const
struct file_operations
*fops;
...
}
struct
input_handle
//用來創建input_dev與input_handler的鏈接的
{
...
struct input_dev
*dev;
struct input_handler
*handler;
struct list_head d_node;
struct list_head h_node;
}
struct
input_event
//用來表示一個輸入事件
{
struct timeval time;
//事件產生的時間
__u16 type;
//事件類型 EV_KEY
__u16 code;
//事件碼 KEY_A KEY_B
__s32 value;
//事件值 1-按下 0-鬆開
}
【input子系統中涉及的重要函數:(input.c)】
/*註冊一個事件處理句柄*/
int input_register_handler(
struct input_handler
*handler)
void input_unregister_handler(
struct input_handler
*handler)
/*註冊一個輸入設備*/
int input_register_device(
struct input_dev
*dev)
void input_unregister_device(
struct input_dev
*dev)
/*提交事件到事件處理層*/
void input_event(
struct input_dev
*dev,
unsigned
int type,
unsigned
int code,
int value)
/*提交按鍵類事件*/
void input_report_key(
struct input_dev
*dev,
unsigned
int code,
int value)
/*提交相對位移事件*/
void input_report_rel(
struct input_dev
*dev,
unsigned
int code,
int value)
/*提交絕對位移事件*/
void input_report_abs(
struct input_dev
*dev,
unsigned
int code,
int value)
/*提交同步類事件,每上報完一次事件後,都必需要上報一個同步事件*/
void input_sync(
struct input_dev
*dev)
/*分配一個input_dev結構體*/
struct input_dev
*input_allocate_device(
void)
/*設置input_dev,設置它能產生哪類事件,設置它能產生哪些*/
方法一
:BIT_MASK(事件類型) 事件類型都在
:linux
/input.h
例如
:
ts.input
-
>evbit[
0]
= BIT_MASK(EV_KEY)
| BIT_MASK(EV_ABS);
ts.input
-
>keybit[BIT_WORD(BTN_TOUCH)]
= BIT_MASK(BTN_TOUCH);
方法二
:set_bit
例如
:
set_bit(EV_KEY,ts.input
-
>evbit);
set_bit(EV_ABS,ts.input
-
>evbit);
set_bit(BIN_TOUCH,ts.input
-
>keybit);
【input子系統框架】
【input子系統框架完整版】
@成鵬致遠async
(email:wwwlllll@126.com)函數
(qq:552158509)spa