IR driver分析
1、相關代碼
(1)相關代碼位置
/drivers/media/rc
(2)kconfig文件分析
根據kconfig文件語法說迷,可以分析得到目錄代碼裏
config RC_CORE 是被核心依賴的
If RC_DECODERS對應框架驅動
config LIRC 是lirc驅動
config IR_LIRC_CODEC是LIRC解碼程序,且依賴LIRC
config IR_NEC_DECODER 是別的解碼程序,不依賴LIRC,可以獨立配合RC_CORE工作
config IR_SONY_DECODER 類似。。
menuconfig RC_DEVICES
bool"Remote Controller devices"
dependson RC_CORE
If RC_DEVICES
configRC_ATI_REMOTE對應具體的設備驅動
(3)Makefile文件分析
根據config變量去Makefile尋找相關的文件,再配合kconfig中的描述,就可大概知道各個文件功能。
1 rc-core-objs :=rc-main.o ir-raw.o
2
3obj-y += keymaps/
4
5obj-$(CONFIG_RC_CORE) += rc-core.o
6obj-$(CONFIG_LIRC) += lirc_dev.o
7obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
8obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
9obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
10obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
11obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
12obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
13obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
14obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
15obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
16obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
17
18 #stand-alone IR receivers/transmitters
19obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
20obj-$(CONFIG_IR_IMON) += imon.o
21obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
22obj-$(CONFIG_IR_MCEUSB) += mceusb.o
23obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
24obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
25obj-$(CONFIG_IR_ENE) += ene_ir.o
26obj-$(CONFIG_IR_REDRAT3) += redrat3.o
27obj-$(CONFIG_IR_RX51) += ir-rx51.o
28obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
29obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
30obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
31obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
32obj-$(CONFIG_IR_IGUANA) += iguanair.o
33obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
34obj-$(CONFIG_RC_ST) += st_rc.o
35obj-$(CONFIG_IR_HISI) += lirc_serial.o
36obj-$(CONFIG_IR_IMG) += img-ir/
2、驅動框架分析
(1)rc-main.c文件分析
主要關注,初始化函數和註冊函數
int rc_register_device(struct rc_dev *dev)
1283 {
1284 static boolraw_init = false; /* raw decoders loaded? */
1285 struct rc_map*rc_map;
1286 const char *path;
1287 int rc, devno, attr= 0;
1333 dev->devno =devno;
1334 dev_set_name(&dev->dev, "rc%ld", dev->devno);
1335 dev_set_drvdata(&dev->dev, dev);
1336 rc =device_add(&dev->dev);
1337 if (rc)
1338 gotoout_unlock;
1339
1340 rc =ir_setkeytable(dev, rc_map);
1341 if (rc)
1342 goto out_dev;
1343
1344 dev->input_dev->dev.parent = &dev->dev;
1345 memcpy(&dev->input_dev->id, &dev->input_id,sizeof(dev->input_id));
1346 dev->input_dev->phys = dev->input_phys;
1347 dev->input_dev->name = dev->input_name;
1348
1349 /*input_register_device can call ir_open, so unlock mutex here */
1350 mutex_unlock(&dev->lock);
1351
1352 rc =input_register_device(dev->input_dev);//註冊一個了input_dev,用於後續上報key_event事件
if (dev->driver_type ==RC_DRIVER_IR_RAW) {
1384 /* Load rawdecoders, if they aren't already */
1385 if (!raw_init){
1386 IR_dprintk(1, "Loading raw decoders\n");
1387 ir_raw_init();
1388 raw_init =true;
1389 }
1390 rc= ir_raw_event_register(dev); //註冊raw_event處理
1391 if (rc < 0)
1392 gotoout_input;
1393 }
1394
(2)ir-raw文件分析
intir_raw_event_register(struct rc_dev *dev)
247 {
248 int rc;
249 structir_raw_handler *handler;
250
251 if (!dev)
252 return -EINVAL;
253
254 dev->raw =kzalloc(sizeof(*dev->raw), GFP_KERNEL);
255 if (!dev->raw)
256 return -ENOMEM;
257
258 dev->raw->dev= dev;
259 rc_set_enabled_protocols(dev, ~0);
260 rc =kfifo_alloc(&dev->raw->kfifo,
261 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
262 GFP_KERNEL);
263 if (rc < 0)
264 goto out;
265
266 spin_lock_init(&dev->raw->lock);
267 dev->raw->thread= kthread_run(ir_raw_event_thread, dev->raw, //爲每個rc_device開啓一個線程
268 "rc%ld", dev->devno);
269
270 if(IS_ERR(dev->raw->thread)) {
271 rc =PTR_ERR(dev->raw->thread);
272 goto out;
273 }
274
275 mutex_lock(&ir_raw_handler_lock);
276 list_add_tail(&dev->raw->list, &ir_raw_client_list);
277 list_for_each_entry(handler, &ir_raw_handler_list, list)//這裏的handler_list保存的全是各種decoder算法,如lirc_codec,sony_decoder....
278 if(handler->raw_register)
279 handler->raw_register(dev);//目前只有lirc_codec提供了raw_register,主要完成裏到lirc_dev驅動的關聯。
線程裏面把rc_dev裏面的ir_raw_event_ctrl結構體中的fifo數據取出來,供解碼算法使用。
static intir_raw_event_thread(void *data)
35 {
36 struct ir_raw_eventev;
37 structir_raw_handler *handler;
38 structir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
39 int retval;
40
41 while(!kthread_should_stop()) {
42
43 spin_lock_irq(&raw->lock);
44 retval =kfifo_len(&raw->kfifo);
45
46 if (retval <sizeof(ev)) {
47 set_current_state(TASK_INTERRUPTIBLE);
48
49 if(kthread_should_stop())
50 set_current_state(TASK_RUNNING);
51
52 spin_unlock_irq(&raw->lock);
53 schedule();
54 continue;
55 }
56
57 retval =kfifo_out(&raw->kfifo, &ev, sizeof(ev));
58 spin_unlock_irq(&raw->lock);
59
60 mutex_lock(&ir_raw_handler_lock);
61 list_for_each_entry(handler, &ir_raw_handler_list, list)
62 handler->decode(raw->dev, ev);
63 raw->prev_ev= ev;
64 mutex_unlock(&ir_raw_handler_lock);
65 }
66
//sony算法如果能解碼直接上報掃描碼。
static intir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
43 {
44 struct sony_dec *data= &dev->raw->sony;
45 u32 scancode;
46 u8 device,subdevice, function;
。。。。
47
158 scancode =device << 16 | subdevice << 8 | function;
159 IR_dprintk(1,"Sony(%u) scancode 0x%05x\n", data->count, scancode);
160 rc_keydown(dev,scancode, 0);
161 data->state =STATE_INACTIVE;
}
//lirc_codec如果能解碼,則存儲到lirc.drv->rbuf裏面去了。
static intir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
34 {
35 struct lirc_codec*lirc = &dev->raw->lirc;
36 int sample;
37
94
95 lirc_buffer_write(dev->raw->lirc.drv->rbuf,
96 (unsigned char *) &sample);
97 wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
}
而lirc.drv會被註冊關聯到lirc_dev.
static intir_lirc_register(struct rc_dev *dev)
{
drv->minor = -1;
379 drv->features =features;
380 drv->data =&dev->raw->lirc;
381 drv->rbuf =rbuf;
382 drv->set_use_inc= &ir_lirc_open;
383 drv->set_use_dec= &ir_lirc_close;
384 drv->code_length= sizeof(struct ir_raw_event) * 8;
385 drv->fops =&lirc_fops;
386 drv->dev =&dev->dev;
387 drv->rdev = dev;
388 drv->owner =THIS_MODULE;
389
390 drv->minor = lirc_register_driver(drv); //註冊到lirc_dev,最終通過lirc_dev註冊字符設備,供用戶空間使用
391 if (drv->minor <0) {
392 rc = -ENODEV;
393 gotolirc_register_failed;
394 }
395
396 dev->raw->lirc.drv= drv;
397 dev->raw->lirc.dev= dev;
398 return 0;
}
因此,對於類似sony,nec等解碼算法,若能解碼直接通過input_dev上報sancode事件。而lirc_codec則需要再把原始數據處理後共lirc_dev使用,後者註冊了dev設備,cdev設備,可以共用戶空間訪問。
3、具體驅動實現st_rc.c
具體驅動主要通過中斷往raw->fifo裏面填充脈衝原始數據,並支持一般的fops操作。
static irqreturn_tst_rc_rx_interrupt(int irq, void *data)
97 {
98 unsigned int symbol,mark = 0;
99 struct st_rc_device*dev = data;
100 int last_symbol =0;
101 u32 status;
102 DEFINE_IR_RAW_EVENT(ev);
ev.duration =US_TO_NS(mark);
137 ev.pulse =true;
138 ir_raw_event_store(dev->rdev, &ev);
}
探測函數裏面完成資源獲取以及驅動註冊,註冊到rc_dev,rc_dev會分配ir_raw_event_ctrl *raw結構體,從而分配fifo內存,供具體設備中斷髮生時,往fifo填raw_event.
static intst_rc_probe(struct platform_device *pdev)
220 {
221 int ret = -EINVAL;
222 struct rc_dev*rdev;
223 struct device *dev =&pdev->dev;
224 struct resource*res;
225 struct st_rc_device*rc_dev;
226 struct device_node*np = pdev->dev.of_node;
227 const char*rx_mode;
228
229 rc_dev =devm_kzalloc(dev, sizeof(struct st_rc_device), GFP_KERNEL);
230
231 if (!rc_dev)
232 return -ENOMEM;
233
234 rdev =rc_allocate_device();
235
4、測試方案
-
對於具體一個遙控器,若不清楚對應的解碼協議,通過加載所有的協議算法,對debug信息進行分析,看哪一個能正確解碼。
-
對於lirc,需要去網站下載並編譯lirc可執行程序,並選擇一個通用的lirc.conf文件進行配置
./lirc –device=/dev/lirc0
./irw
便可以看到解析信息。