Linux红外遥控驱动HS0038
生活随笔
收集整理的這篇文章主要介紹了
Linux红外遥控驱动HS0038
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
測試平臺imx6q linux5.4.215
華為電信高清IPTV遙控器
使用其它遙控器可以更改key_table和user_id
#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/sched.h> #include <linux/pm.h> #include <linux/slab.h> #include <linux/sysctl.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/input.h> #include <linux/gpio_keys.h> #include <linux/workqueue.h> #include <linux/gpio.h> #include <asm/io.h> #include <linux/jiffies.h> #include <asm/irq.h>#define DEVICE_DEBUG //undefine DEVICE_DEBUGstruct key_table_t{unsigned char key_val;unsigned char key_code;unsigned char key_name[20]; };struct key_table_t key_table[]={{0xF2, KEY_POWER, "POWER" }, //1{0xDC, KEY_SLEEP, "SLEEP" },{0xF3, KEY_LEFTMETA, "TV+" },{0xF4, KEY_RIGHTMETA, "TV-" },{0xF1, KEY_MEDIA, "TV/IPTV" },{0x98, KEY_SOUND, "VOL CANCEL" }, //6{0x9C, KEY_MUTE, "MUTE" },{0x8D, KEY_SETUP, "SETUP" },{0xD6, KEY_ROTATE_DISPLAY, "ROTATE_DISPLAY"},{0x91, KEY_CHAT, "LOOK BACK" },{0xCD, KEY_LINEFEED, "LIVE" }, //11{0x83, KEY_PLAYCD, "Request Play" },{0xC3, KEY_HELP, "INFO/HELP" },{0x88, KEY_HOME, "DESKTOP" },{0x82, KEY_MENU, "MENU" },{0xCA, KEY_UP, "UP" }, //16 {0xD2, KEY_DOWN, "DOWN" },{0x99, KEY_LEFT, "LEFT" },{0xC1, KEY_RIGHT, "RIGHT" },{0xCE, KEY_ENTER, "ENTER" },{0x80, KEY_VOLUMEUP, "VOLUME+" }, //21{0x81, KEY_VOLUMEDOWN, "VOLUME-" },{0xDD, KEY_PAGEUP, "PAGE UP" },{0x8C, KEY_PAGEDOWN, "PAGE DOWN" },{0x85, KEY_LEFTSHIFT, "CHANEL+" },{0x86, KEY_RIGHTSHIFT, "CHANEL-" }, //26{0x92, KEY_1, "Num:1" },{0x93, KEY_2, "Num:2" },{0xCC, KEY_3, "Num:3" },{0x8E, KEY_4, "Num:4" },{0x8F, KEY_5, "Num:5" }, //31{0xC8, KEY_6, "Num:6" },{0x8A, KEY_7, "Num:7" },{0x8B, KEY_8, "Num:8" },{0xC4, KEY_9, "Num:9" },{0x87, KEY_0, "Num:0" }, //36{0xDA, KEY_SEARCH, "*" },{0xD0, KEY_INSERT, "#" },{0x95, KEY_PLAYPAUSE, "PLAY/PAUSE" },{0xC5, KEY_BACK, "BACK" }, }; #define KEY_NUM sizeof(key_table)/sizeof(key_table[0])struct ir_key_info_t{unsigned char user_id;unsigned int key_num;struct key_table_t *key_data; };static struct ir_key_info_t ir_remote_keycode ={.user_id = 0xB2,.key_num = KEY_NUM,.key_data = key_table, };struct remote_ctrl{struct input_dev *input;struct gpio_keys_button *button;unsigned int keycode[KEY_NUM];spinlock_t lock;struct work_struct work; }; // IR timing /* │ │ │ │ │ │* │ 9ms │ 4.5ms │ │560us│ 1690us │ │ 560us│ 560us│* │<-----1350us---->│ │<-------2250us------->│ │<--1120us--->│*ˉˉˉ│_________│ˉˉˉˉˉˉˉ│_..._│_____│ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ│_..._│______│ˉˉˉˉˉˉ│__...* │-----------------│-----│----------------------│ │-------------│----* │---IR start up---│ │ Logic:1 │ │ Logic:0 │*/static int __inline ir_bus_startup_timing(int pin){int i;i = 0;while(1){if( 0 == ( (gpio_get_value(pin)) & 1 ) ){udelay(900);if( i>9 )return -1;i++;} //wait bus release;elsebreak;}i = 0;while(1){//0 1 2 3 4if( 1 == ( (gpio_get_value(pin)) & 1 ) ){udelay(900);if(i>4) //5*900us + (program run time) > 4.5msreturn -1; //ir repect statusi++;}elsebreak; //ir nomoal status}return 0; }static u32 __inline__ ir_bus_read_byte(struct remote_ctrl *hs0038) {int j;//struct gpio_keys_button *button = hs0038->button;int ir_pin = hs0038->button->gpio;u32 tmp=0;for(j=1;j<=8;j++){ //每個字節(jié)8個bit的判斷while( ((gpio_get_value(ir_pin)) & 1 ) ==0 ); //等待上升沿udelay(900);if(((gpio_get_value(ir_pin)) & 1) ==1 ){udelay(900);tmp=tmp|0x80;if(j<8) tmp=tmp>>1;}elseif(j<8)tmp=tmp>>1;//如果是"0",則向右移一位,自動補"0"}return tmp; } static unsigned int get_key_table_id(unsigned int kv) {int id;for(id=0; id<KEY_NUM; id++){if(kv == key_table[id].key_val){if(KEY_NUM >= id)return id;}}return 0xFFFF; }static int hs0038_read_data(struct remote_ctrl *hs0038) {//struct gpio_keys_button *button;int ir_pin;u8 user_id,n_user_id = 0;u8 k_val,nk_val = 0;int id=0;ir_pin = hs0038->button->gpio;gpio_direction_input(ir_pin);if( 0 != ir_bus_startup_timing(ir_pin)){printk("unknow ir startup timing.\n");return -1;}user_id = ir_bus_read_byte(hs0038); //user id low byten_user_id= (ir_bus_read_byte(hs0038)); //user id high bytek_val = ir_bus_read_byte(hs0038); //user id low bytenk_val = (ir_bus_read_byte(hs0038)); //user id high byteif( k_val&nk_val || user_id&n_user_id){//dev_info(hs0038->input->dev, "ir dat check sum error.\n");printk("data error or repect operater.\n");}else{ #ifdef DEVICE_DEBUGprintk("hs0038 read-> [user id]:0x%2X, [~user id]:0x%2X, [kv]:0x%2X, [~kv]0x%2X.\n",user_id, n_user_id,k_val, nk_val); #endif}id = get_key_table_id(k_val);switch (user_id){case 0xB2:input_report_key(hs0038->input,key_table[id].key_code, 1); //report pressinput_report_key(hs0038->input,key_table[id].key_code, 0); //report releaseinput_sync(hs0038->input); #ifdef DEVICE_DEBUGprintk("val=0x%2X, code=0x%2X, remote name:%s.\n",key_table[id].key_val,key_table[id].key_code,key_table[id].key_name); #endifbreak;default ://dev_info(hs0038->input->dev, "Unkonw ir remote button.\n");return -1;break;}return 0; }void hs0038_do_work(struct work_struct *wk) { #if 0struct remote_ctrl *hs0038;hs0038 = container_of(wk, struct remote_ctrl, work);hs0038->button->irq = gpio_to_irq(hs0038->button->gpio);printk("do work\n");//hs0038_read(hs0038);irq_set_irq_type(hs0038->button->irq, IRQF_TRIGGER_FALLING);enable_irq(hs0038->button->irq); #endifstruct remote_ctrl *hs0038;//struct gpio_keys_button *button; //int irq;hs0038 = container_of(wk, struct remote_ctrl, work);//button = hs0038->button; //irq = gpio_to_irq(button->gpio);hs0038_read_data(hs0038);//irq_set_irq_type(irq, IRQF_TRIGGER_FALLING);enable_irq(hs0038->button->irq);}static irqreturn_t hs0038_irq_handler(int irq, void *dev_id) {struct remote_ctrl *hs0038 = dev_id;disable_irq_nosync(irq);schedule_work(&hs0038->work); //irq request function schedule, as follow INIT_WORKreturn IRQ_HANDLED; }static int hs0038_gpio_init(struct platform_device *pdev) {struct remote_ctrl *hs0038;struct gpio_keys_button *button;const char *desc; //description infoint ret;hs0038 = platform_get_drvdata(pdev);button = hs0038->button;desc = button->desc ? button->desc : "HS0038 IR Remote"; //if unset decription inforet = gpio_request_one(button->gpio, GPIOF_IN, desc);if (ret < 0) {dev_err(&pdev->dev, "Failed to request GPIO %d, error %d\n",button->gpio, ret);return ret;}ret = gpio_to_irq( button->gpio ); //gpio pin config as irq inputif (ret < 0){dev_err(&pdev->dev, "Unable to get irq id for GPIO %d,error %d\n",button->gpio, ret);goto fail;}else{hs0038->button->irq = ret;dev_info(&pdev->dev, "irq:%d.\n", hs0038->button->irq);}ret = request_irq( hs0038->button->irq, //irq idhs0038_irq_handler, //irq handler functionIRQF_TRIGGER_FALLING, //irq modehs0038->input->name, //device namehs0038 ); //dev id/priv dataif (ret){dev_err(&pdev->dev, "Unable to claim irq %d; error %d\n", hs0038->button->irq, ret);goto fail;}ret = gpio_direction_input(button->gpio);if (ret < 0){dev_err(&pdev->dev, "Failed to configure direction for GPIO %d , error %d\n",button->gpio, ret);goto fail;}return 0;fail:gpio_free(button->gpio);return ret; } #define IMX_GPIO_NR(bank, nr) (((bank) - 1) * 32 + (nr)) static int hs0038_probe(struct platform_device *pdev) {int ret=0, i=0;struct device *dev = &pdev->dev;struct remote_ctrl *hs0038=NULL;dev_info(dev, "Remote cotrol probe.\n");hs0038 = kzalloc(sizeof(struct remote_ctrl),GFP_KERNEL);hs0038 ->button = kzalloc(sizeof(struct gpio_keys_button),GFP_KERNEL);platform_set_drvdata(pdev, hs0038);hs0038->input = input_allocate_device();if (!hs0038->input || !hs0038){dev_err(dev, "Failed to allocate state\n");ret= -ENOMEM;goto err_free_mem;}hs0038->input->name = "HS0038 IR Remote control";hs0038->input->phys = "hs0038/input1";hs0038->input->id.bustype = BUS_HOST;hs0038->input->id.vendor = 0xabce;hs0038->input->id.product = 0xecba;hs0038->input->id.version = 0x0100;hs0038->input->evbit[0] = BIT(EV_KEY);hs0038->input->keycode = hs0038->keycode;hs0038->input->keycodesize = sizeof(unsigned int);hs0038->input->keycodemax = KEY_NUM;set_bit(EV_KEY, hs0038->input->evbit);for (i = 0; i < KEY_NUM; i++){hs0038->keycode[i]= ir_remote_keycode.key_data[i].key_code;set_bit(hs0038->keycode[i], hs0038->input->keybit);}INIT_WORK(&hs0038->work, hs0038_do_work); //dcspin_lock_init(&hs0038->lock);hs0038->button->gpio = IMX_GPIO_NR(1, 6);hs0038->button->desc = "HS0038 IR Remote";ret=hs0038_gpio_init(pdev);if(ret)goto err_gpio_free;ret = input_register_device(hs0038->input);if (ret < 0){dev_err(dev,"probe input device register failed.\n");goto err_input_free;}return 0;err_input_free:input_free_device(hs0038->input);err_gpio_free:gpio_free(hs0038->button->gpio);err_free_mem:kfree(hs0038->input);kfree(hs0038->button);kfree(hs0038);return ret; } static int hs0038_remove(struct platform_device *pdev) {struct device *dev = &pdev->dev;struct remote_ctrl *hs0038;hs0038 = platform_get_drvdata(pdev);dev_info(dev, "Remote cotrol remove.\n");input_unregister_device(hs0038->input);//input_free_device(hs0038->input);free_irq(hs0038->button->irq, hs0038);gpio_free(hs0038->button->gpio);kfree(hs0038->input);kfree(hs0038->button);kfree(hs0038);return 0; }static const struct of_device_id hs0038_of_match[] = {{ .compatible = "hs0038", },{ }, };static struct platform_driver hs0038_driver = {.probe = hs0038_probe,.remove = hs0038_remove,.driver = {.name = "IR Remote",.owner = THIS_MODULE,.of_match_table = of_match_ptr(hs0038_of_match),}, }; static int __init hs0038_init(void) {return platform_driver_register(&hs0038_driver); }static void __exit hs0038_exit(void) {platform_driver_unregister(&hs0038_driver); }module_init(hs0038_init); module_exit(hs0038_exit);MODULE_AUTHOR("YuanBin"); MODULE_DESCRIPTION("GPIO IR Remote Driver"); MODULE_LICENSE("GPL");總結
以上是生活随笔為你收集整理的Linux红外遥控驱动HS0038的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: servlet+ajax在线生成二维码
- 下一篇: 野火 STM32 F103 指南者LED