18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * keyboard input driver for i2c IR remote controls 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org> 78c2ecf20Sopenharmony_ci * modified for PixelView (BT878P+W/FM) by 88c2ecf20Sopenharmony_ci * Michal Kochanowicz <mkochano@pld.org.pl> 98c2ecf20Sopenharmony_ci * Christoph Bartelmus <lirc@bartelmus.de> 108c2ecf20Sopenharmony_ci * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by 118c2ecf20Sopenharmony_ci * Ulrich Mueller <ulrich.mueller42@web.de> 128c2ecf20Sopenharmony_ci * modified for em2820 based USB TV tuners by 138c2ecf20Sopenharmony_ci * Markus Rechberger <mrechberger@gmail.com> 148c2ecf20Sopenharmony_ci * modified for DViCO Fusion HDTV 5 RT GOLD by 158c2ecf20Sopenharmony_ci * Chaogui Zhang <czhang1974@gmail.com> 168c2ecf20Sopenharmony_ci * modified for MSI TV@nywhere Plus by 178c2ecf20Sopenharmony_ci * Henry Wong <henry@stuffedcow.net> 188c2ecf20Sopenharmony_ci * Mark Schultz <n9xmj@yahoo.com> 198c2ecf20Sopenharmony_ci * Brian Rogers <brian_rogers@comcast.net> 208c2ecf20Sopenharmony_ci * modified for AVerMedia Cardbus by 218c2ecf20Sopenharmony_ci * Oldrich Jedlicka <oldium.pro@seznam.cz> 228c2ecf20Sopenharmony_ci * Zilog Transmitter portions/ideas were derived from GPLv2+ sources: 238c2ecf20Sopenharmony_ci * - drivers/char/pctv_zilogir.[ch] from Hauppauge Broadway product 248c2ecf20Sopenharmony_ci * Copyright 2011 Hauppauge Computer works 258c2ecf20Sopenharmony_ci * - drivers/staging/media/lirc/lirc_zilog.c 268c2ecf20Sopenharmony_ci * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> 278c2ecf20Sopenharmony_ci * Michal Kochanowicz <mkochano@pld.org.pl> 288c2ecf20Sopenharmony_ci * Christoph Bartelmus <lirc@bartelmus.de> 298c2ecf20Sopenharmony_ci * Ulrich Mueller <ulrich.mueller42@web.de> 308c2ecf20Sopenharmony_ci * Stefan Jahn <stefan@lkcc.org> 318c2ecf20Sopenharmony_ci * Jerome Brock <jbrock@users.sourceforge.net> 328c2ecf20Sopenharmony_ci * Thomas Reitmayr (treitmayr@yahoo.com) 338c2ecf20Sopenharmony_ci * Mark Weaver <mark@npsl.co.uk> 348c2ecf20Sopenharmony_ci * Jarod Wilson <jarod@redhat.com> 358c2ecf20Sopenharmony_ci * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net> 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 398c2ecf20Sopenharmony_ci#include <linux/module.h> 408c2ecf20Sopenharmony_ci#include <linux/init.h> 418c2ecf20Sopenharmony_ci#include <linux/kernel.h> 428c2ecf20Sopenharmony_ci#include <linux/string.h> 438c2ecf20Sopenharmony_ci#include <linux/timer.h> 448c2ecf20Sopenharmony_ci#include <linux/delay.h> 458c2ecf20Sopenharmony_ci#include <linux/errno.h> 468c2ecf20Sopenharmony_ci#include <linux/slab.h> 478c2ecf20Sopenharmony_ci#include <linux/i2c.h> 488c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <media/rc-core.h> 518c2ecf20Sopenharmony_ci#include <media/i2c/ir-kbd-i2c.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define FLAG_TX 1 548c2ecf20Sopenharmony_ci#define FLAG_HDPVR 2 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic bool enable_hdpvr; 578c2ecf20Sopenharmony_cimodule_param(enable_hdpvr, bool, 0644); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, 608c2ecf20Sopenharmony_ci u32 *scancode, u8 *ptoggle, int size) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned char buf[6]; 638c2ecf20Sopenharmony_ci int start, range, toggle, dev, code, ircode, vendor; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* poll IR chip */ 668c2ecf20Sopenharmony_ci if (size != i2c_master_recv(ir->c, buf, size)) 678c2ecf20Sopenharmony_ci return -EIO; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (buf[0] & 0x80) { 708c2ecf20Sopenharmony_ci int offset = (size == 6) ? 3 : 0; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* split rc5 data block ... */ 738c2ecf20Sopenharmony_ci start = (buf[offset] >> 7) & 1; 748c2ecf20Sopenharmony_ci range = (buf[offset] >> 6) & 1; 758c2ecf20Sopenharmony_ci toggle = (buf[offset] >> 5) & 1; 768c2ecf20Sopenharmony_ci dev = buf[offset] & 0x1f; 778c2ecf20Sopenharmony_ci code = (buf[offset+1] >> 2) & 0x3f; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* rc5 has two start bits 808c2ecf20Sopenharmony_ci * the first bit must be one 818c2ecf20Sopenharmony_ci * the second bit defines the command range: 828c2ecf20Sopenharmony_ci * 1 = 0-63, 0 = 64 - 127 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci if (!start) 858c2ecf20Sopenharmony_ci /* no key pressed */ 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* filter out invalid key presses */ 898c2ecf20Sopenharmony_ci ircode = (start << 12) | (toggle << 11) | (dev << 6) | code; 908c2ecf20Sopenharmony_ci if ((ircode & 0x1fff) == 0x1fff) 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!range) 948c2ecf20Sopenharmony_ci code += 64; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, 978c2ecf20Sopenharmony_ci "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", 988c2ecf20Sopenharmony_ci start, range, toggle, dev, code); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci *protocol = RC_PROTO_RC5; 1018c2ecf20Sopenharmony_ci *scancode = RC_SCANCODE_RC5(dev, code); 1028c2ecf20Sopenharmony_ci *ptoggle = toggle; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return 1; 1058c2ecf20Sopenharmony_ci } else if (size == 6 && (buf[0] & 0x40)) { 1068c2ecf20Sopenharmony_ci code = buf[4]; 1078c2ecf20Sopenharmony_ci dev = buf[3]; 1088c2ecf20Sopenharmony_ci vendor = get_unaligned_be16(buf + 1); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (vendor == 0x800f) { 1118c2ecf20Sopenharmony_ci *ptoggle = (dev & 0x80) != 0; 1128c2ecf20Sopenharmony_ci *protocol = RC_PROTO_RC6_MCE; 1138c2ecf20Sopenharmony_ci dev &= 0x7f; 1148c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, 1158c2ecf20Sopenharmony_ci "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", 1168c2ecf20Sopenharmony_ci *ptoggle, vendor, dev, code); 1178c2ecf20Sopenharmony_ci } else { 1188c2ecf20Sopenharmony_ci *ptoggle = 0; 1198c2ecf20Sopenharmony_ci *protocol = RC_PROTO_RC6_6A_32; 1208c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, 1218c2ecf20Sopenharmony_ci "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", 1228c2ecf20Sopenharmony_ci vendor, dev, code); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci *scancode = RC_SCANCODE_RC6_6A(vendor, dev, code); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return 1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int get_key_haup(struct IR_i2c *ir, enum rc_proto *protocol, 1348c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return get_key_haup_common(ir, protocol, scancode, toggle, 3); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol, 1408c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci unsigned char buf[1] = { 0 }; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * This is the same apparent "are you ready?" poll command observed 1478c2ecf20Sopenharmony_ci * watching Windows driver traffic and implemented in lirc_zilog. With 1488c2ecf20Sopenharmony_ci * this added, we get far saner remote behavior with z8 chips on usb 1498c2ecf20Sopenharmony_ci * connected devices, even with the default polling interval of 100ms. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci ret = i2c_master_send(ir->c, buf, 1); 1528c2ecf20Sopenharmony_ci if (ret != 1) 1538c2ecf20Sopenharmony_ci return (ret < 0) ? ret : -EINVAL; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return get_key_haup_common(ir, protocol, scancode, toggle, 6); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, 1598c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci int rc; 1628c2ecf20Sopenharmony_ci unsigned char b; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* poll IR chip */ 1658c2ecf20Sopenharmony_ci rc = i2c_master_recv(ir->c, &b, 1); 1668c2ecf20Sopenharmony_ci if (rc != 1) { 1678c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "read error\n"); 1688c2ecf20Sopenharmony_ci if (rc < 0) 1698c2ecf20Sopenharmony_ci return rc; 1708c2ecf20Sopenharmony_ci return -EIO; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci *protocol = RC_PROTO_OTHER; 1748c2ecf20Sopenharmony_ci *scancode = b; 1758c2ecf20Sopenharmony_ci *toggle = 0; 1768c2ecf20Sopenharmony_ci return 1; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, 1808c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci int rc; 1838c2ecf20Sopenharmony_ci unsigned char buf[4]; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* poll IR chip */ 1868c2ecf20Sopenharmony_ci rc = i2c_master_recv(ir->c, buf, 4); 1878c2ecf20Sopenharmony_ci if (rc != 4) { 1888c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "read error\n"); 1898c2ecf20Sopenharmony_ci if (rc < 0) 1908c2ecf20Sopenharmony_ci return rc; 1918c2ecf20Sopenharmony_ci return -EIO; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0 || buf[3] != 0) 1958c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "%s: %*ph\n", __func__, 4, buf); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* no key pressed or signal from other ir remote */ 1988c2ecf20Sopenharmony_ci if(buf[0] != 0x1 || buf[1] != 0xfe) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci *protocol = RC_PROTO_UNKNOWN; 2028c2ecf20Sopenharmony_ci *scancode = buf[2]; 2038c2ecf20Sopenharmony_ci *toggle = 0; 2048c2ecf20Sopenharmony_ci return 1; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, 2088c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int rc; 2118c2ecf20Sopenharmony_ci unsigned char b; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* poll IR chip */ 2148c2ecf20Sopenharmony_ci rc = i2c_master_recv(ir->c, &b, 1); 2158c2ecf20Sopenharmony_ci if (rc != 1) { 2168c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "read error\n"); 2178c2ecf20Sopenharmony_ci if (rc < 0) 2188c2ecf20Sopenharmony_ci return rc; 2198c2ecf20Sopenharmony_ci return -EIO; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* it seems that 0xFE indicates that a button is still hold 2238c2ecf20Sopenharmony_ci down, while 0xff indicates that no button is hold 2248c2ecf20Sopenharmony_ci down. 0xfe sequences are sometimes interrupted by 0xFF */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "key %02x\n", b); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (b == 0xff) 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (b == 0xfe) 2328c2ecf20Sopenharmony_ci /* keep old data */ 2338c2ecf20Sopenharmony_ci return 1; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci *protocol = RC_PROTO_UNKNOWN; 2368c2ecf20Sopenharmony_ci *scancode = b; 2378c2ecf20Sopenharmony_ci *toggle = 0; 2388c2ecf20Sopenharmony_ci return 1; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, 2428c2ecf20Sopenharmony_ci u32 *scancode, u8 *toggle) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci unsigned char subaddr, key, keygroup; 2458c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, 2468c2ecf20Sopenharmony_ci .buf = &subaddr, .len = 1}, 2478c2ecf20Sopenharmony_ci { .addr = ir->c->addr, .flags = I2C_M_RD, 2488c2ecf20Sopenharmony_ci .buf = &key, .len = 1} }; 2498c2ecf20Sopenharmony_ci subaddr = 0x0d; 2508c2ecf20Sopenharmony_ci if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { 2518c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "read error\n"); 2528c2ecf20Sopenharmony_ci return -EIO; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (key == 0xff) 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci subaddr = 0x0b; 2598c2ecf20Sopenharmony_ci msg[1].buf = &keygroup; 2608c2ecf20Sopenharmony_ci if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { 2618c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "read error\n"); 2628c2ecf20Sopenharmony_ci return -EIO; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (keygroup == 0xff) 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "read key 0x%02x/0x%02x\n", key, keygroup); 2698c2ecf20Sopenharmony_ci if (keygroup < 2 || keygroup > 4) { 2708c2ecf20Sopenharmony_ci dev_warn(&ir->rc->dev, "warning: invalid key group 0x%02x for key 0x%02x\n", 2718c2ecf20Sopenharmony_ci keygroup, key); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci key |= (keygroup & 1) << 6; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci *protocol = RC_PROTO_UNKNOWN; 2768c2ecf20Sopenharmony_ci *scancode = key; 2778c2ecf20Sopenharmony_ci if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */ 2788c2ecf20Sopenharmony_ci *scancode |= keygroup << 8; 2798c2ecf20Sopenharmony_ci *toggle = 0; 2808c2ecf20Sopenharmony_ci return 1; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int ir_key_poll(struct IR_i2c *ir) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci enum rc_proto protocol; 2888c2ecf20Sopenharmony_ci u32 scancode; 2898c2ecf20Sopenharmony_ci u8 toggle; 2908c2ecf20Sopenharmony_ci int rc; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "%s\n", __func__); 2938c2ecf20Sopenharmony_ci rc = ir->get_key(ir, &protocol, &scancode, &toggle); 2948c2ecf20Sopenharmony_ci if (rc < 0) { 2958c2ecf20Sopenharmony_ci dev_warn(&ir->rc->dev, "error %d\n", rc); 2968c2ecf20Sopenharmony_ci return rc; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (rc) { 3008c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "%s: proto = 0x%04x, scancode = 0x%08x\n", 3018c2ecf20Sopenharmony_ci __func__, protocol, scancode); 3028c2ecf20Sopenharmony_ci rc_keydown(ir->rc, protocol, scancode, toggle); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void ir_work(struct work_struct *work) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * If the transmit code is holding the lock, skip polling for 3148c2ecf20Sopenharmony_ci * IR, we'll get it to it next time round 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci if (mutex_trylock(&ir->lock)) { 3178c2ecf20Sopenharmony_ci rc = ir_key_poll(ir); 3188c2ecf20Sopenharmony_ci mutex_unlock(&ir->lock); 3198c2ecf20Sopenharmony_ci if (rc == -ENODEV) { 3208c2ecf20Sopenharmony_ci rc_unregister_device(ir->rc); 3218c2ecf20Sopenharmony_ci ir->rc = NULL; 3228c2ecf20Sopenharmony_ci return; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int ir_open(struct rc_dev *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct IR_i2c *ir = dev->priv; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci schedule_delayed_work(&ir->work, 0); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void ir_close(struct rc_dev *dev) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct IR_i2c *ir = dev->priv; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ir->work); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* Zilog Transmit Interface */ 3468c2ecf20Sopenharmony_ci#define XTAL_FREQ 18432000 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci#define ZILOG_SEND 0x80 3498c2ecf20Sopenharmony_ci#define ZILOG_UIR_END 0x40 3508c2ecf20Sopenharmony_ci#define ZILOG_INIT_END 0x20 3518c2ecf20Sopenharmony_ci#define ZILOG_LIR_END 0x10 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci#define ZILOG_STATUS_OK 0x80 3548c2ecf20Sopenharmony_ci#define ZILOG_STATUS_TX 0x40 3558c2ecf20Sopenharmony_ci#define ZILOG_STATUS_SET 0x20 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* 3588c2ecf20Sopenharmony_ci * As you can see here, very few different lengths of pulse and space 3598c2ecf20Sopenharmony_ci * can be encoded. This means that the hardware does not work well with 3608c2ecf20Sopenharmony_ci * recorded IR. It's best to work with generated IR, like from ir-ctl or 3618c2ecf20Sopenharmony_ci * the in-kernel encoders. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_cistruct code_block { 3648c2ecf20Sopenharmony_ci u8 length; 3658c2ecf20Sopenharmony_ci u16 pulse[7]; /* not aligned */ 3668c2ecf20Sopenharmony_ci u8 carrier_pulse; 3678c2ecf20Sopenharmony_ci u8 carrier_space; 3688c2ecf20Sopenharmony_ci u16 space[8]; /* not aligned */ 3698c2ecf20Sopenharmony_ci u8 codes[61]; 3708c2ecf20Sopenharmony_ci u8 csum[2]; 3718c2ecf20Sopenharmony_ci} __packed; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int send_data_block(struct IR_i2c *ir, int cmd, 3748c2ecf20Sopenharmony_ci struct code_block *code_block) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci int i, j, ret; 3778c2ecf20Sopenharmony_ci u8 buf[5], *p; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci p = &code_block->length; 3808c2ecf20Sopenharmony_ci for (i = 0; p < code_block->csum; i++) 3818c2ecf20Sopenharmony_ci code_block->csum[i & 1] ^= *p++; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci p = &code_block->length; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(*code_block);) { 3868c2ecf20Sopenharmony_ci int tosend = sizeof(*code_block) - i; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (tosend > 4) 3898c2ecf20Sopenharmony_ci tosend = 4; 3908c2ecf20Sopenharmony_ci buf[0] = i + 1; 3918c2ecf20Sopenharmony_ci for (j = 0; j < tosend; ++j) 3928c2ecf20Sopenharmony_ci buf[1 + j] = p[i + j]; 3938c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "%*ph", tosend + 1, buf); 3948c2ecf20Sopenharmony_ci ret = i2c_master_send(ir->tx_c, buf, tosend + 1); 3958c2ecf20Sopenharmony_ci if (ret != tosend + 1) { 3968c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, 3978c2ecf20Sopenharmony_ci "i2c_master_send failed with %d\n", ret); 3988c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci i += tosend; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci buf[0] = 0; 4048c2ecf20Sopenharmony_ci buf[1] = cmd; 4058c2ecf20Sopenharmony_ci ret = i2c_master_send(ir->tx_c, buf, 2); 4068c2ecf20Sopenharmony_ci if (ret != 2) { 4078c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); 4088c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci usleep_range(2000, 5000); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ret = i2c_master_send(ir->tx_c, buf, 1); 4148c2ecf20Sopenharmony_ci if (ret != 1) { 4158c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); 4168c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int zilog_init(struct IR_i2c *ir) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct code_block code_block = { .length = sizeof(code_block) }; 4258c2ecf20Sopenharmony_ci u8 buf[4]; 4268c2ecf20Sopenharmony_ci int ret; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci put_unaligned_be16(0x1000, &code_block.pulse[3]); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci ret = send_data_block(ir, ZILOG_INIT_END, &code_block); 4318c2ecf20Sopenharmony_ci if (ret) 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = i2c_master_recv(ir->tx_c, buf, 4); 4358c2ecf20Sopenharmony_ci if (ret != 4) { 4368c2ecf20Sopenharmony_ci dev_err(&ir->c->dev, "failed to retrieve firmware version: %d\n", 4378c2ecf20Sopenharmony_ci ret); 4388c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci dev_info(&ir->c->dev, "Zilog/Hauppauge IR blaster firmware version %d.%d.%d\n", 4428c2ecf20Sopenharmony_ci buf[1], buf[2], buf[3]); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/* 4488c2ecf20Sopenharmony_ci * If the last slot for pulse is the same as the current slot for pulse, 4498c2ecf20Sopenharmony_ci * then use slot no 7. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_cistatic void copy_codes(u8 *dst, u8 *src, unsigned int count) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci u8 c, last = 0xff; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci while (count--) { 4568c2ecf20Sopenharmony_ci c = *src++; 4578c2ecf20Sopenharmony_ci if ((c & 0xf0) == last) { 4588c2ecf20Sopenharmony_ci *dst++ = 0x70 | (c & 0xf); 4598c2ecf20Sopenharmony_ci } else { 4608c2ecf20Sopenharmony_ci *dst++ = c; 4618c2ecf20Sopenharmony_ci last = c & 0xf0; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* 4678c2ecf20Sopenharmony_ci * When looking for repeats, we don't care about the trailing space. This 4688c2ecf20Sopenharmony_ci * is set to the shortest possible anyway. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_cistatic int cmp_no_trail(u8 *a, u8 *b, unsigned int count) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci while (--count) { 4738c2ecf20Sopenharmony_ci if (*a++ != *b++) 4748c2ecf20Sopenharmony_ci return 1; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return (*a & 0xf0) - (*b & 0xf0); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int find_slot(u16 *array, unsigned int size, u16 val) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci int i; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 4858c2ecf20Sopenharmony_ci if (get_unaligned_be16(&array[i]) == val) { 4868c2ecf20Sopenharmony_ci return i; 4878c2ecf20Sopenharmony_ci } else if (!array[i]) { 4888c2ecf20Sopenharmony_ci put_unaligned_be16(val, &array[i]); 4898c2ecf20Sopenharmony_ci return i; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return -1; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf, 4978c2ecf20Sopenharmony_ci unsigned int count, struct code_block *code_block) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct IR_i2c *ir = rcdev->priv; 5008c2ecf20Sopenharmony_ci int rep, i, l, p = 0, s, c = 0; 5018c2ecf20Sopenharmony_ci bool repeating; 5028c2ecf20Sopenharmony_ci u8 codes[174]; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci code_block->carrier_pulse = DIV_ROUND_CLOSEST( 5058c2ecf20Sopenharmony_ci ir->duty_cycle * XTAL_FREQ / 1000, ir->carrier); 5068c2ecf20Sopenharmony_ci code_block->carrier_space = DIV_ROUND_CLOSEST( 5078c2ecf20Sopenharmony_ci (100 - ir->duty_cycle) * XTAL_FREQ / 1000, ir->carrier); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 5108c2ecf20Sopenharmony_ci if (c >= ARRAY_SIZE(codes) - 1) { 5118c2ecf20Sopenharmony_ci dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); 5128c2ecf20Sopenharmony_ci return -EINVAL; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * Lengths more than 142220us cannot be encoded; also 5178c2ecf20Sopenharmony_ci * this checks for multiply overflow 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci if (txbuf[i] > 142220) 5208c2ecf20Sopenharmony_ci return -EINVAL; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci l = DIV_ROUND_CLOSEST((XTAL_FREQ / 1000) * txbuf[i], 40000); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (i & 1) { 5258c2ecf20Sopenharmony_ci s = find_slot(code_block->space, 5268c2ecf20Sopenharmony_ci ARRAY_SIZE(code_block->space), l); 5278c2ecf20Sopenharmony_ci if (s == -1) { 5288c2ecf20Sopenharmony_ci dev_warn(&rcdev->dev, "Too many different lengths spaces, cannot transmit"); 5298c2ecf20Sopenharmony_ci return -EINVAL; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* We have a pulse and space */ 5338c2ecf20Sopenharmony_ci codes[c++] = (p << 4) | s; 5348c2ecf20Sopenharmony_ci } else { 5358c2ecf20Sopenharmony_ci p = find_slot(code_block->pulse, 5368c2ecf20Sopenharmony_ci ARRAY_SIZE(code_block->pulse), l); 5378c2ecf20Sopenharmony_ci if (p == -1) { 5388c2ecf20Sopenharmony_ci dev_warn(&rcdev->dev, "Too many different lengths pulses, cannot transmit"); 5398c2ecf20Sopenharmony_ci return -EINVAL; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* We have to encode the trailing pulse. Find the shortest space */ 5458c2ecf20Sopenharmony_ci s = 0; 5468c2ecf20Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(code_block->space); i++) { 5478c2ecf20Sopenharmony_ci u16 d = get_unaligned_be16(&code_block->space[i]); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (get_unaligned_be16(&code_block->space[s]) > d) 5508c2ecf20Sopenharmony_ci s = i; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci codes[c++] = (p << 4) | s; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci dev_dbg(&rcdev->dev, "generated %d codes\n", c); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* 5588c2ecf20Sopenharmony_ci * Are the last N codes (so pulse + space) repeating 3 times? 5598c2ecf20Sopenharmony_ci * if so we can shorten the codes list and use code 0xc0 to repeat 5608c2ecf20Sopenharmony_ci * them. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci repeating = false; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci for (rep = c / 3; rep >= 1; rep--) { 5658c2ecf20Sopenharmony_ci if (!memcmp(&codes[c - rep * 3], &codes[c - rep * 2], rep) && 5668c2ecf20Sopenharmony_ci !cmp_no_trail(&codes[c - rep], &codes[c - rep * 2], rep)) { 5678c2ecf20Sopenharmony_ci repeating = true; 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (repeating) { 5738c2ecf20Sopenharmony_ci /* first copy any leading non-repeating */ 5748c2ecf20Sopenharmony_ci int leading = c - rep * 3; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (leading >= ARRAY_SIZE(code_block->codes) - 3 - rep) { 5778c2ecf20Sopenharmony_ci dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); 5788c2ecf20Sopenharmony_ci return -EINVAL; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dev_dbg(&rcdev->dev, "found trailing %d repeat\n", rep); 5828c2ecf20Sopenharmony_ci copy_codes(code_block->codes, codes, leading); 5838c2ecf20Sopenharmony_ci code_block->codes[leading] = 0x82; 5848c2ecf20Sopenharmony_ci copy_codes(code_block->codes + leading + 1, codes + leading, 5858c2ecf20Sopenharmony_ci rep); 5868c2ecf20Sopenharmony_ci c = leading + 1 + rep; 5878c2ecf20Sopenharmony_ci code_block->codes[c++] = 0xc0; 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci if (c >= ARRAY_SIZE(code_block->codes) - 3) { 5908c2ecf20Sopenharmony_ci dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); 5918c2ecf20Sopenharmony_ci return -EINVAL; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci dev_dbg(&rcdev->dev, "found no trailing repeat\n"); 5958c2ecf20Sopenharmony_ci code_block->codes[0] = 0x82; 5968c2ecf20Sopenharmony_ci copy_codes(code_block->codes + 1, codes, c); 5978c2ecf20Sopenharmony_ci c++; 5988c2ecf20Sopenharmony_ci code_block->codes[c++] = 0xc4; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci while (c < ARRAY_SIZE(code_block->codes)) 6028c2ecf20Sopenharmony_ci code_block->codes[c++] = 0x83; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf, 6088c2ecf20Sopenharmony_ci unsigned int count) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct IR_i2c *ir = rcdev->priv; 6118c2ecf20Sopenharmony_ci struct code_block code_block = { .length = sizeof(code_block) }; 6128c2ecf20Sopenharmony_ci u8 buf[2]; 6138c2ecf20Sopenharmony_ci int ret, i; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci ret = zilog_ir_format(rcdev, txbuf, count, &code_block); 6168c2ecf20Sopenharmony_ci if (ret) 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&ir->lock); 6208c2ecf20Sopenharmony_ci if (ret) 6218c2ecf20Sopenharmony_ci return ret; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ret = send_data_block(ir, ZILOG_UIR_END, &code_block); 6248c2ecf20Sopenharmony_ci if (ret) 6258c2ecf20Sopenharmony_ci goto out_unlock; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci ret = i2c_master_recv(ir->tx_c, buf, 1); 6288c2ecf20Sopenharmony_ci if (ret != 1) { 6298c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret); 6308c2ecf20Sopenharmony_ci goto out_unlock; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "code set status: %02x\n", buf[0]); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (buf[0] != (ZILOG_STATUS_OK | ZILOG_STATUS_SET)) { 6368c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "unexpected IR TX response %02x\n", 6378c2ecf20Sopenharmony_ci buf[0]); 6388c2ecf20Sopenharmony_ci ret = -EIO; 6398c2ecf20Sopenharmony_ci goto out_unlock; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci buf[0] = 0x00; 6438c2ecf20Sopenharmony_ci buf[1] = ZILOG_SEND; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci ret = i2c_master_send(ir->tx_c, buf, 2); 6468c2ecf20Sopenharmony_ci if (ret != 2) { 6478c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); 6488c2ecf20Sopenharmony_ci if (ret >= 0) 6498c2ecf20Sopenharmony_ci ret = -EIO; 6508c2ecf20Sopenharmony_ci goto out_unlock; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "send command sent\n"); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* 6568c2ecf20Sopenharmony_ci * This bit NAKs until the device is ready, so we retry it 6578c2ecf20Sopenharmony_ci * sleeping a bit each time. This seems to be what the windows 6588c2ecf20Sopenharmony_ci * driver does, approximately. 6598c2ecf20Sopenharmony_ci * Try for up to 1s. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci for (i = 0; i < 20; ++i) { 6628c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 6638c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(50)); 6648c2ecf20Sopenharmony_ci ret = i2c_master_send(ir->tx_c, buf, 1); 6658c2ecf20Sopenharmony_ci if (ret == 1) 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, 6688c2ecf20Sopenharmony_ci "NAK expected: i2c_master_send failed with %d (try %d)\n", 6698c2ecf20Sopenharmony_ci ret, i + 1); 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (ret != 1) { 6738c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, 6748c2ecf20Sopenharmony_ci "IR TX chip never got ready: last i2c_master_send failed with %d\n", 6758c2ecf20Sopenharmony_ci ret); 6768c2ecf20Sopenharmony_ci if (ret >= 0) 6778c2ecf20Sopenharmony_ci ret = -EIO; 6788c2ecf20Sopenharmony_ci goto out_unlock; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci ret = i2c_master_recv(ir->tx_c, buf, 1); 6828c2ecf20Sopenharmony_ci if (ret != 1) { 6838c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret); 6848c2ecf20Sopenharmony_ci ret = -EIO; 6858c2ecf20Sopenharmony_ci goto out_unlock; 6868c2ecf20Sopenharmony_ci } else if (buf[0] != ZILOG_STATUS_OK) { 6878c2ecf20Sopenharmony_ci dev_err(&ir->rc->dev, "unexpected IR TX response #2: %02x\n", 6888c2ecf20Sopenharmony_ci buf[0]); 6898c2ecf20Sopenharmony_ci ret = -EIO; 6908c2ecf20Sopenharmony_ci goto out_unlock; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci dev_dbg(&ir->rc->dev, "transmit complete\n"); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* Oh good, it worked */ 6958c2ecf20Sopenharmony_ci ret = count; 6968c2ecf20Sopenharmony_ciout_unlock: 6978c2ecf20Sopenharmony_ci mutex_unlock(&ir->lock); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return ret; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int zilog_tx_carrier(struct rc_dev *dev, u32 carrier) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct IR_i2c *ir = dev->priv; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (carrier > 500000 || carrier < 20000) 7078c2ecf20Sopenharmony_ci return -EINVAL; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci ir->carrier = carrier; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int zilog_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct IR_i2c *ir = dev->priv; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ir->duty_cycle = duty_cycle; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci char *ir_codes = NULL; 7268c2ecf20Sopenharmony_ci const char *name = NULL; 7278c2ecf20Sopenharmony_ci u64 rc_proto = RC_PROTO_BIT_UNKNOWN; 7288c2ecf20Sopenharmony_ci struct IR_i2c *ir; 7298c2ecf20Sopenharmony_ci struct rc_dev *rc = NULL; 7308c2ecf20Sopenharmony_ci struct i2c_adapter *adap = client->adapter; 7318c2ecf20Sopenharmony_ci unsigned short addr = client->addr; 7328c2ecf20Sopenharmony_ci bool probe_tx = (id->driver_data & FLAG_TX) != 0; 7338c2ecf20Sopenharmony_ci int err; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if ((id->driver_data & FLAG_HDPVR) && !enable_hdpvr) { 7368c2ecf20Sopenharmony_ci dev_err(&client->dev, "IR for HDPVR is known to cause problems during recording, use enable_hdpvr modparam to enable\n"); 7378c2ecf20Sopenharmony_ci return -ENODEV; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL); 7418c2ecf20Sopenharmony_ci if (!ir) 7428c2ecf20Sopenharmony_ci return -ENOMEM; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci ir->c = client; 7458c2ecf20Sopenharmony_ci ir->polling_interval = DEFAULT_POLLING_INTERVAL; 7468c2ecf20Sopenharmony_ci i2c_set_clientdata(client, ir); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci switch(addr) { 7498c2ecf20Sopenharmony_ci case 0x64: 7508c2ecf20Sopenharmony_ci name = "Pixelview"; 7518c2ecf20Sopenharmony_ci ir->get_key = get_key_pixelview; 7528c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_OTHER; 7538c2ecf20Sopenharmony_ci ir_codes = RC_MAP_EMPTY; 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci case 0x18: 7568c2ecf20Sopenharmony_ci case 0x1f: 7578c2ecf20Sopenharmony_ci case 0x1a: 7588c2ecf20Sopenharmony_ci name = "Hauppauge"; 7598c2ecf20Sopenharmony_ci ir->get_key = get_key_haup; 7608c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_RC5; 7618c2ecf20Sopenharmony_ci ir_codes = RC_MAP_HAUPPAUGE; 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci case 0x30: 7648c2ecf20Sopenharmony_ci name = "KNC One"; 7658c2ecf20Sopenharmony_ci ir->get_key = get_key_knc1; 7668c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_OTHER; 7678c2ecf20Sopenharmony_ci ir_codes = RC_MAP_EMPTY; 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci case 0x6b: 7708c2ecf20Sopenharmony_ci name = "FusionHDTV"; 7718c2ecf20Sopenharmony_ci ir->get_key = get_key_fusionhdtv; 7728c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_UNKNOWN; 7738c2ecf20Sopenharmony_ci ir_codes = RC_MAP_FUSIONHDTV_MCE; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci case 0x40: 7768c2ecf20Sopenharmony_ci name = "AVerMedia Cardbus remote"; 7778c2ecf20Sopenharmony_ci ir->get_key = get_key_avermedia_cardbus; 7788c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_OTHER; 7798c2ecf20Sopenharmony_ci ir_codes = RC_MAP_AVERMEDIA_CARDBUS; 7808c2ecf20Sopenharmony_ci break; 7818c2ecf20Sopenharmony_ci case 0x41: 7828c2ecf20Sopenharmony_ci name = "AVerMedia EM78P153"; 7838c2ecf20Sopenharmony_ci ir->get_key = get_key_avermedia_cardbus; 7848c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_OTHER; 7858c2ecf20Sopenharmony_ci /* RM-KV remote, seems to be same as RM-K6 */ 7868c2ecf20Sopenharmony_ci ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case 0x71: 7898c2ecf20Sopenharmony_ci name = "Hauppauge/Zilog Z8"; 7908c2ecf20Sopenharmony_ci ir->get_key = get_key_haup_xvr; 7918c2ecf20Sopenharmony_ci rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | 7928c2ecf20Sopenharmony_ci RC_PROTO_BIT_RC6_6A_32; 7938c2ecf20Sopenharmony_ci ir_codes = RC_MAP_HAUPPAUGE; 7948c2ecf20Sopenharmony_ci ir->polling_interval = 125; 7958c2ecf20Sopenharmony_ci probe_tx = true; 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Let the caller override settings */ 8008c2ecf20Sopenharmony_ci if (client->dev.platform_data) { 8018c2ecf20Sopenharmony_ci const struct IR_i2c_init_data *init_data = 8028c2ecf20Sopenharmony_ci client->dev.platform_data; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci ir_codes = init_data->ir_codes; 8058c2ecf20Sopenharmony_ci rc = init_data->rc_dev; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci name = init_data->name; 8088c2ecf20Sopenharmony_ci if (init_data->type) 8098c2ecf20Sopenharmony_ci rc_proto = init_data->type; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (init_data->polling_interval) 8128c2ecf20Sopenharmony_ci ir->polling_interval = init_data->polling_interval; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci switch (init_data->internal_get_key_func) { 8158c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_CUSTOM: 8168c2ecf20Sopenharmony_ci /* The bridge driver provided us its own function */ 8178c2ecf20Sopenharmony_ci ir->get_key = init_data->get_key; 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_PIXELVIEW: 8208c2ecf20Sopenharmony_ci ir->get_key = get_key_pixelview; 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_HAUP: 8238c2ecf20Sopenharmony_ci ir->get_key = get_key_haup; 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_KNC1: 8268c2ecf20Sopenharmony_ci ir->get_key = get_key_knc1; 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_FUSIONHDTV: 8298c2ecf20Sopenharmony_ci ir->get_key = get_key_fusionhdtv; 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_HAUP_XVR: 8328c2ecf20Sopenharmony_ci ir->get_key = get_key_haup_xvr; 8338c2ecf20Sopenharmony_ci break; 8348c2ecf20Sopenharmony_ci case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS: 8358c2ecf20Sopenharmony_ci ir->get_key = get_key_avermedia_cardbus; 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (!rc) { 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci * If platform_data doesn't specify rc_dev, initialize it 8438c2ecf20Sopenharmony_ci * internally 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_ci rc = rc_allocate_device(RC_DRIVER_SCANCODE); 8468c2ecf20Sopenharmony_ci if (!rc) 8478c2ecf20Sopenharmony_ci return -ENOMEM; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci ir->rc = rc; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* Make sure we are all setup before going on */ 8528c2ecf20Sopenharmony_ci if (!name || !ir->get_key || !rc_proto || !ir_codes) { 8538c2ecf20Sopenharmony_ci dev_warn(&client->dev, "Unsupported device at address 0x%02x\n", 8548c2ecf20Sopenharmony_ci addr); 8558c2ecf20Sopenharmony_ci err = -ENODEV; 8568c2ecf20Sopenharmony_ci goto err_out_free; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci ir->ir_codes = ir_codes; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci snprintf(ir->phys, sizeof(ir->phys), "%s/%s", dev_name(&adap->dev), 8628c2ecf20Sopenharmony_ci dev_name(&client->dev)); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* 8658c2ecf20Sopenharmony_ci * Initialize input_dev fields 8668c2ecf20Sopenharmony_ci * It doesn't make sense to allow overriding them via platform_data 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci rc->input_id.bustype = BUS_I2C; 8698c2ecf20Sopenharmony_ci rc->input_phys = ir->phys; 8708c2ecf20Sopenharmony_ci rc->device_name = name; 8718c2ecf20Sopenharmony_ci rc->dev.parent = &client->dev; 8728c2ecf20Sopenharmony_ci rc->priv = ir; 8738c2ecf20Sopenharmony_ci rc->open = ir_open; 8748c2ecf20Sopenharmony_ci rc->close = ir_close; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* 8778c2ecf20Sopenharmony_ci * Initialize the other fields of rc_dev 8788c2ecf20Sopenharmony_ci */ 8798c2ecf20Sopenharmony_ci rc->map_name = ir->ir_codes; 8808c2ecf20Sopenharmony_ci rc->allowed_protocols = rc_proto; 8818c2ecf20Sopenharmony_ci if (!rc->driver_name) 8828c2ecf20Sopenharmony_ci rc->driver_name = KBUILD_MODNAME; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci mutex_init(&ir->lock); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ir->work, ir_work); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (probe_tx) { 8898c2ecf20Sopenharmony_ci ir->tx_c = i2c_new_dummy_device(client->adapter, 0x70); 8908c2ecf20Sopenharmony_ci if (IS_ERR(ir->tx_c)) { 8918c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to setup tx i2c address"); 8928c2ecf20Sopenharmony_ci err = PTR_ERR(ir->tx_c); 8938c2ecf20Sopenharmony_ci goto err_out_free; 8948c2ecf20Sopenharmony_ci } else if (!zilog_init(ir)) { 8958c2ecf20Sopenharmony_ci ir->carrier = 38000; 8968c2ecf20Sopenharmony_ci ir->duty_cycle = 40; 8978c2ecf20Sopenharmony_ci rc->tx_ir = zilog_tx; 8988c2ecf20Sopenharmony_ci rc->s_tx_carrier = zilog_tx_carrier; 8998c2ecf20Sopenharmony_ci rc->s_tx_duty_cycle = zilog_tx_duty_cycle; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci err = rc_register_device(rc); 9048c2ecf20Sopenharmony_ci if (err) 9058c2ecf20Sopenharmony_ci goto err_out_free; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return 0; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci err_out_free: 9108c2ecf20Sopenharmony_ci if (!IS_ERR(ir->tx_c)) 9118c2ecf20Sopenharmony_ci i2c_unregister_device(ir->tx_c); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Only frees rc if it were allocated internally */ 9148c2ecf20Sopenharmony_ci rc_free_device(rc); 9158c2ecf20Sopenharmony_ci return err; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int ir_remove(struct i2c_client *client) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct IR_i2c *ir = i2c_get_clientdata(client); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ir->work); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci i2c_unregister_device(ir->tx_c); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci rc_unregister_device(ir->rc); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic const struct i2c_device_id ir_kbd_id[] = { 9328c2ecf20Sopenharmony_ci /* Generic entry for any IR receiver */ 9338c2ecf20Sopenharmony_ci { "ir_video", 0 }, 9348c2ecf20Sopenharmony_ci /* IR device specific entries should be added here */ 9358c2ecf20Sopenharmony_ci { "ir_z8f0811_haup", FLAG_TX }, 9368c2ecf20Sopenharmony_ci { "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR }, 9378c2ecf20Sopenharmony_ci { } 9388c2ecf20Sopenharmony_ci}; 9398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ir_kbd_id); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic struct i2c_driver ir_kbd_driver = { 9428c2ecf20Sopenharmony_ci .driver = { 9438c2ecf20Sopenharmony_ci .name = "ir-kbd-i2c", 9448c2ecf20Sopenharmony_ci }, 9458c2ecf20Sopenharmony_ci .probe = ir_probe, 9468c2ecf20Sopenharmony_ci .remove = ir_remove, 9478c2ecf20Sopenharmony_ci .id_table = ir_kbd_id, 9488c2ecf20Sopenharmony_ci}; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cimodule_i2c_driver(ir_kbd_driver); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); 9558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("input driver for i2c IR remote controls"); 9568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 957