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

    便可以看到解析信息。


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