linux ir驅動框架分析

IR driver分析

1、相關代碼

1)相關代碼位置

/drivers/media/rc

2kconfig文件分析

根據kconfig文件語法說迷,可以分析得到目錄代碼裏

config RC_CORE 是被核心依賴的

If RC_DECODERS對應框架驅動

config LIRC lirc驅動

config IR_LIRC_CODECLIRC解碼程序,且依賴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對應具體的設備驅動


3Makefile文件分析

根據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、驅動框架分析

1rc-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


2ir-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內存,供具體設備中斷髮生時,往fiforaw_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、測試方案

  1. 對於具體一個遙控器,若不清楚對應的解碼協議,通過加載所有的協議算法,對debug信息進行分析,看哪一個能正確解碼。

  2. 對於lirc,需要去網站下載並編譯lirc可執行程序,並選擇一個通用的lirc.conf文件進行配置

    ./lirc –device=/dev/lirc0

    ./irw

    便可以看到解析信息。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章