Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the infrared driver of Linux?

2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "what is the infrared driver of Linux". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the infrared driver of Linux".

Infrared remote control is a kind of wireless transceiver equipment that we often see, such as TV remote control, air-conditioning remote control, now some TV remote control has gradually become Bluetooth devices. Yesterday I saw someone ask a question in the knowledge Planet. Today I'm going to parse a driver written by a netizen.

Several details need to be paid attention to in debugging infrared.

1. The remote control we launch is invisible to the naked eye and needs to be observed by a camera.

2. The infrared receiver tube is different from the ordinary diode, and it will not work if you use the wrong material.

The principle of wireless data transmission of 1.NEC protocol the characteristics of NEC protocol:

1, 8-bit address and 8-bit instruction length

2. Address and command are transmitted twice; (ensure reliability)

3. PWM pulse width modulation, in which the duty cycle of the transmitted infrared carrier represents "0" and "1".

4. The carrier frequency is 38KHz

5. Bit time is 1.125ms and 2.25ms

The definition of NEC code point: a pulse corresponds to the continuous carrier of 560us, a logic 1 transmission requires 2.25ms (560us pulse + 1680us low level), and a logic 0 transmission requires 1.125ms (560us pulse + 560us low level).

While the remote control receiver is low when receiving the pulse and high when not receiving the pulse, so the signal we receive at the receiving head is: logic 1 should be 560us low + 1680us high, logic 0 should be 560us low + 560us high.

As shown below:

Hardware

2. Driver receiver under Linux

Refer to the original text:

Https://blog.csdn.net/wllw7176/article/details/110506677

Two driver files

Gpio-ir-recv.c / * Copyright (c) 2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * / # include # define GPIO_IR_DRIVER_NAME "gpio-rc-recv" # define GPIO_IR_DEVICE_NAME "gpio_ir_recv" struct gpio_rc_dev {struct rc_dev * rcdev; int gpio_nr; bool active_low;} # ifdef CONFIG_OF / * * Translate OpenFirmware node properties into platform_data * / static int gpio_ir_recv_get_devtree_pdata (struct device * dev, struct gpio_ir_recv_platform_data * pdata) {struct device_node * np = dev- > of_node; enum of_gpio_flags flags; int gpio; gpio = of_get_gpio_flags (np, 0, & flags); if (gpio

< 0) { if (gpio != -EPROBE_DEFER) dev_err(dev, "Failed to get gpio flags (%d)\n", gpio); return gpio; } pdata->

Gpiogpio_nr = gpio; pdata- > active_low = (flags & OF_GPIO_ACTIVE_LOW); / * probe () takes care of map_name = = NULL or allowed_protos = = 0 * / pdata- > map_name = of_get_property (np, "linux,rc-map-name", NULL); pdata- > allowed_protos = 0; return 0 } static const struct of_device_id gpio_ir_recv_of_match [] = {{.clients = "gpio-ir-receiver",}, {},}; MODULE_DEVICE_TABLE (of, gpio_ir_recv_of_match) # else / *! CONFIG_OF * / # define gpio_ir_recv_get_devtree_pdata (dev, pdata) (- ENOSYS) # endif static irqreturn_t gpio_ir_recv_irq (int irq, void * dev_id) {struct gpio_rc_dev * gpio_dev = dev_id; int gval; int rc = 0; enum raw_event_type type = IR_SPACE; gval = gpio_get_value (gpio_dev- > gpio_nr); if (gval

< 0) goto err_get_value; if (gpio_dev->

Active_low) gval =! gval; if (gval = = 1) type = IR_PULSE; rc = ir_raw_event_store_edge (gpio_dev- > rcdev, type); if (rc

< 0) goto err_get_value; ir_raw_event_handle(gpio_dev->

Rcdev); err_get_value: return IRQ_HANDLED;} static int gpio_ir_recv_probe (struct platform_device * pdev) {struct gpio_rc_dev * gpio_dev; struct rc_dev * rcdev; const struct gpio_ir_recv_platform_data * pdata = pdev- > dev.platform_data; int rc If (pdev- > dev.of_node) {struct gpio_ir_recv_platform_data * dtpdata = devm_kzalloc (& pdev- > dev, sizeof (* dtpdata), GFP_KERNEL); if (! dtpdata) return-ENOMEM; rc = gpio_ir_recv_get_devtree_pdata (& pdev- > dev, dtpdata); if (rc) return rc; pdata = dtpdata;} if (! pdata) return-EINVAL; if (pdata- > gpio_nr)

< 0) return -EINVAL; gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL); if (!gpio_dev) return -ENOMEM; rcdev = rc_allocate_device(); if (!rcdev) { rc = -ENOMEM; goto err_allocate_device; } rcdev->

Priv = gpio_dev; rcdev- > driver_type = RC_DRIVER_IR_RAW; rcdev- > input_name = GPIO_IR_DEVICE_NAME; rcdev- > input_phys = GPIO_IR_DEVICE_NAME "/ input0"; rcdev- > input_id.bustype = BUS_HOST; rcdev- > input_id.vendor = 0x0001; rcdev- > input_id.product = 0x0001; rcdev- > input_id.version = 0x0100; rcdev- > dev.parent = & pdev- > dev; rcdev- > driver_name = GPIO_IR_DRIVER_NAME If (pdata- > allowed_protos) rcdev- > allowed_protocols = pdata- > allowed_protos; else rcdev- > allowed_protocols = RC_BIT_ALL; rcdev- > map_name = pdata- > map_name?: RC_MAP_EMPTY; gpio_dev- > rcdevrcdev = rcdev; gpio_dev- > gpio_nr = pdata- > gpio_nr; gpio_dev- > active_low = pdata- > active_low; rc = gpio_request (pdata- > gpio_nr, "gpio-ir-recv"); if (rc

< 0) goto err_gpio_request; rc = gpio_direction_input(pdata->

Gpio_nr); if (rc

< 0) goto err_gpio_direction_input; rc = rc_register_device(rcdev); if (rc < 0) { dev_err(&pdev->

Dev, "failed to register rc device\ n"); goto err_register_rc_device;} platform_set_drvdata (pdev, gpio_dev); rc = request_any_context_irq (gpio_to_irq (pdata- > gpio_nr), gpio_ir_recv_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "gpio-ir-recv-irq", gpio_dev); if (rc

< 0) goto err_request_irq; return 0; err_request_irq: rc_unregister_device(rcdev); rcdev = NULL; err_register_rc_device: err_gpio_direction_input: gpio_free(pdata->

Gpio_nr); err_gpio_request: rc_free_device (rcdev); err_allocate_device: kfree (gpio_dev); return rc;} static int gpio_ir_recv_remove (struct platform_device * pdev) {struct gpio_rc_dev * gpio_dev = platform_get_drvdata (pdev); free_irq (gpio_to_irq (gpio_dev- > gpio_nr), gpio_dev); rc_unregister_device (gpio_dev- > rcdev) Gpio_free (gpio_dev- > gpio_nr); kfree (gpio_dev); return 0;} # ifdef CONFIG_PM static int gpio_ir_recv_suspend (struct device * dev) {struct platform_device * pdev = to_platform_device (dev); struct gpio_rc_dev * gpio_dev = platform_get_drvdata (pdev); if (device_may_wakeup (dev)) enable_irq_wake (gpio_to_irq (gpio_dev- > gpio_nr)) Else disable_irq (gpio_to_irq (gpio_dev- > gpio_nr)); return 0;} static int gpio_ir_recv_resume (struct device * dev) {struct platform_device * pdev = to_platform_device (dev); struct gpio_rc_dev * gpio_dev = platform_get_drvdata (pdev); if (device_may_wakeup (dev)) disable_irq_wake (gpio_to_irq (gpio_dev- > gpio_nr)) Else enable_irq (gpio_to_irq (gpio_dev- > gpio_nr)); return 0;} static const struct dev_pm_ops gpio_ir_recv_pm_ops = {.clients = gpio_ir_recv_suspend, .clients = gpio_ir_recv_resume,} # endif static struct platform_driver gpio_ir_recv_driver = {.probe = gpio_ir_recv_probe, .remove = gpio_ir_recv_remove, .driver = {.name = GPIO_IR_DRIVER_NAME, .of _ match_table = of_match_ptr (gpio_ir_recv_of_match), # ifdef CONFIG_PM. Pm = & gpio_ir_recv_pm_ops, # endif},} Module_platform_driver (gpio_ir_recv_driver); MODULE_DESCRIPTION ("GPIO IR Receiver driver"); MODULE_LICENSE ("GPL v2")

Ir-nec-decoder.c

/ * ir-nec-decoder.c-handle NEC IR Pulse/Space protocol * * Copyright (C) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * / # include # include # include "rc-core-priv.h" # define NEC_NBITS 32 # define NEC_UNIT 562500 / * ns * / # define NEC_HEADER_PULSE (16 * NEC_UNIT) # define NECX_HEADER_PULSE (8 * NEC_UNIT) / * Less common NEC variant * / # define NEC_HEADER_SPACE (8 * NEC_UNIT) # define NEC_REPEAT_SPACE (4 * NEC_UNIT) # define NEC_BIT_PULSE (1 * NEC_UNIT) # define NEC_BIT_0_SPACE (1 * NEC_UNIT) # define NEC_BIT_1_SPACE (3 * NEC_UNIT) # define NEC_TRAILER_PULSE (1 * NEC_UNIT) # define NEC_TRAILER_SPACE (10 * NEC_UNIT) / * even longer in reality * / # define NECX_REPEAT_BITS 1 enum nec_state {STATE_INACTIVE STATE_HEADER_SPACE, STATE_BIT_PULSE, STATE_BIT_SPACE, STATE_TRAILER_PULSE, STATE_TRAILER_SPACE,} / * ir_nec_decode ()-Decode one NEC pulse or space * @ dev: the struct rc_dev descriptor of the device * @ duration: the struct ir_raw_event descriptor of the pulse/space * * This function returns-EINVAL if the pulse violates the state machine * / static int ir_nec_decode (struct rc_dev * dev, struct ir_raw_event ev) {struct nec_dec * data = & dev- > raw- > nec; U32 scancode U8 address, not_address, command, not_command; bool send_32bits = false; if (! (dev- > enabled_protocols & RC_BIT_NEC)) return 0; if (! is_timing_event (ev)) {if (ev.reset) data- > state = STATE_INACTIVE; return 0 } IR_dprintk (2, "NEC decode started at state% d (% uus% s)\ n", data- > state, TO_US (ev.duration), TO_STR (ev.pulse); switch (data- > state) {case STATE_INACTIVE: if (! ev.pulse) break; if (eq_margin (ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {data- > is_nec_x = false; data- > necx_repeat = false } else if (eq_margin (ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2)) data- > is_nec_x = true; else break; data- > count = 0; data- > state = STATE_HEADER_SPACE; return 0; case STATE_HEADER_SPACE: if (ev.pulse) break; if (eq_margin (ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {data- > state = STATE_BIT_PULSE Return 0;} else if (eq_margin (ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {if (! dev- > keypressed) {IR_dprintk (1, "Discarding last key repeat: event after key up\ n");} else {rc_repeat (dev); IR_dprintk (1, "Repeat last key\ n"); data- > state = STATE_TRAILER_PULSE;} return 0 } break; case STATE_BIT_PULSE: if (! ev.pulse) break; if (! eq_margin (ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2)) break; data- > state = STATE_BIT_SPACE; return 0; case STATE_BIT_SPACE: if (ev.pulse) break If (data- > necx_repeat & & data- > count = = NECX_REPEAT_BITS & & geq_margin (ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) {IR_dprintk (1, "Repeat last key\ n"); rc_repeat (dev); data- > state = STATE_INACTIVE; return 0;} else if (data- > count > NECX_REPEAT_BITS) data- > necx_repeat = false; data- > bits count++ If (data- > count = = NEC_NBITS) data- > state = STATE_TRAILER_PULSE; else data- > state = STATE_BIT_PULSE; return 0; case STATE_TRAILER_PULSE: if (! ev.pulse) break; if (! eq_margin (ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2)) break; data- > state = STATE_TRAILER_SPACE; return 0; case STATE_TRAILER_SPACE: if (ev.pulse) break If (! geq_margin (ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) break; address = bitrev8 ((data- > bits > > 24) & 0xff); not_address = bitrev8 ((data- > bits > > 16) & 0xff); command = bitrev8 (data- > bits > > 8) & 0xff); not_command = bitrev8 ((data- > bits > > 0) & 0xff) If ((command ^ not_command)! = 0xff) {IR_dprintk (1, "NEC checksum error: received 0xx\ n", data- > bits); send_32bits = true;} if (send_32bits) {/ * NEC transport, but modified protocol, used by at * least Apple and TiVo remotes * / scancode = data- > bits; IR_dprintk (1, "NEC (modified) scancode 0xx\ n", scancode) } else if ((address ^ not_address)! = 0xff) {/ * Extended NEC * / scancode = address state = STATE_INACTIVE; return 0;} IR_dprintk (1, "NEC decode failed at count% d state% d (% uus% s)\ n", data- > count, data- > state, TO_US (ev.duration), TO_STR (ev.pulse); data- > state = STATE_INACTIVE; return-EINVAL } static struct ir_raw_handler nec_handler = {.birthday = RC_BIT_NEC, .decode = ir_nec_decode,}; static int _ _ init ir_nec_decode_init (void) {ir_raw_handler_register (& nec_handler); printk (KERN_INFO "IR NEC protocol handler initialized\ n"); return 0;} static void _ exit ir_nec_decode_exit (void) {ir_raw_handler_unregister (& nec_handler) } module_init (ir_nec_decode_init); module_exit (ir_nec_decode_exit); MODULE_LICENSE ("GPL"); MODULE_AUTHOR ("Mauro Carvalho Chehab"); MODULE_AUTHOR ("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION (" NEC IR protocol decoder "))

Refer to the dts file in the article:

Gpio-ir-receiver {compatible = "gpio-ir-receiver"; gpios =; / connect the infrared interrupt pin active_low =; / / whether the infrared receiver reverses the signal, some infrared receivers will reverse the received high and low level signals, such as the hx1838 infrared receiver I use linux,rc-map-name = "rc-hx18380-carmp3" / / Infrared scancode and actual input_evnent code mapping table name, to be registered in rc_register_device, see gpio-ir-recv.c allowed_protos =; / * NEC protocol*/ reserved, which is not used in the driver}

Called in another file

Ir-nec-decoder.c

This function is the infrared processing application function in the Linux kernel

The main thing here is to register a decoded structure

Ir-nec-decoder.c

3. Interrupt handler parsing

Gpio-ir-recv.c

The ir_raw_event_store_edge () function is used to calculate the duration of the level.

Ir_raw_event_handle () is used to deal with what this level means.

In the driver, the first thing is to judge the current GPIO level, if it is low, enter the infrared resolution, if not, or fail to get, exit the program.

4. Analysis of Infrared data processing Program

The kernel has a special thread to handle data parsing.

Rc-ir-raw.c

In fact, the processing function is to process the level time to determine the digital signal.

Ir-nec-decoder.c

Here is the judgment head, this time is compared with 9ms

Where did 9ms come from? you can take a look at this.

Ir-nec-decoder.c

After getting the head, the switch function continues to run down.

Ir-nec-decoder.c

And then it's time to judge 1 and 0.

Ir-nec-decoder.c

The one at the top is 1 and the one at the bottom is 0.

4. And then how to report the data?

Ir-nec-decoder.c

Here is the mapping registered in another module

Different infrared key values correspond to different reported key values.

Rc-trekstor.c

Thank you for your reading, the above is the content of "what is the Linux infrared driver". After the study of this article, I believe you have a deeper understanding of what the Linux infrared driver is, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report