RK 3066リモコンデバッグプロセス

10867 ワード

RK 3066リモコンフロー
1.まず構成されたドライバを見てみましょう
	#vi kernel/.config
	CONFIG_RECKCHIP_REMOTECTL=y
	CONFIG_RK_REMOTECTL=y
2.上記のオプションが構成されているプロファイルを検索すると、ドライバのソースがわかります.
	#vi kernel/drivers/input/remotectl/Kconfig
	menuconfig ROCKCHIP_REMOTECTL
		bool "rkxx remotectl"
		default y
		help
			...
	if ROCKCHIP_REMOTECTL
	config RK_REMOTECTL
		bool "rkxx remotectl"
		default y
	...
	endif
#vi kernel/drivers/input/remotectl/Makefile
	obj-$(CONFIG_RK_REMOTECTL) += rkxx_remotectl.o
RK_が構成されている場合はREMOTECTLがyであればrkxx_remotectl.oカーネルを入れて、このrkxx_remotectl.oはrkxx_に対応するremotectl.cファイル
3.分析ソースプログラム
#vi kernel/drivers/input/remotectl/rkxx_remotectl.c
	static int __devinit remotectl_probe(struc platform_device *pdev)
	{
		struct RKxx_remotectl_platform_data *pdata;	//             
		pdata = pdev->dev.platform_data;
		struc rkxx_remotectl_drvdata *ddata;	//          ,        ,   ,        
		...
		ddata = kzalloc(sizeof(struct rkxx_remotectl_drvdata),GFP_KERNEL);	//                 
		memset(ddata, 0, sizeof(struct rkxx_remotectl_drvdata));	//    ,   “ ”  
		
		ddata->state = RMC_PRELAOD;	//       ,   typedef enum _RMC_STATE{RMC_IDLE,RMC_PRELOAD,RMC_USERCODE,RMC_GETDATA,RMC_SEQUENCE}eRMC_STATE      
		input = input_allocate_device();	//        。  input_free_device,        
		
		platform_set_drvdata(pdev,ddata);	//      ,              
		
		//           
		input->name = pdev->name;
		input->phys = "gpio-keys/input0";
		input->dev.parent = &pdev->dev;
		input->id.bustype = BUS_HOST;
		input->id.vendor = 0x0001;
		input->id.product = 0x0001;
		input->id.version = 0x0100;
		
		if(pdata->rep)	//            
			__set_bit(EV_REP, input->evbit);	//  Linux          (Enable auto repeat feature of Linux input subsystem)
		
		ddata->input = input;	//   input    input
		wake_lock_init(&ddata->remotectl_wake_lock, WAKE_LOCK_SUSPEND,"rk29_remote");	//                   ,                ,          。
		...
		error = gpio_request(pdata->gpio, "remotectl");	//  gpio         ,     GPIO(These"optonal" allocation calls help prevent drivers from stomping on each other, and help provide better diagnostics debugfs. They're called even less than the "set direction" call)
		...error  ,goto fail1;
		error = gpio_direction_input(pdata->gpio);	//(Drivers Must set GPIO directoin before making get/set calls. In some cases this is done in early boot, befor IRQs are enabled.)
		...error  ,goto fail1;
		irq = gpio_to_irq(pdata->gpio);	//(return the IRQ corresponding to a GPIO,@gpio whose IRQ will be return{already requested})
		...error  ,goto fail1;
		error = request_irq(irq, remotectl_isr,IRQF_TRIGGER_FALLING,"remotectl",ddata);	//    
		...error  ,goto fail1;
		
		setup_timer(&ddata->timer, remotectl_timer, (unsigned long)ddata;	//     ,     remotectl_timer
		tasklet_init(&ddata->remote_tasklet, remotectl_do_something, (unsigned long)ddata);	//     tasklet,     remotectl_do_something
		/*
		        struct input_event      ,                    
		struct input_event {
		         structtimeval time;   //      
		         __u16type;            //    
		         __u16code;            //    
		         __s32value;           //   
		};
		
		    ,   linux/input.h 
		#define EV_SYN          0x00    //           
		#define EV_KEY          0x01    //      ,      
		#define EV_REL          0x02    //    ,             
		#define EV_ABS          0x03    //       ,         
		#define EV_MSC          0x04    //    
		#define EV_LED          0x11    //LED   
		#define EV_SND          0x12    //   ,    
		#define EV_REP          0x14    //        
		#define EV_PWR          0x16    //       
		
		    ,               
		EV_KEY                                KEY_1,KEY_2,KEY_3…
		EV_REL                                REL_X,REL_Y, REL_Z…  
		EV_ABS                                ABS_X,ABS_Y, ABS_Z…
		   ,          ,            GPIO     (       ),    0,    1
		*/
		for(j = 0; j < sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button); j++){
			for(i = 0; i < remotectl_button[j].nbuttons; i++){
				unsigned int type = EV_KEY;
				input_set_capability(input, type, remotectl_button[j].key_table[i].keyCode);	//         :    ,  keyCode  
				//input_set_capability   :
				/*
				//         (      )
          set_bit(EV_KEY, input->evbit);
				//         (    1 set_bit(KEY_1, input->keybit);)	
          set_bit(remotectl_button[j].key_table[i].keyCode, input->keybit);
				*/
			}
		}
		
		error = input_register_device(input);	//      ,   input       
		//error  
		input_set_capability(input, EV_KEY, KEY_WAKEUP);	//         :    
		device_init_wakeup(&pdev->dev, 1);
		
		return 0;
		fail*:
			//    
	}
	
	static struct platform_driver remotectl_device_driver = {
		.probe = remotectl_probe,	//            ,                  
		.remove = __devexit_p(remotectl_remove),
		.driver = {
			.name = "rkxx-remotectl",
			.owner = THIS_MODULE,
	#ifdef CONFIG_PM
		.pm = &remotectl_pm_ops,	//           
	#endif
		}
	}
	
	static int remotectl_init(void)	//     
	{
		return platform_driver_register(&remotectl_device_driver);
	}
	
	static int remotectl_exit(void)	//    
	{
		return platform_driver_unregister(&remotectl_device_driver);
	}
	
	module_init(remotectl_init);
	module_exit(remotectl_exit);
	MODULE_DESCRIPTION("Keyboard driver for CUP GPIOs");	//    GPIO    
	
	       ,                  ,        ,             input_report_key,            ,  :
	     
	void input_report_key(struct input_dev *dev, unsigned int code, int value)
	
	      
	void input_report_rel(struct input_dev *dev, unsigned int code, int value)
	
	      
	void input_report_abs(struct input_dev *dev, unsigned int code, int value)
	
	       ,      
	void input_sync(struct input_dev *dev)
	
	     Input_event   
	void input_event(struct input_dev *dev,unsigned int type, unsigned int code, intvalue)
	
	input_report_key  :
	static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
	{
		input_event(dev,EV_KEY, code, !!value);	//!!value   value  0 1,      
	}
	
	            ,        ,        ,                                  。
	
	static irqreturn_t remotectl_isr(int irq, void *dev_id)
	{
		...
		ddata->period = ddata->cur_time - ddata->pre_time;	//      
		//  &ddata->remote_tasklet,   tasklet       remotectl_do_something
		tasklet_hi_schedule(&ddata->remote_tasklet);	//tasklet_schedule()   tasklet_hi_schedule()         CPU        TASKLET_SOFTIRQ HI_SOFTIRQ,     tasklet    CPU    tasklet        。tasklet_hi_schedule()        
		if((ddata->state == RMC_PRELOAD) || (ddata->state == RMC_SEQUENCE))
			mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(130));	// 130               
	}
	
	static void remotectl_do_something(unsigned long data)
	{
		/*           
		RMC_PRELOAD -> RMC_USERCODE -> RMC_GETDATA ( -> RMC_SEQUENCE             ,            )
		*/
		struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata *)data;
		switch(ddata->state)
		{
			case RMC_IDLE:
				break;
			case RMC_PRELOAD:
				//#define TIME_PRE_MIN 13000
				//#define TIME_PRE_MAX 14000
				if((TIME_PRE_MIN < ddata->period) && (ddata->period < TIME_PRE_MAX)){	//       period   ,          ,               RMC_USERCODE
					ddata->scanData = 0;
					ddata->count = 0;
					ddata->state = RMC_USERCODE;
				}else{
					ddata-> state = RMC_PRELOAD;
				}
				ddata->pre_time = ddata->cur_time;
				break;
			case RMC_USERCODE:
				ddata->scanData <<= 1;	//  scanData,              ,      spec            ,                
				ddata->count++;	//  usercode 16bit ,   count  ,   0x10          usercode
				if((TIME_BIT1_MIN < ddata->preiod) && (ddata->preiod < TIME_BIT1_MAN)){
					ddata->scanData |= 0x01;	//  spec   scanData  
				}
				if(ddata->count == 0x10){	16bit usercode
					if(remotectl_keybdNum_lookup(ddata){	//     usercode       
						ddata->state = RMC_GETDATA;
						ddata->scanData = 0;
						ddata->count = 0;
					}else{
						ddata->state = 	RMC_PRELOAD;
					}
				}
				break;
			case RMC_GETDATA:
				ddata->count++;
				ddata->scanData <<=1;
				if((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){
					ddata->scanData |= 0x01;
				}
				if(ddata->count == 0x10){
					if((ddata->scanData&0x0ff) == ((!ddata->scanData >> 8)&0x0ff)){	//&0x0ff   8 
						if(remotectl_keycode_lookup(ddata)){
							ddata->press = 1;
							if(get_suspend_state() == 0){	//        ,        
								input_event(ddata->input, EV_KEY, ddata->keycode, 1);
								input_sync(ddata->input);
							}else if((get_suspend_state()) && (ddata->keycode==KEY_POWER)){	//         ,        KEY_POWER,   KEY_WAKEUP     (                )
								input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);
								input_sync(ddata->input);
							}
							ddata-> state = RMC_SEQUENCE;
						}else{
							ddata->state = RMC_PRELOAD;
						}
					}
				}
				break;
			case RMC_SEQUENCE:
				if((TIME_RPT_MIN < ddata->period) && (ddata->period < TIME_RPT_MAX)){
					;
				}else if((TIME_SEQ_MIN < ddata->period) && (ddata->period < TIME_SEQ_MAX)){
					if(ddata->press == 1){
						ddata->press = 3;
					}else if(ddata->press & 0x2){
						ddata->press = 2;
					}
				}
			default:
			
		}
	}
	
	    ,            ,          ,         ,     
	        ,          130               
	static void remotectl_timer(unsigned long data)
	{
		struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)__data;
		if(ddata->press != ddata->pre_press){
			ddata->pre_press = ddata->press = 0;
			if(get_suspend_state() == 0){
				input_event(ddata->input, EV_KEY, ddata->keycode, 0);
				input_sync(ddata->input);
			}else if((get_suspend_state()) && (ddata->keycode == KEY_POWER)){
				input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0);
				input_sync(ddata->input);
			}
		}
	}
注意:logを見ると、リモコンがbitを1つ報告するたびに割り込みが発生し、報告順序やルールについてはNECプロトコルの原理を参照することができます.(1つお勧め:http://download.csdn.net/detail/lijinwei_123/5698249)
デバッグ中に発生した問題:
1.リモコンは操作されていないが、駆動表示に割り込みが発生している
与えられたusercodeコードとキー値の対応関係を押して、そのマッピングと関連するlogを増やした後、コンパイル-録画して、正常にキーに応答できないことを発見して、logを見てUSERCODEに入っていないことを知って、観察して、意外にもリモコンを操作していないで、中断しても報告します.これは基本的にハードウェアの原因であると判断できる.プレートを交換してください.
2.コードから読み出されたデータとリモコンメーカーから提供された値は、ちょうど逆シーケンスです
リモコンメーカーはこれが正常だと言っています.私たちが提供したコード値のため、彼らのソフトウェアは逆シーケンスで発行されます.修正したいなら、逆シーケンスのコード値を直接提供すればいいです.リモコンの報告値に基づいて駆動で対応すればいいです.