mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-02 11:13:02 +09:00
PD#SWPL-17246 Problem: sync the code from mainline. Solution: sync the code from mainline. 7c03859983c2 OSS vulnerability found in [boot.img]:[linux_kernel] (CVE-2018-12232) Risk:[] [1/1] ba89a3d9c791 OSS vulnerability found in [boot.img]:[linux_kernel] (CVE-2019-8912) Risk:[] [1/1] c434d0530610 Android Security Bulletin - November 2019-11 - Kernel components binder driver - CVE-2019-2214 [1/1] ff8d9012fbd4 Android Security Bulletin - November 2019-11 - Kernel components ext4 filesystem - CVE-2019-11833 [1/1] 3c52e964495e cec: store msg after bootup from st [1/2] 94198a56ee10 lcd: support tcon vac and demura data [2/2] 1add1a008a03 vout: spi: porting lcd driver and SPI to Linux [1/1] 3e8d7b0e5f97 hdmirx: add hpd recovery logic when input clk is unstable [1/1] f92e7ba21c62 ppmgr: Add 10bit, dolby and HDR video rotation. [1/1] dab2cc37cd95 dvb: fix dmx2 interrupt bug [1/1] 9d31efae4a55 dv: add dv target output mode [1/1] e86eb9d1b5c5 hdmirx: add rx phy tdr enable control [1/1] 8ea66f645bf6 dts: enable spi for gva [1/1] baf6e74528ef drm: add drm support for tm2 [1/1] Verify: verify by newton Change-Id: I9415060a4b39895b5d624117271a72fc6a1fd187 Signed-off-by: Luan Yuan <luan.yuan@amlogic.com>
268 lines
6.5 KiB
C
268 lines
6.5 KiB
C
/*
|
|
* drivers/amlogic/irblaster/encoder.c
|
|
*
|
|
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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 <linux/module.h>
|
|
#include <linux/list.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/err.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/device.h>
|
|
#include <linux/amlogic/irblaster.h>
|
|
#include <linux/amlogic/irblaster_encoder.h>
|
|
|
|
static int irblaster_raw_gen_pulse_space(unsigned int *data,
|
|
unsigned int *max,
|
|
unsigned int pulse_width,
|
|
unsigned int space_width,
|
|
unsigned int len)
|
|
{
|
|
if (!*max)
|
|
return -ENOBUFS;
|
|
data[len - *max] = pulse_width;
|
|
if (!--*max)
|
|
return -ENOBUFS;
|
|
data[len - *max] = space_width;
|
|
--*max;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* irblaster_raw_gen() - Encode data to raw events with pulse-length modulation.
|
|
* @data: Pointer to data
|
|
* @timings: Pulse distance modulation timings.
|
|
* @raw: Data bits to encode.
|
|
* @Returns: buff len on success.
|
|
*
|
|
* Encodes the @n least significant bits of @data using space-distance
|
|
* modulation with the timing characteristics described by @timings, writing up
|
|
* to data using the *data pointer.
|
|
*/
|
|
int irblaster_raw_gen(unsigned int *data,
|
|
const struct irblaster_raw_timings *timings,
|
|
u32 raw)
|
|
{
|
|
int i, ret, max;
|
|
int len = timings->data_size;
|
|
unsigned int space;
|
|
|
|
max = len;
|
|
if (timings->header_pulse) {
|
|
ret = irblaster_raw_gen_pulse_space(data, &max,
|
|
timings->header_pulse,
|
|
timings->header_space,
|
|
len);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (timings->msb_first) {
|
|
for (i = timings->raw_nbits - 1; i >= 0; --i) {
|
|
space = timings->bit_space[(raw >> i) & 1];
|
|
ret = irblaster_raw_gen_pulse_space(data, &max,
|
|
timings->bit_pulse,
|
|
space, len);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
} else {
|
|
for (i = 0; i < timings->raw_nbits; ++i, raw >>= 1) {
|
|
space = timings->bit_space[raw & 1];
|
|
ret = irblaster_raw_gen_pulse_space(data, &max,
|
|
timings->bit_pulse,
|
|
space, len);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = irblaster_raw_gen_pulse_space(data, &max,
|
|
timings->trailer_pulse,
|
|
timings->trailer_space,
|
|
len);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return len;
|
|
}
|
|
|
|
unsigned int protocol_show_select(struct irblaster_chip *chip, char *buf)
|
|
{
|
|
struct irblaster_raw_handler *protocol;
|
|
unsigned int len = 0;
|
|
|
|
mutex_lock(&irblaster_raw_handler_lock);
|
|
list_for_each_entry(protocol, &irblaster_raw_handler_list, list) {
|
|
if (chip->protocol &&
|
|
chip->state.protocol == protocol->protocol)
|
|
len += scnprintf(buf + len, PAGE_SIZE - len, "[%s] ",
|
|
protocol->name);
|
|
else
|
|
len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
|
|
protocol->name);
|
|
}
|
|
|
|
len += scnprintf(len + buf, PAGE_SIZE - len, "\n");
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
|
|
return len;
|
|
}
|
|
|
|
unsigned int protocol_store_select(const char *buf)
|
|
{
|
|
struct irblaster_raw_handler *protocol;
|
|
|
|
mutex_lock(&irblaster_raw_handler_lock);
|
|
list_for_each_entry(protocol, &irblaster_raw_handler_list, list) {
|
|
if (sysfs_streq(buf, protocol->name)) {
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
return protocol->protocol;
|
|
}
|
|
}
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* irblaster_raw_handler_register()
|
|
* - register a new raw_handle
|
|
* @ir_raw_handler: the raw_handle to add
|
|
* @Returns: 0 on success
|
|
*/
|
|
int irblaster_raw_handler_register(struct irblaster_raw_handler *ir_raw_handler)
|
|
{
|
|
mutex_lock(&irblaster_raw_handler_lock);
|
|
list_add_tail(&ir_raw_handler->list, &irblaster_raw_handler_list);
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(irblaster_raw_handler_register);
|
|
|
|
/**
|
|
* irblaster_raw_handler_unregister()
|
|
* - unregister a raw_handle
|
|
* @ir_raw_handler: the raw_handle to remove
|
|
*/
|
|
void irblaster_raw_handler_unregister(struct irblaster_raw_handler
|
|
*ir_raw_handler)
|
|
{
|
|
mutex_lock(&irblaster_raw_handler_lock);
|
|
list_del(&ir_raw_handler->list);
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
}
|
|
EXPORT_SYMBOL(irblaster_raw_handler_unregister);
|
|
|
|
/**
|
|
* irblaster_send_key() - send key with addr and commmand
|
|
* @chip: irblaster controller
|
|
* @addr: remote control ID
|
|
* @commmand: key
|
|
*/
|
|
int irblaster_send_key(struct irblaster_chip *chip, unsigned int addr,
|
|
unsigned int commmand)
|
|
{
|
|
int ret;
|
|
unsigned int *data;
|
|
|
|
if (!chip)
|
|
return -EINVAL;
|
|
|
|
if (chip->ops->send_key) {
|
|
ret = chip->ops->send_key(chip, addr, commmand);
|
|
if (ret) {
|
|
pr_err("%s(): irblaster_send fail\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
} else {
|
|
data = kzalloc(sizeof(uint32_t) * MAX_PLUSE, GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
if (chip->protocol->encode) {
|
|
ret = chip->protocol->encode(chip->state.protocol,
|
|
addr, commmand, data);
|
|
if (ret <= 0) {
|
|
pr_err("%s(): irblaster encode fail\n",
|
|
__func__);
|
|
goto err;
|
|
}
|
|
} else {
|
|
pr_err("%s(): irblaster func %s not found\n",
|
|
__func__, __func__);
|
|
goto err;
|
|
}
|
|
|
|
ret = irblaster_send(chip, data,
|
|
chip->protocol->timing->data_size);
|
|
if (ret) {
|
|
pr_err("%s(): irblaster_send fail\n", __func__);
|
|
goto err;
|
|
}
|
|
|
|
kfree(data);
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
kfree(data);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/**
|
|
* irblaster_set_protocol() - set irblaster protocol
|
|
* @chip: irblaster controller
|
|
* @ir_protocol: irblaster protocol
|
|
*/
|
|
int irblaster_set_protocol(struct irblaster_chip *chip,
|
|
enum irblaster_protocol ir_protocol)
|
|
{
|
|
struct irblaster_raw_handler *protocol;
|
|
|
|
if (!chip || ir_protocol < 0 || ir_protocol >= IRBLASTER_PROTOCOL_MAX)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&irblaster_raw_handler_lock);
|
|
|
|
list_for_each_entry(protocol, &irblaster_raw_handler_list, list)
|
|
if (protocol->protocol == ir_protocol) {
|
|
chip->state.protocol = ir_protocol;
|
|
chip->protocol = protocol;
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
return 0;
|
|
}
|
|
|
|
mutex_unlock(&irblaster_raw_handler_lock);
|
|
pr_err("%s(): irblaster protocol is not found\n", __func__);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
/**
|
|
* irblaster_get_protocol() - get irblaster protocol
|
|
* @chip: irblaster controller
|
|
*/
|
|
enum irblaster_protocol irblaster_get_protocol(struct irblaster_chip *chip)
|
|
{
|
|
if (!chip)
|
|
return -EINVAL;
|
|
|
|
return chip->state.protocol;
|
|
}
|