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
便可以看到解析信息。