4. 遙控器裝置¶
4.1. 遙控器核心¶
遙控器核心實現了接收和傳送遙控器鍵盤按鍵和滑鼠事件的基礎設施。
每次按下遙控器上的按鍵時,都會產生一個掃描碼。此外,在大多數硬體上,持續按住一個按鍵超過幾十毫秒會產生一個重複按鍵事件。這有點類似於 Linux 內部處理普通鍵盤或滑鼠的方式[1]。因此,遙控器核心是在 Linux input/evdev 介面之上實現的。
然而,大多數遙控器使用紅外 (IR) 來傳輸訊號。由於有幾種協議用於調製紅外訊號,核心的一個重要部分專門用於調整驅動程式和核心繫統,以支援發射器使用的紅外協議。
紅外傳輸是透過使用載波閃爍紅外發射器來完成的。載波可以透過 IR 發射器硬體開啟或關閉。當載波開啟時,稱為脈衝。當載波關閉時,稱為空間。
換句話說,典型的紅外傳輸可以看作是一系列脈衝和空間事件,每個事件都有給定的持續時間。
載波引數(頻率、佔空比)以及脈衝和空間事件的間隔取決於協議。例如,NEC 協議使用 38kHz 的載波,傳輸以 9ms 脈衝和 4.5ms 空間開始。然後它傳輸 16 位掃描碼,其中 8 位用於地址(通常對於給定的遙控器來說是一個固定的數字),後跟 8 位程式碼。“1”位用 560µs 脈衝後跟 1690µs 空間調製,“0”位用 560µs 脈衝後跟 560µs 空間調製。
在接收器端,可以使用簡單的低通濾波器將接收到的訊號轉換為一系列脈衝/空間事件,從而濾除載波頻率。因此,接收器並不關心載波的實際頻率引數:它所要做的就是測量它接收到脈衝/空間事件的時間量。因此,一個簡單的 IR 接收器硬體將只向核心提供這些事件的時序序列。具有此類接收器的硬體的驅動程式由 RC_DRIVER_IR_RAW 標識,如 rc_driver_type[2] 中定義的那樣。其他硬體配備了一個微控制器,可以解碼脈衝/空間序列並將掃描碼返回給核心。這種接收器由 RC_DRIVER_SCANCODE 標識。
RC 核心還支援只有 IR 發射器而沒有任何接收器的裝置。目前,所有此類裝置僅在原始 TX 模式下工作。這種硬體被標識為 RC_DRIVER_IR_RAW_TX。
當 RC 核心接收到由 RC_DRIVER_IR_RAW IR 接收器產生的事件時,它需要解碼 IR 協議,以便獲得相應的掃描碼。RC 核心支援的協議在列舉 rc_proto 中定義。
當 RC 程式碼接收到掃描碼時(無論是直接透過 RC_DRIVER_SCANCODE 型別的驅動程式,還是透過其 IR 解碼器),它需要將其轉換為 Linux 輸入事件程式碼。這是透過對映表完成的。
核心支援大多數媒體裝置上可用的對映表。它還支援透過一些 sysfs 節點在執行時載入表。有關更多詳細資訊,請參見 RC 使用者空間 API。
4.1.1. 遙控器資料結構和函式¶
-
enum rc_driver_type¶
RC 驅動程式的型別。
常量
RC_DRIVER_SCANCODE驅動程式或硬體生成掃描碼。
RC_DRIVER_IR_RAW驅動程式或硬體生成脈衝/空間序列。它需要一個紅外脈衝/空間解碼器
RC_DRIVER_IR_RAW_TX僅裝置發射器,驅動程式需要脈衝/空間資料序列。
-
struct rc_scancode_filter¶
過濾掃描碼。
定義:
struct rc_scancode_filter {
u32 data;
u32 mask;
};
成員
data要匹配的掃描碼資料。
mask要比較的掃描碼位的掩碼。
-
enum rc_filter_type¶
過濾器型別常量。
常量
RC_FILTER_NORMAL用於正常操作的過濾器。
RC_FILTER_WAKEUP用於從掛起狀態喚醒的過濾器。
RC_FILTER_MAX過濾器型別的數量。
-
struct lirc_fh¶
表示一個開啟的 lirc 檔案
定義:
struct lirc_fh {
struct list_head list;
struct rc_dev *rc;
unsigned int *rawir;
struct lirc_scancode *scancodes;
wait_queue_head_t wait_poll;
u32 carrier_low;
u8 send_mode;
u8 rec_mode;
};
成員
list開啟的檔案控制代碼列表
rc此 lirc 字元裝置的 rcdev
rawir傳入原始 IR 的佇列
scancodes傳入解碼的掃描碼的佇列
wait_polllirc 裝置的輪詢結構
carrier_low設定載波範圍時,必須先使用 ioctl 設定低端,然後使用另一個 ioctl 設定高階
send_mode傳送的 lirc 模式,可以是 LIRC_MODE_SCANCODE 或 LIRC_MODE_PULSE
rec_mode接收的 lirc 模式,可以是 LIRC_MODE_SCANCODE 或 LIRC_MODE_MODE2
-
struct rc_dev¶
表示遙控裝置
定義:
struct rc_dev {
struct device dev;
bool managed_alloc;
bool registered;
bool idle;
bool encode_wakeup;
unsigned int minor;
const struct attribute_group *sysfs_groups[5];
const char *device_name;
const char *input_phys;
struct input_id input_id;
const char *driver_name;
const char *map_name;
struct rc_map rc_map;
struct mutex lock;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
enum rc_driver_type driver_type;
u32 users;
u64 allowed_protocols;
u64 enabled_protocols;
u64 allowed_wakeup_protocols;
enum rc_proto wakeup_protocol;
struct rc_scancode_filter scancode_filter;
struct rc_scancode_filter scancode_wakeup_filter;
u32 scancode_mask;
void *priv;
spinlock_t keylock;
bool keypressed;
u8 last_toggle;
u32 last_keycode;
enum rc_proto last_protocol;
u64 last_scancode;
unsigned long keyup_jiffies;
struct timer_list timer_keyup;
struct timer_list timer_repeat;
u32 timeout;
u32 min_timeout;
u32 max_timeout;
u32 rx_resolution;
#ifdef CONFIG_LIRC;
struct device lirc_dev;
struct cdev lirc_cdev;
ktime_t gap_start;
spinlock_t lirc_fh_lock;
struct list_head lirc_fh;
#endif;
int (*change_protocol)(struct rc_dev *dev, u64 *rc_proto);
int (*open)(struct rc_dev *dev);
void (*close)(struct rc_dev *dev);
int (*s_tx_mask)(struct rc_dev *dev, u32 mask);
int (*s_tx_carrier)(struct rc_dev *dev, u32 carrier);
int (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle);
int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max);
int (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n);
void (*s_idle)(struct rc_dev *dev, bool enable);
int (*s_wideband_receiver)(struct rc_dev *dev, int enable);
int (*s_carrier_report) (struct rc_dev *dev, int enable);
int (*s_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
int (*s_wakeup_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
int (*s_timeout)(struct rc_dev *dev, unsigned int timeout);
};
成員
dev驅動程式模型對此裝置的看法
managed_alloc使用 devm_rc_allocate_device 建立 rc_dev
registered由
rc_register_device()設定為 true,由 rc_unregister_device 設定為 falseidle用於跟蹤 RX 狀態
encode_wakeup喚醒過濾使用 IR 編碼 API,因此允許的喚醒協議是所有原始編碼器的集合
minor唯一的次要遙控裝置號
sysfs_groupssysfs 屬性組
device_namerc 子裝置的名稱
input_phys輸入子裝置的物理路徑
input_id輸入子裝置的 ID(結構 input_id)
driver_name註冊此裝置的硬體驅動程式的名稱
map_name預設鍵對映的名稱
rc_map當前掃描/按鍵表
lock用於確保我們在任何人呼叫 show_protocols 或 store_protocols 之前填寫了所有協議詳細資訊
raw原始脈衝/空間裝置的附加資料
input_dev用於將事件傳達給使用者空間的輸入子裝置
driver_type指定協議解碼是在硬體還是軟體中完成
users裝置的當前使用者數
allowed_protocols帶有支援的 RC_PROTO_BIT_* 協議的位掩碼
enabled_protocols帶有啟用的 RC_PROTO_BIT_* 協議的位掩碼
allowed_wakeup_protocols帶有支援的 RC_PROTO_BIT_* 喚醒協議的位掩碼
wakeup_protocol啟用的 RC_PROTO_* 喚醒協議,如果停用,則為 RC_PROTO_UNKNOWN。
scancode_filter掃描碼過濾器
scancode_wakeup_filter掃描碼喚醒過濾器
scancode_mask某些硬體解碼器無法嚮應用程式提供完整的掃描碼。由於這是一個硬體限制,我們對此無能為力。然而,由於相同的按鍵程式碼表可以與其他裝置一起使用,因此提供了一個掩碼以允許其使用。驅動程式通常應將此欄位留空
priv驅動程式特定資料
keylock保護結構的其餘成員
keypressed當前是否按下某個按鍵
last_toggle最後一個命令的切換值
last_keycode上次按鍵的按鍵程式碼
last_protocol上次按鍵的協議
last_scancode上次按鍵的掃描碼
keyup_jiffies應釋放當前按鍵的時間(以 jiffies 為單位)
timer_keyup用於釋放按鍵的計時器
timer_repeat用於自動重複事件的計時器。這是 CEC 所必需的,CEC 具有非標準重複。
timeout裝置停止傳送資料後的可選時間
min_timeout裝置支援的最小超時
max_timeout裝置支援的最大超時
rx_resolution輸入取樣器的解析度(以微秒為單位)
lirc_devlirc 裝置
lirc_cdevlirc 字元 cdev
gap_start如果非零,則超時後間隙的開始時間
lirc_fh_lock保護 lirc_fh 列表
lirc_fh開啟的檔案列表
change_protocol允許更改硬體解碼器上使用的協議
open允許驅動程式在開啟 IR 輸入裝置時啟用輪詢/irq 的回撥。
close允許驅動程式在開啟 IR 輸入裝置時停用輪詢/irq 的回撥。
s_tx_mask設定發射器掩碼(對於具有多個 tx 輸出的裝置)
s_tx_carrier設定發射載波頻率
s_tx_duty_cycle設定發射佔空比 (0% - 100%)
s_rx_carrier_range通知驅動程式它應該處理的載波
tx_ir傳輸紅外
s_idle啟用/停用硬體空閒模式,在此模式下,裝置不會中斷主機,直到它看到 IR 脈衝
s_wideband_receiver啟用用於學習的寬頻接收器
s_carrier_report啟用載波報告
s_filter設定掃描碼過濾器
s_wakeup_filter設定喚醒掃描碼過濾器。如果掩碼為零,則應停用喚醒。如果掩碼非零,則 wakeup_protocol 將設定為有效協議。
s_timeout以微秒為單位設定硬體超時
-
struct rc_dev *rc_allocate_device(enum rc_driver_type)¶
分配一個 RC 裝置
引數
enum rc_driver_type指定要分配的 RC 輸出型別,返回指向
struct rc_dev的指標。
-
struct rc_dev *devm_rc_allocate_device(struct device *dev, enum rc_driver_type)¶
託管 RC 裝置分配
引數
struct device *dev指向
struct device的指標enum rc_driver_type指定要分配的 RC 輸出型別,返回指向
struct rc_dev的指標。
引數
struct rc_dev *dev指向
struct rc_dev的指標。
引數
struct rc_dev *dev指向
struct rc_dev的指標。
引數
struct device *parent指向
struct device的指標。struct rc_dev *dev指向
struct rc_dev的指標。
引數
struct rc_dev *dev指向
struct rc_dev的指標。
-
struct rc_map_table¶
表示掃描碼/按鍵程式碼對
定義:
struct rc_map_table {
u64 scancode;
u32 keycode;
};
成員
scancode掃描碼 (u64)
keycodeLinux 輸入按鍵程式碼
-
struct rc_map¶
表示按鍵程式碼對映表
定義:
struct rc_map {
struct rc_map_table *scan;
unsigned int size;
unsigned int len;
unsigned int alloc;
enum rc_proto rc_proto;
const char *name;
spinlock_t lock;
};
成員
scan指向結構
rc_map_table的指標size最大條目數
len正在使用的條目數
alloc*scan 的大小(以位元組為單位)
rc_proto遙控器協議的型別,如列舉
rc_proto中定義name按鍵對映表的名稱
lock用於保護對此結構的訪問的鎖
定義:
struct rc_map_list {
struct list_head list;
struct rc_map map;
};
成員
list指向結構
list_head的指標map指向結構
rc_map的指標
-
int rc_map_register(struct rc_map_list *map)¶
註冊一個遙控器掃描碼對映
引數
struct rc_map_list *map指向
struct rc_map_list的指標
-
void rc_map_unregister(struct rc_map_list *map)¶
登出一個遙控器掃描碼對映
引數
struct rc_map_list *map指向
struct rc_map_list的指標
引數
const char *nameRC 掃描碼對映的名稱