linux/drivers/media/i2c/ir-kbd-i2c.c

1003 lines
24 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
/*
*
* keyboard input driver for i2c IR remote controls
*
* Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
* modified for PixelView (BT878P+W/FM) by
* Michal Kochanowicz <mkochano@pld.org.pl>
* Christoph Bartelmus <lirc@bartelmus.de>
* modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
* Ulrich Mueller <ulrich.mueller42@web.de>
* modified for em2820 based USB TV tuners by
* Markus Rechberger <mrechberger@gmail.com>
* modified for DViCO Fusion HDTV 5 RT GOLD by
* Chaogui Zhang <czhang1974@gmail.com>
* modified for MSI TV@nywhere Plus by
* Henry Wong <henry@stuffedcow.net>
* Mark Schultz <n9xmj@yahoo.com>
* Brian Rogers <brian_rogers@comcast.net>
* modified for AVerMedia Cardbus by
* Oldrich Jedlicka <oldium.pro@seznam.cz>
* Zilog Transmitter portions/ideas were derived from GPLv2+ sources:
* - drivers/char/pctv_zilogir.[ch] from Hauppauge Broadway product
* Copyright 2011 Hauppauge Computer works
* - drivers/staging/media/lirc/lirc_zilog.c
* Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
* Michal Kochanowicz <mkochano@pld.org.pl>
* Christoph Bartelmus <lirc@bartelmus.de>
* Ulrich Mueller <ulrich.mueller42@web.de>
* Stefan Jahn <stefan@lkcc.org>
* Jerome Brock <jbrock@users.sourceforge.net>
* Thomas Reitmayr (treitmayr@yahoo.com)
* Mark Weaver <mark@npsl.co.uk>
* Jarod Wilson <jarod@redhat.com>
* Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net>
*/
#include <asm/unaligned.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <media/rc-core.h>
[media] include/media: split I2C headers from V4L2 core Currently, include/media is messy, as it contains both the V4L2 core headers and some driver-specific headers on the same place. That makes harder to identify what core headers should be documented and what headers belong to I2C drivers that are included only by bridge/main drivers that would require the functions provided by them. Let's move those i2c specific files to its own subdirectory. The files to move were produced via the following script: mkdir include/media/i2c (cd include/media; for i in *.h; do n=`echo $i|sed s/.h$/.c/`; if [ -e ../../drivers/media/i2c/$n ]; then echo $i; git mv $i i2c/; fi; done) (cd include/media; for i in *.h; do n=`echo $i|sed s/.h$/.c/`; if [ -e ../../drivers/media/*/i2c/$n ]; then echo $i; git mv $i i2c/; fi; done) for i in include/media/*.h; do n=`basename $i`; (for j in $(git grep -l $n); do dirname $j; done)|sort|uniq|grep -ve '^.$' > list; num=$(wc -l list|cut -d' ' -f1); if [ $num == 1 ]; then if [ "`grep i2c list`" != "" ]; then git mv $i include/media/i2c; fi; fi; done And the references corrected via this script: MAIN_DIR="media/" PREV_DIR="media/" DIRS="i2c/" echo "Checking affected files" >&2 for i in $DIRS; do for j in $(find include/$MAIN_DIR/$i -type f -name '*.h'); do n=`basename $j` git grep -l $n done done|sort|uniq >files && ( echo "Handling files..." >&2; echo "for i in \$(cat files|grep -v Documentation); do cat \$i | \\"; ( cd include/$MAIN_DIR; for j in $DIRS; do for i in $(ls $j); do echo "perl -ne 's,(include [\\\"\\<])$PREV_DIR($i)([\\\"\\>]),\1$MAIN_DIR$j\2\3,; print \$_' |\\"; done; done; echo "cat > a && mv a \$i; done"; ); echo "Handling documentation..." >&2; echo "for i in MAINTAINERS \$(cat files); do cat \$i | \\"; ( cd include/$MAIN_DIR; for j in $DIRS; do for i in $(ls $j); do echo " perl -ne 's,include/$PREV_DIR($i)\b,include/$MAIN_DIR$j\1,; print \$_' |\\"; done; done; echo "cat > a && mv a \$i; done" ); ) >script && . ./script Merged Sakari Ailus patch that moves smiapp.h to include/media/i2c. Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
2015-11-10 22:01:44 +08:00
#include <media/i2c/ir-kbd-i2c.h>
#define FLAG_TX 1
#define FLAG_HDPVR 2
static bool enable_hdpvr;
module_param(enable_hdpvr, bool, 0644);
static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *ptoggle, int size)
{
unsigned char buf[6];
int start, range, toggle, dev, code, ircode, vendor;
/* poll IR chip */
if (size != i2c_master_recv(ir->c, buf, size))
return -EIO;
if (buf[0] & 0x80) {
int offset = (size == 6) ? 3 : 0;
/* split rc5 data block ... */
start = (buf[offset] >> 7) & 1;
range = (buf[offset] >> 6) & 1;
toggle = (buf[offset] >> 5) & 1;
dev = buf[offset] & 0x1f;
code = (buf[offset+1] >> 2) & 0x3f;
/* rc5 has two start bits
* the first bit must be one
* the second bit defines the command range:
* 1 = 0-63, 0 = 64 - 127
*/
if (!start)
/* no key pressed */
return 0;
/* filter out invalid key presses */
ircode = (start << 12) | (toggle << 11) | (dev << 6) | code;
if ((ircode & 0x1fff) == 0x1fff)
return 0;
if (!range)
code += 64;
dev_dbg(&ir->rc->dev,
"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
start, range, toggle, dev, code);
*protocol = RC_PROTO_RC5;
*scancode = RC_SCANCODE_RC5(dev, code);
*ptoggle = toggle;
return 1;
} else if (size == 6 && (buf[0] & 0x40)) {
code = buf[4];
dev = buf[3];
vendor = get_unaligned_be16(buf + 1);
if (vendor == 0x800f) {
*ptoggle = (dev & 0x80) != 0;
*protocol = RC_PROTO_RC6_MCE;
dev &= 0x7f;
dev_dbg(&ir->rc->dev,
"ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n",
*ptoggle, vendor, dev, code);
} else {
*ptoggle = 0;
*protocol = RC_PROTO_RC6_6A_32;
dev_dbg(&ir->rc->dev,
"ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n",
vendor, dev, code);
}
*scancode = RC_SCANCODE_RC6_6A(vendor, dev, code);
return 1;
}
return 0;
}
static int get_key_haup(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
return get_key_haup_common(ir, protocol, scancode, toggle, 3);
}
static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
int ret;
unsigned char buf[1] = { 0 };
/*
* This is the same apparent "are you ready?" poll command observed
* watching Windows driver traffic and implemented in lirc_zilog. With
* this added, we get far saner remote behavior with z8 chips on usb
* connected devices, even with the default polling interval of 100ms.
*/
ret = i2c_master_send(ir->c, buf, 1);
if (ret != 1)
return (ret < 0) ? ret : -EINVAL;
return get_key_haup_common(ir, protocol, scancode, toggle, 6);
}
static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
int rc;
unsigned char b;
/* poll IR chip */
rc = i2c_master_recv(ir->c, &b, 1);
if (rc != 1) {
dev_dbg(&ir->rc->dev, "read error\n");
if (rc < 0)
return rc;
return -EIO;
}
*protocol = RC_PROTO_OTHER;
*scancode = b;
*toggle = 0;
return 1;
}
static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
int rc;
unsigned char buf[4];
/* poll IR chip */
rc = i2c_master_recv(ir->c, buf, 4);
if (rc != 4) {
dev_dbg(&ir->rc->dev, "read error\n");
if (rc < 0)
return rc;
return -EIO;
}
if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0 || buf[3] != 0)
dev_dbg(&ir->rc->dev, "%s: %*ph\n", __func__, 4, buf);
/* no key pressed or signal from other ir remote */
if(buf[0] != 0x1 || buf[1] != 0xfe)
return 0;
*protocol = RC_PROTO_UNKNOWN;
*scancode = buf[2];
*toggle = 0;
return 1;
}
static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
int rc;
unsigned char b;
/* poll IR chip */
rc = i2c_master_recv(ir->c, &b, 1);
if (rc != 1) {
dev_dbg(&ir->rc->dev, "read error\n");
if (rc < 0)
return rc;
return -EIO;
}
/* it seems that 0xFE indicates that a button is still hold
down, while 0xff indicates that no button is hold
down. 0xfe sequences are sometimes interrupted by 0xFF */
dev_dbg(&ir->rc->dev, "key %02x\n", b);
if (b == 0xff)
return 0;
if (b == 0xfe)
/* keep old data */
return 1;
*protocol = RC_PROTO_UNKNOWN;
*scancode = b;
*toggle = 0;
return 1;
}
static int get_key_geniatech(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
int i, rc;
unsigned char b;
/* poll IR chip */
for (i = 0; i < 4; i++) {
rc = i2c_master_recv(ir->c, &b, 1);
if (rc == 1)
break;
msleep(20);
}
if (rc != 1) {
dev_dbg(&ir->rc->dev, "read error\n");
if (rc < 0)
return rc;
return -EIO;
}
/* don't repeat the key */
if (ir->old == b)
return 0;
ir->old = b;
/* decode to RC5 */
b &= 0x7f;
b = (b - 1) / 2;
dev_dbg(&ir->rc->dev, "key %02x\n", b);
*protocol = RC_PROTO_RC5;
*scancode = b;
*toggle = ir->old >> 7;
return 1;
}
static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
unsigned char subaddr, key, keygroup;
struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
.buf = &subaddr, .len = 1},
{ .addr = ir->c->addr, .flags = I2C_M_RD,
.buf = &key, .len = 1} };
subaddr = 0x0d;
if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
dev_dbg(&ir->rc->dev, "read error\n");
return -EIO;
}
if (key == 0xff)
return 0;
subaddr = 0x0b;
msg[1].buf = &keygroup;
if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
dev_dbg(&ir->rc->dev, "read error\n");
return -EIO;
}
if (keygroup == 0xff)
return 0;
dev_dbg(&ir->rc->dev, "read key 0x%02x/0x%02x\n", key, keygroup);
if (keygroup < 2 || keygroup > 4) {
dev_warn(&ir->rc->dev, "warning: invalid key group 0x%02x for key 0x%02x\n",
keygroup, key);
}
key |= (keygroup & 1) << 6;
*protocol = RC_PROTO_UNKNOWN;
*scancode = key;
if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */
*scancode |= keygroup << 8;
*toggle = 0;
return 1;
}
/* ----------------------------------------------------------------------- */
static int ir_key_poll(struct IR_i2c *ir)
{
enum rc_proto protocol;
u32 scancode;
u8 toggle;
int rc;
dev_dbg(&ir->rc->dev, "%s\n", __func__);
rc = ir->get_key(ir, &protocol, &scancode, &toggle);
if (rc < 0) {
dev_warn(&ir->rc->dev, "error %d\n", rc);
return rc;
}
if (rc) {
dev_dbg(&ir->rc->dev, "%s: proto = 0x%04x, scancode = 0x%08x\n",
__func__, protocol, scancode);
rc_keydown(ir->rc, protocol, scancode, toggle);
}
return 0;
}
static void ir_work(struct work_struct *work)
{
int rc;
struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
/*
* If the transmit code is holding the lock, skip polling for
* IR, we'll get it to it next time round
*/
if (mutex_trylock(&ir->lock)) {
rc = ir_key_poll(ir);
mutex_unlock(&ir->lock);
if (rc == -ENODEV) {
rc_unregister_device(ir->rc);
ir->rc = NULL;
return;
}
}
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval));
}
static int ir_open(struct rc_dev *dev)
{
struct IR_i2c *ir = dev->priv;
schedule_delayed_work(&ir->work, 0);
return 0;
}
static void ir_close(struct rc_dev *dev)
{
struct IR_i2c *ir = dev->priv;
cancel_delayed_work_sync(&ir->work);
}
/* Zilog Transmit Interface */
#define XTAL_FREQ 18432000
#define ZILOG_SEND 0x80
#define ZILOG_UIR_END 0x40
#define ZILOG_INIT_END 0x20
#define ZILOG_LIR_END 0x10
#define ZILOG_STATUS_OK 0x80
#define ZILOG_STATUS_TX 0x40
#define ZILOG_STATUS_SET 0x20
/*
* As you can see here, very few different lengths of pulse and space
* can be encoded. This means that the hardware does not work well with
* recorded IR. It's best to work with generated IR, like from ir-ctl or
* the in-kernel encoders.
*/
struct code_block {
u8 length;
u16 pulse[7]; /* not aligned */
u8 carrier_pulse;
u8 carrier_space;
u16 space[8]; /* not aligned */
u8 codes[61];
u8 csum[2];
} __packed;
static int send_data_block(struct IR_i2c *ir, int cmd,
struct code_block *code_block)
{
int i, j, ret;
u8 buf[5], *p;
p = &code_block->length;
for (i = 0; p < code_block->csum; i++)
code_block->csum[i & 1] ^= *p++;
p = &code_block->length;
for (i = 0; i < sizeof(*code_block);) {
int tosend = sizeof(*code_block) - i;
if (tosend > 4)
tosend = 4;
buf[0] = i + 1;
for (j = 0; j < tosend; ++j)
buf[1 + j] = p[i + j];
dev_dbg(&ir->rc->dev, "%*ph", tosend + 1, buf);
ret = i2c_master_send(ir->tx_c, buf, tosend + 1);
if (ret != tosend + 1) {
dev_dbg(&ir->rc->dev,
"i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EIO;
}
i += tosend;
}
buf[0] = 0;
buf[1] = cmd;
ret = i2c_master_send(ir->tx_c, buf, 2);
if (ret != 2) {
dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EIO;
}
usleep_range(2000, 5000);
ret = i2c_master_send(ir->tx_c, buf, 1);
if (ret != 1) {
dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EIO;
}
return 0;
}
static int zilog_init(struct IR_i2c *ir)
{
struct code_block code_block = { .length = sizeof(code_block) };
u8 buf[4];
int ret;
put_unaligned_be16(0x1000, &code_block.pulse[3]);
ret = send_data_block(ir, ZILOG_INIT_END, &code_block);
if (ret)
return ret;
ret = i2c_master_recv(ir->tx_c, buf, 4);
if (ret != 4) {
dev_err(&ir->c->dev, "failed to retrieve firmware version: %d\n",
ret);
return ret < 0 ? ret : -EIO;
}
dev_info(&ir->c->dev, "Zilog/Hauppauge IR blaster firmware version %d.%d.%d\n",
buf[1], buf[2], buf[3]);
return 0;
}
/*
* If the last slot for pulse is the same as the current slot for pulse,
* then use slot no 7.
*/
static void copy_codes(u8 *dst, u8 *src, unsigned int count)
{
u8 c, last = 0xff;
while (count--) {
c = *src++;
if ((c & 0xf0) == last) {
*dst++ = 0x70 | (c & 0xf);
} else {
*dst++ = c;
last = c & 0xf0;
}
}
}
/*
* When looking for repeats, we don't care about the trailing space. This
* is set to the shortest possible anyway.
*/
static int cmp_no_trail(u8 *a, u8 *b, unsigned int count)
{
while (--count) {
if (*a++ != *b++)
return 1;
}
return (*a & 0xf0) - (*b & 0xf0);
}
static int find_slot(u16 *array, unsigned int size, u16 val)
{
int i;
for (i = 0; i < size; i++) {
if (get_unaligned_be16(&array[i]) == val) {
return i;
} else if (!array[i]) {
put_unaligned_be16(val, &array[i]);
return i;
}
}
return -1;
}
static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf,
unsigned int count, struct code_block *code_block)
{
struct IR_i2c *ir = rcdev->priv;
int rep, i, l, p = 0, s, c = 0;
bool repeating;
u8 codes[174];
code_block->carrier_pulse = DIV_ROUND_CLOSEST(
ir->duty_cycle * XTAL_FREQ / 1000, ir->carrier);
code_block->carrier_space = DIV_ROUND_CLOSEST(
(100 - ir->duty_cycle) * XTAL_FREQ / 1000, ir->carrier);
for (i = 0; i < count; i++) {
if (c >= ARRAY_SIZE(codes) - 1) {
dev_warn(&rcdev->dev, "IR too long, cannot transmit\n");
return -EINVAL;
}
/*
* Lengths more than 142220us cannot be encoded; also
* this checks for multiply overflow
*/
if (txbuf[i] > 142220)
return -EINVAL;
l = DIV_ROUND_CLOSEST((XTAL_FREQ / 1000) * txbuf[i], 40000);
if (i & 1) {
s = find_slot(code_block->space,
ARRAY_SIZE(code_block->space), l);
if (s == -1) {
dev_warn(&rcdev->dev, "Too many different lengths spaces, cannot transmit");
return -EINVAL;
}
/* We have a pulse and space */
codes[c++] = (p << 4) | s;
} else {
p = find_slot(code_block->pulse,
ARRAY_SIZE(code_block->pulse), l);
if (p == -1) {
dev_warn(&rcdev->dev, "Too many different lengths pulses, cannot transmit");
return -EINVAL;
}
}
}
/* We have to encode the trailing pulse. Find the shortest space */
s = 0;
for (i = 1; i < ARRAY_SIZE(code_block->space); i++) {
u16 d = get_unaligned_be16(&code_block->space[i]);
if (get_unaligned_be16(&code_block->space[s]) > d)
s = i;
}
codes[c++] = (p << 4) | s;
dev_dbg(&rcdev->dev, "generated %d codes\n", c);
/*
* Are the last N codes (so pulse + space) repeating 3 times?
* if so we can shorten the codes list and use code 0xc0 to repeat
* them.
*/
repeating = false;
for (rep = c / 3; rep >= 1; rep--) {
if (!memcmp(&codes[c - rep * 3], &codes[c - rep * 2], rep) &&
!cmp_no_trail(&codes[c - rep], &codes[c - rep * 2], rep)) {
repeating = true;
break;
}
}
if (repeating) {
/* first copy any leading non-repeating */
int leading = c - rep * 3;
if (leading >= ARRAY_SIZE(code_block->codes) - 3 - rep) {
dev_warn(&rcdev->dev, "IR too long, cannot transmit\n");
return -EINVAL;
}
dev_dbg(&rcdev->dev, "found trailing %d repeat\n", rep);
copy_codes(code_block->codes, codes, leading);
code_block->codes[leading] = 0x82;
copy_codes(code_block->codes + leading + 1, codes + leading,
rep);
c = leading + 1 + rep;
code_block->codes[c++] = 0xc0;
} else {
if (c >= ARRAY_SIZE(code_block->codes) - 3) {
dev_warn(&rcdev->dev, "IR too long, cannot transmit\n");
return -EINVAL;
}
dev_dbg(&rcdev->dev, "found no trailing repeat\n");
code_block->codes[0] = 0x82;
copy_codes(code_block->codes + 1, codes, c);
c++;
code_block->codes[c++] = 0xc4;
}
while (c < ARRAY_SIZE(code_block->codes))
code_block->codes[c++] = 0x83;
return 0;
}
static int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf,
unsigned int count)
{
struct IR_i2c *ir = rcdev->priv;
struct code_block code_block = { .length = sizeof(code_block) };
u8 buf[2];
int ret, i;
ret = zilog_ir_format(rcdev, txbuf, count, &code_block);
if (ret)
return ret;
ret = mutex_lock_interruptible(&ir->lock);
if (ret)
return ret;
ret = send_data_block(ir, ZILOG_UIR_END, &code_block);
if (ret)
goto out_unlock;
ret = i2c_master_recv(ir->tx_c, buf, 1);
if (ret != 1) {
dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret);
goto out_unlock;
}
dev_dbg(&ir->rc->dev, "code set status: %02x\n", buf[0]);
if (buf[0] != (ZILOG_STATUS_OK | ZILOG_STATUS_SET)) {
dev_err(&ir->rc->dev, "unexpected IR TX response %02x\n",
buf[0]);
ret = -EIO;
goto out_unlock;
}
buf[0] = 0x00;
buf[1] = ZILOG_SEND;
ret = i2c_master_send(ir->tx_c, buf, 2);
if (ret != 2) {
dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret);
if (ret >= 0)
ret = -EIO;
goto out_unlock;
}
dev_dbg(&ir->rc->dev, "send command sent\n");
/*
* This bit NAKs until the device is ready, so we retry it
* sleeping a bit each time. This seems to be what the windows
* driver does, approximately.
* Try for up to 1s.
*/
for (i = 0; i < 20; ++i) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(50));
ret = i2c_master_send(ir->tx_c, buf, 1);
if (ret == 1)
break;
dev_dbg(&ir->rc->dev,
"NAK expected: i2c_master_send failed with %d (try %d)\n",
ret, i + 1);
}
if (ret != 1) {
dev_err(&ir->rc->dev,
"IR TX chip never got ready: last i2c_master_send failed with %d\n",
ret);
if (ret >= 0)
ret = -EIO;
goto out_unlock;
}
ret = i2c_master_recv(ir->tx_c, buf, 1);
if (ret != 1) {
dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret);
ret = -EIO;
goto out_unlock;
} else if (buf[0] != ZILOG_STATUS_OK) {
dev_err(&ir->rc->dev, "unexpected IR TX response #2: %02x\n",
buf[0]);
ret = -EIO;
goto out_unlock;
}
dev_dbg(&ir->rc->dev, "transmit complete\n");
/* Oh good, it worked */
ret = count;
out_unlock:
mutex_unlock(&ir->lock);
return ret;
}
static int zilog_tx_carrier(struct rc_dev *dev, u32 carrier)
{
struct IR_i2c *ir = dev->priv;
if (carrier > 500000 || carrier < 20000)
return -EINVAL;
ir->carrier = carrier;
return 0;
}
static int zilog_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
{
struct IR_i2c *ir = dev->priv;
ir->duty_cycle = duty_cycle;
return 0;
}
static int ir_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
char *ir_codes = NULL;
const char *name = NULL;
u64 rc_proto = RC_PROTO_BIT_UNKNOWN;
struct IR_i2c *ir;
struct rc_dev *rc = NULL;
struct i2c_adapter *adap = client->adapter;
unsigned short addr = client->addr;
bool probe_tx = (id->driver_data & FLAG_TX) != 0;
int err;
if ((id->driver_data & FLAG_HDPVR) && !enable_hdpvr) {
dev_err(&client->dev, "IR for HDPVR is known to cause problems during recording, use enable_hdpvr modparam to enable\n");
return -ENODEV;
}
ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL);
if (!ir)
return -ENOMEM;
ir->c = client;
ir->polling_interval = DEFAULT_POLLING_INTERVAL;
i2c_set_clientdata(client, ir);
switch(addr) {
case 0x64:
name = "Pixelview";
ir->get_key = get_key_pixelview;
rc_proto = RC_PROTO_BIT_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x18:
case 0x1f:
case 0x1a:
name = "Hauppauge";
ir->get_key = get_key_haup;
rc_proto = RC_PROTO_BIT_RC5;
ir_codes = RC_MAP_HAUPPAUGE;
break;
case 0x30:
name = "KNC One";
ir->get_key = get_key_knc1;
rc_proto = RC_PROTO_BIT_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x33:
name = "Geniatech";
ir->get_key = get_key_geniatech;
rc_proto = RC_PROTO_BIT_RC5;
ir_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
ir->old = 0xfc;
break;
case 0x6b:
name = "FusionHDTV";
ir->get_key = get_key_fusionhdtv;
rc_proto = RC_PROTO_BIT_UNKNOWN;
ir_codes = RC_MAP_FUSIONHDTV_MCE;
break;
case 0x40:
name = "AVerMedia Cardbus remote";
ir->get_key = get_key_avermedia_cardbus;
rc_proto = RC_PROTO_BIT_OTHER;
ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
break;
case 0x41:
name = "AVerMedia EM78P153";
ir->get_key = get_key_avermedia_cardbus;
rc_proto = RC_PROTO_BIT_OTHER;
/* RM-KV remote, seems to be same as RM-K6 */
ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
break;
case 0x71:
name = "Hauppauge/Zilog Z8";
ir->get_key = get_key_haup_xvr;
rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
RC_PROTO_BIT_RC6_6A_32;
ir_codes = RC_MAP_HAUPPAUGE;
ir->polling_interval = 125;
probe_tx = true;
break;
}
/* Let the caller override settings */
if (client->dev.platform_data) {
const struct IR_i2c_init_data *init_data =
client->dev.platform_data;
ir_codes = init_data->ir_codes;
rc = init_data->rc_dev;
name = init_data->name;
if (init_data->type)
rc_proto = init_data->type;
if (init_data->polling_interval)
ir->polling_interval = init_data->polling_interval;
switch (init_data->internal_get_key_func) {
case IR_KBD_GET_KEY_CUSTOM:
/* The bridge driver provided us its own function */
ir->get_key = init_data->get_key;
break;
case IR_KBD_GET_KEY_PIXELVIEW:
ir->get_key = get_key_pixelview;
break;
case IR_KBD_GET_KEY_HAUP:
ir->get_key = get_key_haup;
break;
case IR_KBD_GET_KEY_KNC1:
ir->get_key = get_key_knc1;
break;
case IR_KBD_GET_KEY_GENIATECH:
ir->get_key = get_key_geniatech;
break;
case IR_KBD_GET_KEY_FUSIONHDTV:
ir->get_key = get_key_fusionhdtv;
break;
case IR_KBD_GET_KEY_HAUP_XVR:
ir->get_key = get_key_haup_xvr;
break;
case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS:
ir->get_key = get_key_avermedia_cardbus;
break;
}
}
if (!rc) {
/*
* If platform_data doesn't specify rc_dev, initialize it
* internally
*/
rc = rc_allocate_device(RC_DRIVER_SCANCODE);
if (!rc)
return -ENOMEM;
}
ir->rc = rc;
/* Make sure we are all setup before going on */
if (!name || !ir->get_key || !rc_proto || !ir_codes) {
dev_warn(&client->dev, "Unsupported device at address 0x%02x\n",
addr);
err = -ENODEV;
goto err_out_free;
}
ir->ir_codes = ir_codes;
snprintf(ir->phys, sizeof(ir->phys), "%s/%s", dev_name(&adap->dev),
dev_name(&client->dev));
/*
* Initialize input_dev fields
* It doesn't make sense to allow overriding them via platform_data
*/
rc->input_id.bustype = BUS_I2C;
rc->input_phys = ir->phys;
rc->device_name = name;
rc->dev.parent = &client->dev;
rc->priv = ir;
rc->open = ir_open;
rc->close = ir_close;
/*
* Initialize the other fields of rc_dev
*/
rc->map_name = ir->ir_codes;
rc->allowed_protocols = rc_proto;
if (!rc->driver_name)
rc->driver_name = KBUILD_MODNAME;
mutex_init(&ir->lock);
INIT_DELAYED_WORK(&ir->work, ir_work);
if (probe_tx) {
ir->tx_c = i2c_new_dummy_device(client->adapter, 0x70);
if (IS_ERR(ir->tx_c)) {
dev_err(&client->dev, "failed to setup tx i2c address");
err = PTR_ERR(ir->tx_c);
goto err_out_free;
} else if (!zilog_init(ir)) {
ir->carrier = 38000;
ir->duty_cycle = 40;
rc->tx_ir = zilog_tx;
rc->s_tx_carrier = zilog_tx_carrier;
rc->s_tx_duty_cycle = zilog_tx_duty_cycle;
}
}
err = rc_register_device(rc);
if (err)
goto err_out_free;
return 0;
err_out_free:
if (!IS_ERR(ir->tx_c))
i2c_unregister_device(ir->tx_c);
/* Only frees rc if it were allocated internally */
rc_free_device(rc);
return err;
}
i2c: Make remove callback return void The value returned by an i2c driver's remove function is mostly ignored. (Only an error message is printed if the value is non-zero that the error is ignored.) So change the prototype of the remove function to return no value. This way driver authors are not tempted to assume that passing an error to the upper layer is a good idea. All drivers are adapted accordingly. There is no intended change of behaviour, all callbacks were prepared to return 0 before. Reviewed-by: Peter Senna Tschudin <peter.senna@gmail.com> Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au> Reviewed-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Crt Mori <cmo@melexis.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Marek Behún <kabel@kernel.org> # for leds-turris-omnia Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Petr Machata <petrm@nvidia.com> # for mlxsw Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> # for surface3_power Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> # for bmc150-accel-i2c + kxcjk-1013 Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> # for media/* + staging/media/* Acked-by: Miguel Ojeda <ojeda@kernel.org> # for auxdisplay/ht16k33 + auxdisplay/lcd2s Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # for versaclock5 Reviewed-by: Ajay Gupta <ajayg@nvidia.com> # for ucsi_ccg Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> # for iio Acked-by: Peter Rosin <peda@axentia.se> # for i2c-mux-*, max9860 Acked-by: Adrien Grassein <adrien.grassein@gmail.com> # for lontium-lt8912b Reviewed-by: Jean Delvare <jdelvare@suse.de> # for hwmon, i2c-core and i2c/muxes Acked-by: Corey Minyard <cminyard@mvista.com> # for IPMI Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com> # for drivers/power Acked-by: Krzysztof Hałasa <khalasa@piap.pl> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Wolfram Sang <wsa@kernel.org>
2022-08-15 16:02:30 +08:00
static void ir_remove(struct i2c_client *client)
{
struct IR_i2c *ir = i2c_get_clientdata(client);
cancel_delayed_work_sync(&ir->work);
i2c_unregister_device(ir->tx_c);
rc_unregister_device(ir->rc);
}
static const struct i2c_device_id ir_kbd_id[] = {
/* Generic entry for any IR receiver */
{ "ir_video", 0 },
/* IR device specific entries should be added here */
{ "ir_z8f0811_haup", FLAG_TX },
{ "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR },
{ }
};
MODULE_DEVICE_TABLE(i2c, ir_kbd_id);
static struct i2c_driver ir_kbd_driver = {
.driver = {
.name = "ir-kbd-i2c",
},
.probe = ir_probe,
.remove = ir_remove,
.id_table = ir_kbd_id,
};
module_i2c_driver(ir_kbd_driver);
/* ----------------------------------------------------------------------- */
MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
MODULE_DESCRIPTION("input driver for i2c IR remote controls");
MODULE_LICENSE("GPL");