162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Remote Controller core header 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009-2010 by Mauro Carvalho Chehab 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _RC_CORE 962306a36Sopenharmony_ci#define _RC_CORE 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/spinlock.h> 1262306a36Sopenharmony_ci#include <linux/cdev.h> 1362306a36Sopenharmony_ci#include <linux/kfifo.h> 1462306a36Sopenharmony_ci#include <linux/time.h> 1562306a36Sopenharmony_ci#include <linux/timer.h> 1662306a36Sopenharmony_ci#include <media/rc-map.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/** 1962306a36Sopenharmony_ci * enum rc_driver_type - type of the RC driver. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * @RC_DRIVER_SCANCODE: Driver or hardware generates a scancode. 2262306a36Sopenharmony_ci * @RC_DRIVER_IR_RAW: Driver or hardware generates pulse/space sequences. 2362306a36Sopenharmony_ci * It needs a Infra-Red pulse/space decoder 2462306a36Sopenharmony_ci * @RC_DRIVER_IR_RAW_TX: Device transmitter only, 2562306a36Sopenharmony_ci * driver requires pulse/space data sequence. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cienum rc_driver_type { 2862306a36Sopenharmony_ci RC_DRIVER_SCANCODE = 0, 2962306a36Sopenharmony_ci RC_DRIVER_IR_RAW, 3062306a36Sopenharmony_ci RC_DRIVER_IR_RAW_TX, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/** 3462306a36Sopenharmony_ci * struct rc_scancode_filter - Filter scan codes. 3562306a36Sopenharmony_ci * @data: Scancode data to match. 3662306a36Sopenharmony_ci * @mask: Mask of bits of scancode to compare. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_cistruct rc_scancode_filter { 3962306a36Sopenharmony_ci u32 data; 4062306a36Sopenharmony_ci u32 mask; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * enum rc_filter_type - Filter type constants. 4562306a36Sopenharmony_ci * @RC_FILTER_NORMAL: Filter for normal operation. 4662306a36Sopenharmony_ci * @RC_FILTER_WAKEUP: Filter for waking from suspend. 4762306a36Sopenharmony_ci * @RC_FILTER_MAX: Number of filter types. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cienum rc_filter_type { 5062306a36Sopenharmony_ci RC_FILTER_NORMAL = 0, 5162306a36Sopenharmony_ci RC_FILTER_WAKEUP, 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci RC_FILTER_MAX 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/** 5762306a36Sopenharmony_ci * struct lirc_fh - represents an open lirc file 5862306a36Sopenharmony_ci * @list: list of open file handles 5962306a36Sopenharmony_ci * @rc: rcdev for this lirc chardev 6062306a36Sopenharmony_ci * @carrier_low: when setting the carrier range, first the low end must be 6162306a36Sopenharmony_ci * set with an ioctl and then the high end with another ioctl 6262306a36Sopenharmony_ci * @rawir: queue for incoming raw IR 6362306a36Sopenharmony_ci * @scancodes: queue for incoming decoded scancodes 6462306a36Sopenharmony_ci * @wait_poll: poll struct for lirc device 6562306a36Sopenharmony_ci * @send_mode: lirc mode for sending, either LIRC_MODE_SCANCODE or 6662306a36Sopenharmony_ci * LIRC_MODE_PULSE 6762306a36Sopenharmony_ci * @rec_mode: lirc mode for receiving, either LIRC_MODE_SCANCODE or 6862306a36Sopenharmony_ci * LIRC_MODE_MODE2 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistruct lirc_fh { 7162306a36Sopenharmony_ci struct list_head list; 7262306a36Sopenharmony_ci struct rc_dev *rc; 7362306a36Sopenharmony_ci int carrier_low; 7462306a36Sopenharmony_ci DECLARE_KFIFO_PTR(rawir, unsigned int); 7562306a36Sopenharmony_ci DECLARE_KFIFO_PTR(scancodes, struct lirc_scancode); 7662306a36Sopenharmony_ci wait_queue_head_t wait_poll; 7762306a36Sopenharmony_ci u8 send_mode; 7862306a36Sopenharmony_ci u8 rec_mode; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/** 8262306a36Sopenharmony_ci * struct rc_dev - represents a remote control device 8362306a36Sopenharmony_ci * @dev: driver model's view of this device 8462306a36Sopenharmony_ci * @managed_alloc: devm_rc_allocate_device was used to create rc_dev 8562306a36Sopenharmony_ci * @sysfs_groups: sysfs attribute groups 8662306a36Sopenharmony_ci * @device_name: name of the rc child device 8762306a36Sopenharmony_ci * @input_phys: physical path to the input child device 8862306a36Sopenharmony_ci * @input_id: id of the input child device (struct input_id) 8962306a36Sopenharmony_ci * @driver_name: name of the hardware driver which registered this device 9062306a36Sopenharmony_ci * @map_name: name of the default keymap 9162306a36Sopenharmony_ci * @rc_map: current scan/key table 9262306a36Sopenharmony_ci * @lock: used to ensure we've filled in all protocol details before 9362306a36Sopenharmony_ci * anyone can call show_protocols or store_protocols 9462306a36Sopenharmony_ci * @minor: unique minor remote control device number 9562306a36Sopenharmony_ci * @raw: additional data for raw pulse/space devices 9662306a36Sopenharmony_ci * @input_dev: the input child device used to communicate events to userspace 9762306a36Sopenharmony_ci * @driver_type: specifies if protocol decoding is done in hardware or software 9862306a36Sopenharmony_ci * @idle: used to keep track of RX state 9962306a36Sopenharmony_ci * @encode_wakeup: wakeup filtering uses IR encode API, therefore the allowed 10062306a36Sopenharmony_ci * wakeup protocols is the set of all raw encoders 10162306a36Sopenharmony_ci * @allowed_protocols: bitmask with the supported RC_PROTO_BIT_* protocols 10262306a36Sopenharmony_ci * @enabled_protocols: bitmask with the enabled RC_PROTO_BIT_* protocols 10362306a36Sopenharmony_ci * @allowed_wakeup_protocols: bitmask with the supported RC_PROTO_BIT_* wakeup 10462306a36Sopenharmony_ci * protocols 10562306a36Sopenharmony_ci * @wakeup_protocol: the enabled RC_PROTO_* wakeup protocol or 10662306a36Sopenharmony_ci * RC_PROTO_UNKNOWN if disabled. 10762306a36Sopenharmony_ci * @scancode_filter: scancode filter 10862306a36Sopenharmony_ci * @scancode_wakeup_filter: scancode wakeup filters 10962306a36Sopenharmony_ci * @scancode_mask: some hardware decoders are not capable of providing the full 11062306a36Sopenharmony_ci * scancode to the application. As this is a hardware limit, we can't do 11162306a36Sopenharmony_ci * anything with it. Yet, as the same keycode table can be used with other 11262306a36Sopenharmony_ci * devices, a mask is provided to allow its usage. Drivers should generally 11362306a36Sopenharmony_ci * leave this field in blank 11462306a36Sopenharmony_ci * @users: number of current users of the device 11562306a36Sopenharmony_ci * @priv: driver-specific data 11662306a36Sopenharmony_ci * @keylock: protects the remaining members of the struct 11762306a36Sopenharmony_ci * @keypressed: whether a key is currently pressed 11862306a36Sopenharmony_ci * @keyup_jiffies: time (in jiffies) when the current keypress should be released 11962306a36Sopenharmony_ci * @timer_keyup: timer for releasing a keypress 12062306a36Sopenharmony_ci * @timer_repeat: timer for autorepeat events. This is needed for CEC, which 12162306a36Sopenharmony_ci * has non-standard repeats. 12262306a36Sopenharmony_ci * @last_keycode: keycode of last keypress 12362306a36Sopenharmony_ci * @last_protocol: protocol of last keypress 12462306a36Sopenharmony_ci * @last_scancode: scancode of last keypress 12562306a36Sopenharmony_ci * @last_toggle: toggle value of last command 12662306a36Sopenharmony_ci * @timeout: optional time after which device stops sending data 12762306a36Sopenharmony_ci * @min_timeout: minimum timeout supported by device 12862306a36Sopenharmony_ci * @max_timeout: maximum timeout supported by device 12962306a36Sopenharmony_ci * @rx_resolution : resolution (in us) of input sampler 13062306a36Sopenharmony_ci * @tx_resolution: resolution (in us) of output sampler 13162306a36Sopenharmony_ci * @lirc_dev: lirc device 13262306a36Sopenharmony_ci * @lirc_cdev: lirc char cdev 13362306a36Sopenharmony_ci * @gap_start: start time for gap after timeout if non-zero 13462306a36Sopenharmony_ci * @lirc_fh_lock: protects lirc_fh list 13562306a36Sopenharmony_ci * @lirc_fh: list of open files 13662306a36Sopenharmony_ci * @registered: set to true by rc_register_device(), false by 13762306a36Sopenharmony_ci * rc_unregister_device 13862306a36Sopenharmony_ci * @change_protocol: allow changing the protocol used on hardware decoders 13962306a36Sopenharmony_ci * @open: callback to allow drivers to enable polling/irq when IR input device 14062306a36Sopenharmony_ci * is opened. 14162306a36Sopenharmony_ci * @close: callback to allow drivers to disable polling/irq when IR input device 14262306a36Sopenharmony_ci * is opened. 14362306a36Sopenharmony_ci * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) 14462306a36Sopenharmony_ci * @s_tx_carrier: set transmit carrier frequency 14562306a36Sopenharmony_ci * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%) 14662306a36Sopenharmony_ci * @s_rx_carrier_range: inform driver about carrier it is expected to handle 14762306a36Sopenharmony_ci * @tx_ir: transmit IR 14862306a36Sopenharmony_ci * @s_idle: enable/disable hardware idle mode, upon which, 14962306a36Sopenharmony_ci * device doesn't interrupt host until it sees IR pulses 15062306a36Sopenharmony_ci * @s_wideband_receiver: enable wide band receiver used for learning 15162306a36Sopenharmony_ci * @s_carrier_report: enable carrier reports 15262306a36Sopenharmony_ci * @s_filter: set the scancode filter 15362306a36Sopenharmony_ci * @s_wakeup_filter: set the wakeup scancode filter. If the mask is zero 15462306a36Sopenharmony_ci * then wakeup should be disabled. wakeup_protocol will be set to 15562306a36Sopenharmony_ci * a valid protocol if mask is nonzero. 15662306a36Sopenharmony_ci * @s_timeout: set hardware timeout in us 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistruct rc_dev { 15962306a36Sopenharmony_ci struct device dev; 16062306a36Sopenharmony_ci bool managed_alloc; 16162306a36Sopenharmony_ci const struct attribute_group *sysfs_groups[5]; 16262306a36Sopenharmony_ci const char *device_name; 16362306a36Sopenharmony_ci const char *input_phys; 16462306a36Sopenharmony_ci struct input_id input_id; 16562306a36Sopenharmony_ci const char *driver_name; 16662306a36Sopenharmony_ci const char *map_name; 16762306a36Sopenharmony_ci struct rc_map rc_map; 16862306a36Sopenharmony_ci struct mutex lock; 16962306a36Sopenharmony_ci unsigned int minor; 17062306a36Sopenharmony_ci struct ir_raw_event_ctrl *raw; 17162306a36Sopenharmony_ci struct input_dev *input_dev; 17262306a36Sopenharmony_ci enum rc_driver_type driver_type; 17362306a36Sopenharmony_ci bool idle; 17462306a36Sopenharmony_ci bool encode_wakeup; 17562306a36Sopenharmony_ci u64 allowed_protocols; 17662306a36Sopenharmony_ci u64 enabled_protocols; 17762306a36Sopenharmony_ci u64 allowed_wakeup_protocols; 17862306a36Sopenharmony_ci enum rc_proto wakeup_protocol; 17962306a36Sopenharmony_ci struct rc_scancode_filter scancode_filter; 18062306a36Sopenharmony_ci struct rc_scancode_filter scancode_wakeup_filter; 18162306a36Sopenharmony_ci u32 scancode_mask; 18262306a36Sopenharmony_ci u32 users; 18362306a36Sopenharmony_ci void *priv; 18462306a36Sopenharmony_ci spinlock_t keylock; 18562306a36Sopenharmony_ci bool keypressed; 18662306a36Sopenharmony_ci unsigned long keyup_jiffies; 18762306a36Sopenharmony_ci struct timer_list timer_keyup; 18862306a36Sopenharmony_ci struct timer_list timer_repeat; 18962306a36Sopenharmony_ci u32 last_keycode; 19062306a36Sopenharmony_ci enum rc_proto last_protocol; 19162306a36Sopenharmony_ci u64 last_scancode; 19262306a36Sopenharmony_ci u8 last_toggle; 19362306a36Sopenharmony_ci u32 timeout; 19462306a36Sopenharmony_ci u32 min_timeout; 19562306a36Sopenharmony_ci u32 max_timeout; 19662306a36Sopenharmony_ci u32 rx_resolution; 19762306a36Sopenharmony_ci u32 tx_resolution; 19862306a36Sopenharmony_ci#ifdef CONFIG_LIRC 19962306a36Sopenharmony_ci struct device lirc_dev; 20062306a36Sopenharmony_ci struct cdev lirc_cdev; 20162306a36Sopenharmony_ci ktime_t gap_start; 20262306a36Sopenharmony_ci spinlock_t lirc_fh_lock; 20362306a36Sopenharmony_ci struct list_head lirc_fh; 20462306a36Sopenharmony_ci#endif 20562306a36Sopenharmony_ci bool registered; 20662306a36Sopenharmony_ci int (*change_protocol)(struct rc_dev *dev, u64 *rc_proto); 20762306a36Sopenharmony_ci int (*open)(struct rc_dev *dev); 20862306a36Sopenharmony_ci void (*close)(struct rc_dev *dev); 20962306a36Sopenharmony_ci int (*s_tx_mask)(struct rc_dev *dev, u32 mask); 21062306a36Sopenharmony_ci int (*s_tx_carrier)(struct rc_dev *dev, u32 carrier); 21162306a36Sopenharmony_ci int (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle); 21262306a36Sopenharmony_ci int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max); 21362306a36Sopenharmony_ci int (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n); 21462306a36Sopenharmony_ci void (*s_idle)(struct rc_dev *dev, bool enable); 21562306a36Sopenharmony_ci int (*s_wideband_receiver)(struct rc_dev *dev, int enable); 21662306a36Sopenharmony_ci int (*s_carrier_report) (struct rc_dev *dev, int enable); 21762306a36Sopenharmony_ci int (*s_filter)(struct rc_dev *dev, 21862306a36Sopenharmony_ci struct rc_scancode_filter *filter); 21962306a36Sopenharmony_ci int (*s_wakeup_filter)(struct rc_dev *dev, 22062306a36Sopenharmony_ci struct rc_scancode_filter *filter); 22162306a36Sopenharmony_ci int (*s_timeout)(struct rc_dev *dev, 22262306a36Sopenharmony_ci unsigned int timeout); 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci#define to_rc_dev(d) container_of(d, struct rc_dev, dev) 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* 22862306a36Sopenharmony_ci * From rc-main.c 22962306a36Sopenharmony_ci * Those functions can be used on any type of Remote Controller. They 23062306a36Sopenharmony_ci * basically creates an input_dev and properly reports the device as a 23162306a36Sopenharmony_ci * Remote Controller, at sys/class/rc. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/** 23562306a36Sopenharmony_ci * rc_allocate_device - Allocates a RC device 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * @rc_driver_type: specifies the type of the RC output to be allocated 23862306a36Sopenharmony_ci * returns a pointer to struct rc_dev. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_cistruct rc_dev *rc_allocate_device(enum rc_driver_type); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/** 24362306a36Sopenharmony_ci * devm_rc_allocate_device - Managed RC device allocation 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * @dev: pointer to struct device 24662306a36Sopenharmony_ci * @rc_driver_type: specifies the type of the RC output to be allocated 24762306a36Sopenharmony_ci * returns a pointer to struct rc_dev. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistruct rc_dev *devm_rc_allocate_device(struct device *dev, enum rc_driver_type); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/** 25262306a36Sopenharmony_ci * rc_free_device - Frees a RC device 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * @dev: pointer to struct rc_dev. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_civoid rc_free_device(struct rc_dev *dev); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * rc_register_device - Registers a RC device 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * @dev: pointer to struct rc_dev. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ciint rc_register_device(struct rc_dev *dev); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/** 26662306a36Sopenharmony_ci * devm_rc_register_device - Manageded registering of a RC device 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * @parent: pointer to struct device. 26962306a36Sopenharmony_ci * @dev: pointer to struct rc_dev. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ciint devm_rc_register_device(struct device *parent, struct rc_dev *dev); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/** 27462306a36Sopenharmony_ci * rc_unregister_device - Unregisters a RC device 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * @dev: pointer to struct rc_dev. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_civoid rc_unregister_device(struct rc_dev *dev); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_civoid rc_repeat(struct rc_dev *dev); 28162306a36Sopenharmony_civoid rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode, 28262306a36Sopenharmony_ci u8 toggle); 28362306a36Sopenharmony_civoid rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, 28462306a36Sopenharmony_ci u64 scancode, u8 toggle); 28562306a36Sopenharmony_civoid rc_keyup(struct rc_dev *dev); 28662306a36Sopenharmony_ciu32 rc_g_keycode_from_table(struct rc_dev *dev, u64 scancode); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* 28962306a36Sopenharmony_ci * From rc-raw.c 29062306a36Sopenharmony_ci * The Raw interface is specific to InfraRed. It may be a good idea to 29162306a36Sopenharmony_ci * split it later into a separate header. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_cistruct ir_raw_event { 29462306a36Sopenharmony_ci union { 29562306a36Sopenharmony_ci u32 duration; 29662306a36Sopenharmony_ci u32 carrier; 29762306a36Sopenharmony_ci }; 29862306a36Sopenharmony_ci u8 duty_cycle; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci unsigned pulse:1; 30162306a36Sopenharmony_ci unsigned overflow:1; 30262306a36Sopenharmony_ci unsigned timeout:1; 30362306a36Sopenharmony_ci unsigned carrier_report:1; 30462306a36Sopenharmony_ci}; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci#define US_TO_NS(usec) ((usec) * 1000) 30762306a36Sopenharmony_ci#define MS_TO_US(msec) ((msec) * 1000) 30862306a36Sopenharmony_ci#define IR_MAX_DURATION MS_TO_US(500) 30962306a36Sopenharmony_ci#define IR_DEFAULT_TIMEOUT MS_TO_US(125) 31062306a36Sopenharmony_ci#define IR_MAX_TIMEOUT LIRC_VALUE_MASK 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_civoid ir_raw_event_handle(struct rc_dev *dev); 31362306a36Sopenharmony_ciint ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); 31462306a36Sopenharmony_ciint ir_raw_event_store_edge(struct rc_dev *dev, bool pulse); 31562306a36Sopenharmony_ciint ir_raw_event_store_with_filter(struct rc_dev *dev, 31662306a36Sopenharmony_ci struct ir_raw_event *ev); 31762306a36Sopenharmony_ciint ir_raw_event_store_with_timeout(struct rc_dev *dev, 31862306a36Sopenharmony_ci struct ir_raw_event *ev); 31962306a36Sopenharmony_civoid ir_raw_event_set_idle(struct rc_dev *dev, bool idle); 32062306a36Sopenharmony_ciint ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode, 32162306a36Sopenharmony_ci struct ir_raw_event *events, unsigned int max); 32262306a36Sopenharmony_ciint ir_raw_encode_carrier(enum rc_proto protocol); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic inline void ir_raw_event_overflow(struct rc_dev *dev) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci ir_raw_event_store(dev, &((struct ir_raw_event) { .overflow = true })); 32762306a36Sopenharmony_ci dev->idle = true; 32862306a36Sopenharmony_ci ir_raw_event_handle(dev); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* extract mask bits out of data and pack them into the result */ 33262306a36Sopenharmony_cistatic inline u32 ir_extract_bits(u32 data, u32 mask) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci u32 vbit = 1, value = 0; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci do { 33762306a36Sopenharmony_ci if (mask & 1) { 33862306a36Sopenharmony_ci if (data & 1) 33962306a36Sopenharmony_ci value |= vbit; 34062306a36Sopenharmony_ci vbit <<= 1; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci data >>= 1; 34362306a36Sopenharmony_ci } while (mask >>= 1); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return value; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* Get NEC scancode and protocol type from address and command bytes */ 34962306a36Sopenharmony_cistatic inline u32 ir_nec_bytes_to_scancode(u8 address, u8 not_address, 35062306a36Sopenharmony_ci u8 command, u8 not_command, 35162306a36Sopenharmony_ci enum rc_proto *protocol) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci u32 scancode; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if ((command ^ not_command) != 0xff) { 35662306a36Sopenharmony_ci /* NEC transport, but modified protocol, used by at 35762306a36Sopenharmony_ci * least Apple and TiVo remotes 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci scancode = not_address << 24 | 36062306a36Sopenharmony_ci address << 16 | 36162306a36Sopenharmony_ci not_command << 8 | 36262306a36Sopenharmony_ci command; 36362306a36Sopenharmony_ci *protocol = RC_PROTO_NEC32; 36462306a36Sopenharmony_ci } else if ((address ^ not_address) != 0xff) { 36562306a36Sopenharmony_ci /* Extended NEC */ 36662306a36Sopenharmony_ci scancode = address << 16 | 36762306a36Sopenharmony_ci not_address << 8 | 36862306a36Sopenharmony_ci command; 36962306a36Sopenharmony_ci *protocol = RC_PROTO_NECX; 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci /* Normal NEC */ 37262306a36Sopenharmony_ci scancode = address << 8 | command; 37362306a36Sopenharmony_ci *protocol = RC_PROTO_NEC; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return scancode; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci#endif /* _RC_CORE */ 380