1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * 3cb7a01acSMauro Carvalho Chehab * keyboard input driver for i2c IR remote controls 4cb7a01acSMauro Carvalho Chehab * 5cb7a01acSMauro Carvalho Chehab * Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org> 6cb7a01acSMauro Carvalho Chehab * modified for PixelView (BT878P+W/FM) by 7cb7a01acSMauro Carvalho Chehab * Michal Kochanowicz <mkochano@pld.org.pl> 8cb7a01acSMauro Carvalho Chehab * Christoph Bartelmus <lirc@bartelmus.de> 9cb7a01acSMauro Carvalho Chehab * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by 10cb7a01acSMauro Carvalho Chehab * Ulrich Mueller <ulrich.mueller42@web.de> 11cb7a01acSMauro Carvalho Chehab * modified for em2820 based USB TV tuners by 12cb7a01acSMauro Carvalho Chehab * Markus Rechberger <mrechberger@gmail.com> 13cb7a01acSMauro Carvalho Chehab * modified for DViCO Fusion HDTV 5 RT GOLD by 14cb7a01acSMauro Carvalho Chehab * Chaogui Zhang <czhang1974@gmail.com> 15cb7a01acSMauro Carvalho Chehab * modified for MSI TV@nywhere Plus by 16cb7a01acSMauro Carvalho Chehab * Henry Wong <henry@stuffedcow.net> 17cb7a01acSMauro Carvalho Chehab * Mark Schultz <n9xmj@yahoo.com> 18cb7a01acSMauro Carvalho Chehab * Brian Rogers <brian_rogers@comcast.net> 19cb7a01acSMauro Carvalho Chehab * modified for AVerMedia Cardbus by 20cb7a01acSMauro Carvalho Chehab * Oldrich Jedlicka <oldium.pro@seznam.cz> 21cb7a01acSMauro Carvalho Chehab * 22cb7a01acSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 23cb7a01acSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 24cb7a01acSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 25cb7a01acSMauro Carvalho Chehab * (at your option) any later version. 26cb7a01acSMauro Carvalho Chehab * 27cb7a01acSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 28cb7a01acSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 29cb7a01acSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30cb7a01acSMauro Carvalho Chehab * GNU General Public License for more details. 31cb7a01acSMauro Carvalho Chehab * 32cb7a01acSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 33cb7a01acSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 34cb7a01acSMauro Carvalho Chehab * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 35cb7a01acSMauro Carvalho Chehab * 36cb7a01acSMauro Carvalho Chehab */ 37cb7a01acSMauro Carvalho Chehab 38cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 39cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 40cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 41cb7a01acSMauro Carvalho Chehab #include <linux/string.h> 42cb7a01acSMauro Carvalho Chehab #include <linux/timer.h> 43cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 44cb7a01acSMauro Carvalho Chehab #include <linux/errno.h> 45cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 46cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 47cb7a01acSMauro Carvalho Chehab #include <linux/workqueue.h> 48cb7a01acSMauro Carvalho Chehab 49cb7a01acSMauro Carvalho Chehab #include <media/rc-core.h> 50cb7a01acSMauro Carvalho Chehab #include <media/ir-kbd-i2c.h> 51cb7a01acSMauro Carvalho Chehab 52cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 53cb7a01acSMauro Carvalho Chehab /* insmod parameters */ 54cb7a01acSMauro Carvalho Chehab 55cb7a01acSMauro Carvalho Chehab static int debug; 56cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0644); /* debug level (0,1,2) */ 57cb7a01acSMauro Carvalho Chehab 58cb7a01acSMauro Carvalho Chehab 59cb7a01acSMauro Carvalho Chehab #define MODULE_NAME "ir-kbd-i2c" 60cb7a01acSMauro Carvalho Chehab #define dprintk(level, fmt, arg...) if (debug >= level) \ 61cb7a01acSMauro Carvalho Chehab printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) 62cb7a01acSMauro Carvalho Chehab 63cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 64cb7a01acSMauro Carvalho Chehab 65cb7a01acSMauro Carvalho Chehab static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, 66cb7a01acSMauro Carvalho Chehab int size, int offset) 67cb7a01acSMauro Carvalho Chehab { 68cb7a01acSMauro Carvalho Chehab unsigned char buf[6]; 69cb7a01acSMauro Carvalho Chehab int start, range, toggle, dev, code, ircode; 70cb7a01acSMauro Carvalho Chehab 71cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 72cb7a01acSMauro Carvalho Chehab if (size != i2c_master_recv(ir->c, buf, size)) 73cb7a01acSMauro Carvalho Chehab return -EIO; 74cb7a01acSMauro Carvalho Chehab 75cb7a01acSMauro Carvalho Chehab /* split rc5 data block ... */ 76cb7a01acSMauro Carvalho Chehab start = (buf[offset] >> 7) & 1; 77cb7a01acSMauro Carvalho Chehab range = (buf[offset] >> 6) & 1; 78cb7a01acSMauro Carvalho Chehab toggle = (buf[offset] >> 5) & 1; 79cb7a01acSMauro Carvalho Chehab dev = buf[offset] & 0x1f; 80cb7a01acSMauro Carvalho Chehab code = (buf[offset+1] >> 2) & 0x3f; 81cb7a01acSMauro Carvalho Chehab 82cb7a01acSMauro Carvalho Chehab /* rc5 has two start bits 83cb7a01acSMauro Carvalho Chehab * the first bit must be one 84cb7a01acSMauro Carvalho Chehab * the second bit defines the command range (1 = 0-63, 0 = 64 - 127) 85cb7a01acSMauro Carvalho Chehab */ 86cb7a01acSMauro Carvalho Chehab if (!start) 87cb7a01acSMauro Carvalho Chehab /* no key pressed */ 88cb7a01acSMauro Carvalho Chehab return 0; 89cb7a01acSMauro Carvalho Chehab /* 90cb7a01acSMauro Carvalho Chehab * Hauppauge remotes (black/silver) always use 91cb7a01acSMauro Carvalho Chehab * specific device ids. If we do not filter the 92cb7a01acSMauro Carvalho Chehab * device ids then messages destined for devices 93cb7a01acSMauro Carvalho Chehab * such as TVs (id=0) will get through causing 94cb7a01acSMauro Carvalho Chehab * mis-fired events. 95cb7a01acSMauro Carvalho Chehab * 96cb7a01acSMauro Carvalho Chehab * We also filter out invalid key presses which 97cb7a01acSMauro Carvalho Chehab * produce annoying debug log entries. 98cb7a01acSMauro Carvalho Chehab */ 99cb7a01acSMauro Carvalho Chehab ircode= (start << 12) | (toggle << 11) | (dev << 6) | code; 100cb7a01acSMauro Carvalho Chehab if ((ircode & 0x1fff)==0x1fff) 101cb7a01acSMauro Carvalho Chehab /* invalid key press */ 102cb7a01acSMauro Carvalho Chehab return 0; 103cb7a01acSMauro Carvalho Chehab 104cb7a01acSMauro Carvalho Chehab if (!range) 105cb7a01acSMauro Carvalho Chehab code += 64; 106cb7a01acSMauro Carvalho Chehab 107cb7a01acSMauro Carvalho Chehab dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", 108cb7a01acSMauro Carvalho Chehab start, range, toggle, dev, code); 109cb7a01acSMauro Carvalho Chehab 110cb7a01acSMauro Carvalho Chehab /* return key */ 111cb7a01acSMauro Carvalho Chehab *ir_key = (dev << 8) | code; 112cb7a01acSMauro Carvalho Chehab *ir_raw = ircode; 113cb7a01acSMauro Carvalho Chehab return 1; 114cb7a01acSMauro Carvalho Chehab } 115cb7a01acSMauro Carvalho Chehab 116cb7a01acSMauro Carvalho Chehab static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) 117cb7a01acSMauro Carvalho Chehab { 118cb7a01acSMauro Carvalho Chehab return get_key_haup_common (ir, ir_key, ir_raw, 3, 0); 119cb7a01acSMauro Carvalho Chehab } 120cb7a01acSMauro Carvalho Chehab 121cb7a01acSMauro Carvalho Chehab static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) 122cb7a01acSMauro Carvalho Chehab { 123cb7a01acSMauro Carvalho Chehab int ret; 124cb7a01acSMauro Carvalho Chehab unsigned char buf[1] = { 0 }; 125cb7a01acSMauro Carvalho Chehab 126cb7a01acSMauro Carvalho Chehab /* 127cb7a01acSMauro Carvalho Chehab * This is the same apparent "are you ready?" poll command observed 128cb7a01acSMauro Carvalho Chehab * watching Windows driver traffic and implemented in lirc_zilog. With 129cb7a01acSMauro Carvalho Chehab * this added, we get far saner remote behavior with z8 chips on usb 130cb7a01acSMauro Carvalho Chehab * connected devices, even with the default polling interval of 100ms. 131cb7a01acSMauro Carvalho Chehab */ 132cb7a01acSMauro Carvalho Chehab ret = i2c_master_send(ir->c, buf, 1); 133cb7a01acSMauro Carvalho Chehab if (ret != 1) 134cb7a01acSMauro Carvalho Chehab return (ret < 0) ? ret : -EINVAL; 135cb7a01acSMauro Carvalho Chehab 136cb7a01acSMauro Carvalho Chehab return get_key_haup_common (ir, ir_key, ir_raw, 6, 3); 137cb7a01acSMauro Carvalho Chehab } 138cb7a01acSMauro Carvalho Chehab 139cb7a01acSMauro Carvalho Chehab static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) 140cb7a01acSMauro Carvalho Chehab { 141cb7a01acSMauro Carvalho Chehab unsigned char b; 142cb7a01acSMauro Carvalho Chehab 143cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 144cb7a01acSMauro Carvalho Chehab if (1 != i2c_master_recv(ir->c, &b, 1)) { 145cb7a01acSMauro Carvalho Chehab dprintk(1,"read error\n"); 146cb7a01acSMauro Carvalho Chehab return -EIO; 147cb7a01acSMauro Carvalho Chehab } 148cb7a01acSMauro Carvalho Chehab *ir_key = b; 149cb7a01acSMauro Carvalho Chehab *ir_raw = b; 150cb7a01acSMauro Carvalho Chehab return 1; 151cb7a01acSMauro Carvalho Chehab } 152cb7a01acSMauro Carvalho Chehab 153cb7a01acSMauro Carvalho Chehab static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) 154cb7a01acSMauro Carvalho Chehab { 155cb7a01acSMauro Carvalho Chehab unsigned char buf[4]; 156cb7a01acSMauro Carvalho Chehab 157cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 158cb7a01acSMauro Carvalho Chehab if (4 != i2c_master_recv(ir->c, buf, 4)) { 159cb7a01acSMauro Carvalho Chehab dprintk(1,"read error\n"); 160cb7a01acSMauro Carvalho Chehab return -EIO; 161cb7a01acSMauro Carvalho Chehab } 162cb7a01acSMauro Carvalho Chehab 163cb7a01acSMauro Carvalho Chehab if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) 164cb7a01acSMauro Carvalho Chehab dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__, 165cb7a01acSMauro Carvalho Chehab buf[0], buf[1], buf[2], buf[3]); 166cb7a01acSMauro Carvalho Chehab 167cb7a01acSMauro Carvalho Chehab /* no key pressed or signal from other ir remote */ 168cb7a01acSMauro Carvalho Chehab if(buf[0] != 0x1 || buf[1] != 0xfe) 169cb7a01acSMauro Carvalho Chehab return 0; 170cb7a01acSMauro Carvalho Chehab 171cb7a01acSMauro Carvalho Chehab *ir_key = buf[2]; 172cb7a01acSMauro Carvalho Chehab *ir_raw = (buf[2] << 8) | buf[3]; 173cb7a01acSMauro Carvalho Chehab 174cb7a01acSMauro Carvalho Chehab return 1; 175cb7a01acSMauro Carvalho Chehab } 176cb7a01acSMauro Carvalho Chehab 177cb7a01acSMauro Carvalho Chehab static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) 178cb7a01acSMauro Carvalho Chehab { 179cb7a01acSMauro Carvalho Chehab unsigned char b; 180cb7a01acSMauro Carvalho Chehab 181cb7a01acSMauro Carvalho Chehab /* poll IR chip */ 182cb7a01acSMauro Carvalho Chehab if (1 != i2c_master_recv(ir->c, &b, 1)) { 183cb7a01acSMauro Carvalho Chehab dprintk(1,"read error\n"); 184cb7a01acSMauro Carvalho Chehab return -EIO; 185cb7a01acSMauro Carvalho Chehab } 186cb7a01acSMauro Carvalho Chehab 187cb7a01acSMauro Carvalho Chehab /* it seems that 0xFE indicates that a button is still hold 188cb7a01acSMauro Carvalho Chehab down, while 0xff indicates that no button is hold 189cb7a01acSMauro Carvalho Chehab down. 0xfe sequences are sometimes interrupted by 0xFF */ 190cb7a01acSMauro Carvalho Chehab 191cb7a01acSMauro Carvalho Chehab dprintk(2,"key %02x\n", b); 192cb7a01acSMauro Carvalho Chehab 193cb7a01acSMauro Carvalho Chehab if (b == 0xff) 194cb7a01acSMauro Carvalho Chehab return 0; 195cb7a01acSMauro Carvalho Chehab 196cb7a01acSMauro Carvalho Chehab if (b == 0xfe) 197cb7a01acSMauro Carvalho Chehab /* keep old data */ 198cb7a01acSMauro Carvalho Chehab return 1; 199cb7a01acSMauro Carvalho Chehab 200cb7a01acSMauro Carvalho Chehab *ir_key = b; 201cb7a01acSMauro Carvalho Chehab *ir_raw = b; 202cb7a01acSMauro Carvalho Chehab return 1; 203cb7a01acSMauro Carvalho Chehab } 204cb7a01acSMauro Carvalho Chehab 205cb7a01acSMauro Carvalho Chehab static int get_key_avermedia_cardbus(struct IR_i2c *ir, 206cb7a01acSMauro Carvalho Chehab u32 *ir_key, u32 *ir_raw) 207cb7a01acSMauro Carvalho Chehab { 208cb7a01acSMauro Carvalho Chehab unsigned char subaddr, key, keygroup; 209cb7a01acSMauro Carvalho Chehab struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, 210cb7a01acSMauro Carvalho Chehab .buf = &subaddr, .len = 1}, 211cb7a01acSMauro Carvalho Chehab { .addr = ir->c->addr, .flags = I2C_M_RD, 212cb7a01acSMauro Carvalho Chehab .buf = &key, .len = 1} }; 213cb7a01acSMauro Carvalho Chehab subaddr = 0x0d; 214cb7a01acSMauro Carvalho Chehab if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { 215cb7a01acSMauro Carvalho Chehab dprintk(1, "read error\n"); 216cb7a01acSMauro Carvalho Chehab return -EIO; 217cb7a01acSMauro Carvalho Chehab } 218cb7a01acSMauro Carvalho Chehab 219cb7a01acSMauro Carvalho Chehab if (key == 0xff) 220cb7a01acSMauro Carvalho Chehab return 0; 221cb7a01acSMauro Carvalho Chehab 222cb7a01acSMauro Carvalho Chehab subaddr = 0x0b; 223cb7a01acSMauro Carvalho Chehab msg[1].buf = &keygroup; 224cb7a01acSMauro Carvalho Chehab if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { 225cb7a01acSMauro Carvalho Chehab dprintk(1, "read error\n"); 226cb7a01acSMauro Carvalho Chehab return -EIO; 227cb7a01acSMauro Carvalho Chehab } 228cb7a01acSMauro Carvalho Chehab 229cb7a01acSMauro Carvalho Chehab if (keygroup == 0xff) 230cb7a01acSMauro Carvalho Chehab return 0; 231cb7a01acSMauro Carvalho Chehab 232cb7a01acSMauro Carvalho Chehab dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); 233cb7a01acSMauro Carvalho Chehab if (keygroup < 2 || keygroup > 3) { 234cb7a01acSMauro Carvalho Chehab /* Only a warning */ 235cb7a01acSMauro Carvalho Chehab dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", 236cb7a01acSMauro Carvalho Chehab keygroup, key); 237cb7a01acSMauro Carvalho Chehab } 238cb7a01acSMauro Carvalho Chehab key |= (keygroup & 1) << 6; 239cb7a01acSMauro Carvalho Chehab 240cb7a01acSMauro Carvalho Chehab *ir_key = key; 241cb7a01acSMauro Carvalho Chehab *ir_raw = key; 242cb7a01acSMauro Carvalho Chehab return 1; 243cb7a01acSMauro Carvalho Chehab } 244cb7a01acSMauro Carvalho Chehab 245cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 246cb7a01acSMauro Carvalho Chehab 247cb7a01acSMauro Carvalho Chehab static int ir_key_poll(struct IR_i2c *ir) 248cb7a01acSMauro Carvalho Chehab { 249cb7a01acSMauro Carvalho Chehab static u32 ir_key, ir_raw; 250cb7a01acSMauro Carvalho Chehab int rc; 251cb7a01acSMauro Carvalho Chehab 252cb7a01acSMauro Carvalho Chehab dprintk(3, "%s\n", __func__); 253cb7a01acSMauro Carvalho Chehab rc = ir->get_key(ir, &ir_key, &ir_raw); 254cb7a01acSMauro Carvalho Chehab if (rc < 0) { 255cb7a01acSMauro Carvalho Chehab dprintk(2,"error\n"); 256cb7a01acSMauro Carvalho Chehab return rc; 257cb7a01acSMauro Carvalho Chehab } 258cb7a01acSMauro Carvalho Chehab 259cb7a01acSMauro Carvalho Chehab if (rc) { 260cb7a01acSMauro Carvalho Chehab dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); 261cb7a01acSMauro Carvalho Chehab rc_keydown(ir->rc, ir_key, 0); 262cb7a01acSMauro Carvalho Chehab } 263cb7a01acSMauro Carvalho Chehab return 0; 264cb7a01acSMauro Carvalho Chehab } 265cb7a01acSMauro Carvalho Chehab 266cb7a01acSMauro Carvalho Chehab static void ir_work(struct work_struct *work) 267cb7a01acSMauro Carvalho Chehab { 268cb7a01acSMauro Carvalho Chehab int rc; 269cb7a01acSMauro Carvalho Chehab struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); 270cb7a01acSMauro Carvalho Chehab 271cb7a01acSMauro Carvalho Chehab rc = ir_key_poll(ir); 272cb7a01acSMauro Carvalho Chehab if (rc == -ENODEV) { 273cb7a01acSMauro Carvalho Chehab rc_unregister_device(ir->rc); 274cb7a01acSMauro Carvalho Chehab ir->rc = NULL; 275cb7a01acSMauro Carvalho Chehab return; 276cb7a01acSMauro Carvalho Chehab } 277cb7a01acSMauro Carvalho Chehab 278cb7a01acSMauro Carvalho Chehab schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); 279cb7a01acSMauro Carvalho Chehab } 280cb7a01acSMauro Carvalho Chehab 281cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 282cb7a01acSMauro Carvalho Chehab 283cb7a01acSMauro Carvalho Chehab static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) 284cb7a01acSMauro Carvalho Chehab { 285cb7a01acSMauro Carvalho Chehab char *ir_codes = NULL; 286cb7a01acSMauro Carvalho Chehab const char *name = NULL; 287*c003ab1bSDavid Härdeman u64 rc_type = RC_BIT_UNKNOWN; 288cb7a01acSMauro Carvalho Chehab struct IR_i2c *ir; 289cb7a01acSMauro Carvalho Chehab struct rc_dev *rc = NULL; 290cb7a01acSMauro Carvalho Chehab struct i2c_adapter *adap = client->adapter; 291cb7a01acSMauro Carvalho Chehab unsigned short addr = client->addr; 292cb7a01acSMauro Carvalho Chehab int err; 293cb7a01acSMauro Carvalho Chehab 294cb7a01acSMauro Carvalho Chehab ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL); 295cb7a01acSMauro Carvalho Chehab if (!ir) 296cb7a01acSMauro Carvalho Chehab return -ENOMEM; 297cb7a01acSMauro Carvalho Chehab 298cb7a01acSMauro Carvalho Chehab ir->c = client; 299cb7a01acSMauro Carvalho Chehab ir->polling_interval = DEFAULT_POLLING_INTERVAL; 300cb7a01acSMauro Carvalho Chehab i2c_set_clientdata(client, ir); 301cb7a01acSMauro Carvalho Chehab 302cb7a01acSMauro Carvalho Chehab switch(addr) { 303cb7a01acSMauro Carvalho Chehab case 0x64: 304cb7a01acSMauro Carvalho Chehab name = "Pixelview"; 305cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_pixelview; 306*c003ab1bSDavid Härdeman rc_type = RC_BIT_OTHER; 307cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_EMPTY; 308cb7a01acSMauro Carvalho Chehab break; 309cb7a01acSMauro Carvalho Chehab case 0x18: 310cb7a01acSMauro Carvalho Chehab case 0x1f: 311cb7a01acSMauro Carvalho Chehab case 0x1a: 312cb7a01acSMauro Carvalho Chehab name = "Hauppauge"; 313cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup; 314*c003ab1bSDavid Härdeman rc_type = RC_BIT_RC5; 315cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_HAUPPAUGE; 316cb7a01acSMauro Carvalho Chehab break; 317cb7a01acSMauro Carvalho Chehab case 0x30: 318cb7a01acSMauro Carvalho Chehab name = "KNC One"; 319cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_knc1; 320*c003ab1bSDavid Härdeman rc_type = RC_BIT_OTHER; 321cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_EMPTY; 322cb7a01acSMauro Carvalho Chehab break; 323cb7a01acSMauro Carvalho Chehab case 0x6b: 324cb7a01acSMauro Carvalho Chehab name = "FusionHDTV"; 325cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_fusionhdtv; 326*c003ab1bSDavid Härdeman rc_type = RC_BIT_RC5; 327cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_FUSIONHDTV_MCE; 328cb7a01acSMauro Carvalho Chehab break; 329cb7a01acSMauro Carvalho Chehab case 0x40: 330cb7a01acSMauro Carvalho Chehab name = "AVerMedia Cardbus remote"; 331cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_avermedia_cardbus; 332*c003ab1bSDavid Härdeman rc_type = RC_BIT_OTHER; 333cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_AVERMEDIA_CARDBUS; 334cb7a01acSMauro Carvalho Chehab break; 335cb7a01acSMauro Carvalho Chehab case 0x71: 336cb7a01acSMauro Carvalho Chehab name = "Hauppauge/Zilog Z8"; 337cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup_xvr; 338*c003ab1bSDavid Härdeman rc_type = RC_BIT_RC5; 339cb7a01acSMauro Carvalho Chehab ir_codes = RC_MAP_HAUPPAUGE; 340cb7a01acSMauro Carvalho Chehab break; 341cb7a01acSMauro Carvalho Chehab } 342cb7a01acSMauro Carvalho Chehab 343cb7a01acSMauro Carvalho Chehab /* Let the caller override settings */ 344cb7a01acSMauro Carvalho Chehab if (client->dev.platform_data) { 345cb7a01acSMauro Carvalho Chehab const struct IR_i2c_init_data *init_data = 346cb7a01acSMauro Carvalho Chehab client->dev.platform_data; 347cb7a01acSMauro Carvalho Chehab 348cb7a01acSMauro Carvalho Chehab ir_codes = init_data->ir_codes; 349cb7a01acSMauro Carvalho Chehab rc = init_data->rc_dev; 350cb7a01acSMauro Carvalho Chehab 351cb7a01acSMauro Carvalho Chehab name = init_data->name; 352cb7a01acSMauro Carvalho Chehab if (init_data->type) 353cb7a01acSMauro Carvalho Chehab rc_type = init_data->type; 354cb7a01acSMauro Carvalho Chehab 355cb7a01acSMauro Carvalho Chehab if (init_data->polling_interval) 356cb7a01acSMauro Carvalho Chehab ir->polling_interval = init_data->polling_interval; 357cb7a01acSMauro Carvalho Chehab 358cb7a01acSMauro Carvalho Chehab switch (init_data->internal_get_key_func) { 359cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_CUSTOM: 360cb7a01acSMauro Carvalho Chehab /* The bridge driver provided us its own function */ 361cb7a01acSMauro Carvalho Chehab ir->get_key = init_data->get_key; 362cb7a01acSMauro Carvalho Chehab break; 363cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_PIXELVIEW: 364cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_pixelview; 365cb7a01acSMauro Carvalho Chehab break; 366cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_HAUP: 367cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup; 368cb7a01acSMauro Carvalho Chehab break; 369cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_KNC1: 370cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_knc1; 371cb7a01acSMauro Carvalho Chehab break; 372cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_FUSIONHDTV: 373cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_fusionhdtv; 374cb7a01acSMauro Carvalho Chehab break; 375cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_HAUP_XVR: 376cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_haup_xvr; 377cb7a01acSMauro Carvalho Chehab break; 378cb7a01acSMauro Carvalho Chehab case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS: 379cb7a01acSMauro Carvalho Chehab ir->get_key = get_key_avermedia_cardbus; 380cb7a01acSMauro Carvalho Chehab break; 381cb7a01acSMauro Carvalho Chehab } 382cb7a01acSMauro Carvalho Chehab } 383cb7a01acSMauro Carvalho Chehab 384cb7a01acSMauro Carvalho Chehab if (!rc) { 385cb7a01acSMauro Carvalho Chehab /* 386cb7a01acSMauro Carvalho Chehab * If platform_data doesn't specify rc_dev, initilize it 387cb7a01acSMauro Carvalho Chehab * internally 388cb7a01acSMauro Carvalho Chehab */ 389cb7a01acSMauro Carvalho Chehab rc = rc_allocate_device(); 390cb7a01acSMauro Carvalho Chehab if (!rc) { 391cb7a01acSMauro Carvalho Chehab err = -ENOMEM; 392cb7a01acSMauro Carvalho Chehab goto err_out_free; 393cb7a01acSMauro Carvalho Chehab } 394cb7a01acSMauro Carvalho Chehab } 395cb7a01acSMauro Carvalho Chehab ir->rc = rc; 396cb7a01acSMauro Carvalho Chehab 397cb7a01acSMauro Carvalho Chehab /* Make sure we are all setup before going on */ 398cb7a01acSMauro Carvalho Chehab if (!name || !ir->get_key || !rc_type || !ir_codes) { 399cb7a01acSMauro Carvalho Chehab dprintk(1, ": Unsupported device at address 0x%02x\n", 400cb7a01acSMauro Carvalho Chehab addr); 401cb7a01acSMauro Carvalho Chehab err = -ENODEV; 402cb7a01acSMauro Carvalho Chehab goto err_out_free; 403cb7a01acSMauro Carvalho Chehab } 404cb7a01acSMauro Carvalho Chehab 405cb7a01acSMauro Carvalho Chehab /* Sets name */ 406cb7a01acSMauro Carvalho Chehab snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); 407cb7a01acSMauro Carvalho Chehab ir->ir_codes = ir_codes; 408cb7a01acSMauro Carvalho Chehab 409cb7a01acSMauro Carvalho Chehab snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", 410cb7a01acSMauro Carvalho Chehab dev_name(&adap->dev), 411cb7a01acSMauro Carvalho Chehab dev_name(&client->dev)); 412cb7a01acSMauro Carvalho Chehab 413cb7a01acSMauro Carvalho Chehab /* 414cb7a01acSMauro Carvalho Chehab * Initialize input_dev fields 415cb7a01acSMauro Carvalho Chehab * It doesn't make sense to allow overriding them via platform_data 416cb7a01acSMauro Carvalho Chehab */ 417cb7a01acSMauro Carvalho Chehab rc->input_id.bustype = BUS_I2C; 418cb7a01acSMauro Carvalho Chehab rc->input_phys = ir->phys; 419cb7a01acSMauro Carvalho Chehab rc->input_name = ir->name; 420cb7a01acSMauro Carvalho Chehab 421cb7a01acSMauro Carvalho Chehab /* 422cb7a01acSMauro Carvalho Chehab * Initialize the other fields of rc_dev 423cb7a01acSMauro Carvalho Chehab */ 424cb7a01acSMauro Carvalho Chehab rc->map_name = ir->ir_codes; 425cb7a01acSMauro Carvalho Chehab rc->allowed_protos = rc_type; 426cb7a01acSMauro Carvalho Chehab if (!rc->driver_name) 427cb7a01acSMauro Carvalho Chehab rc->driver_name = MODULE_NAME; 428cb7a01acSMauro Carvalho Chehab 429cb7a01acSMauro Carvalho Chehab err = rc_register_device(rc); 430cb7a01acSMauro Carvalho Chehab if (err) 431cb7a01acSMauro Carvalho Chehab goto err_out_free; 432cb7a01acSMauro Carvalho Chehab 433cb7a01acSMauro Carvalho Chehab printk(MODULE_NAME ": %s detected at %s [%s]\n", 434cb7a01acSMauro Carvalho Chehab ir->name, ir->phys, adap->name); 435cb7a01acSMauro Carvalho Chehab 436cb7a01acSMauro Carvalho Chehab /* start polling via eventd */ 437cb7a01acSMauro Carvalho Chehab INIT_DELAYED_WORK(&ir->work, ir_work); 438cb7a01acSMauro Carvalho Chehab schedule_delayed_work(&ir->work, 0); 439cb7a01acSMauro Carvalho Chehab 440cb7a01acSMauro Carvalho Chehab return 0; 441cb7a01acSMauro Carvalho Chehab 442cb7a01acSMauro Carvalho Chehab err_out_free: 443cb7a01acSMauro Carvalho Chehab /* Only frees rc if it were allocated internally */ 444cb7a01acSMauro Carvalho Chehab rc_free_device(rc); 445cb7a01acSMauro Carvalho Chehab kfree(ir); 446cb7a01acSMauro Carvalho Chehab return err; 447cb7a01acSMauro Carvalho Chehab } 448cb7a01acSMauro Carvalho Chehab 449cb7a01acSMauro Carvalho Chehab static int ir_remove(struct i2c_client *client) 450cb7a01acSMauro Carvalho Chehab { 451cb7a01acSMauro Carvalho Chehab struct IR_i2c *ir = i2c_get_clientdata(client); 452cb7a01acSMauro Carvalho Chehab 453cb7a01acSMauro Carvalho Chehab /* kill outstanding polls */ 454cb7a01acSMauro Carvalho Chehab cancel_delayed_work_sync(&ir->work); 455cb7a01acSMauro Carvalho Chehab 456cb7a01acSMauro Carvalho Chehab /* unregister device */ 457cb7a01acSMauro Carvalho Chehab if (ir->rc) 458cb7a01acSMauro Carvalho Chehab rc_unregister_device(ir->rc); 459cb7a01acSMauro Carvalho Chehab 460cb7a01acSMauro Carvalho Chehab /* free memory */ 461cb7a01acSMauro Carvalho Chehab kfree(ir); 462cb7a01acSMauro Carvalho Chehab return 0; 463cb7a01acSMauro Carvalho Chehab } 464cb7a01acSMauro Carvalho Chehab 465cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id ir_kbd_id[] = { 466cb7a01acSMauro Carvalho Chehab /* Generic entry for any IR receiver */ 467cb7a01acSMauro Carvalho Chehab { "ir_video", 0 }, 468cb7a01acSMauro Carvalho Chehab /* IR device specific entries should be added here */ 469cb7a01acSMauro Carvalho Chehab { "ir_rx_z8f0811_haup", 0 }, 470cb7a01acSMauro Carvalho Chehab { "ir_rx_z8f0811_hdpvr", 0 }, 471cb7a01acSMauro Carvalho Chehab { } 472cb7a01acSMauro Carvalho Chehab }; 473cb7a01acSMauro Carvalho Chehab 474cb7a01acSMauro Carvalho Chehab static struct i2c_driver ir_kbd_driver = { 475cb7a01acSMauro Carvalho Chehab .driver = { 476cb7a01acSMauro Carvalho Chehab .name = "ir-kbd-i2c", 477cb7a01acSMauro Carvalho Chehab }, 478cb7a01acSMauro Carvalho Chehab .probe = ir_probe, 479cb7a01acSMauro Carvalho Chehab .remove = ir_remove, 480cb7a01acSMauro Carvalho Chehab .id_table = ir_kbd_id, 481cb7a01acSMauro Carvalho Chehab }; 482cb7a01acSMauro Carvalho Chehab 483cb7a01acSMauro Carvalho Chehab module_i2c_driver(ir_kbd_driver); 484cb7a01acSMauro Carvalho Chehab 485cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 486cb7a01acSMauro Carvalho Chehab 487cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); 488cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("input driver for i2c IR remote controls"); 489cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 490