Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 357476
b: refs/heads/master
c: 768da3d
h: refs/heads/master
v: v3
  • Loading branch information
Frank Schaefer authored and Mauro Carvalho Chehab committed Feb 5, 2013
1 parent 7b1a087 commit 1909820
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 89 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 62ec3f86ff86483ae27b9411179b8ded74558c19
refs/heads/master: 768da3dbcf50b697e5e7a921492b7f0d2cd8a8fb
219 changes: 134 additions & 85 deletions trunk/drivers/media/usb/em28xx/em28xx-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,26 +62,31 @@ struct em28xx_IR {
char name[32];
char phys[32];

/* poll external decoder */
/* poll decoder */
int polling;
struct delayed_work work;
unsigned int full_code:1;
unsigned int last_readcount;
u64 rc_type;

/* external device (if used) */
struct i2c_client *i2c_dev;

int (*get_key_i2c)(struct i2c_client *, u32 *, u32 *);
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
};

/**********************************************************
I2C IR based get keycodes - should be used with ir-kbd-i2c
**********************************************************/

static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
u32 *ir_key, u32 *ir_raw)
{
unsigned char b;

/* poll IR chip */
if (1 != i2c_master_recv(ir->c, &b, 1))
if (1 != i2c_master_recv(i2c_dev, &b, 1))
return -EIO;

/* it seems that 0xFE indicates that a button is still hold
Expand All @@ -100,14 +105,15 @@ static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}

static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev,
u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[2];
u16 code;
int size;

/* poll IR chip */
size = i2c_master_recv(ir->c, buf, sizeof(buf));
size = i2c_master_recv(i2c_dev, buf, sizeof(buf));

if (size != 2)
return -EIO;
Expand Down Expand Up @@ -144,14 +150,14 @@ static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}

static int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw)
static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];

/* poll IR chip */

if (3 != i2c_master_recv(ir->c, buf, 3))
if (3 != i2c_master_recv(i2c_dev, buf, 3))
return -EIO;

if (buf[0] != 0x00)
Expand All @@ -163,24 +169,24 @@ static int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
return 1;
}

static int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw)
static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
u32 *ir_key, u32 *ir_raw)
{
unsigned char subaddr, keydetect, key;

struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1},
struct i2c_msg msg[] = { { .addr = i2c_dev->addr, .flags = 0, .buf = &subaddr, .len = 1},

{ .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
{ .addr = i2c_dev->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };

subaddr = 0x10;
if (2 != i2c_transfer(ir->c->adapter, msg, 2))
if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
return -EIO;
if (keydetect == 0x00)
return 0;

subaddr = 0x00;
msg[1].buf = &key;
if (2 != i2c_transfer(ir->c->adapter, msg, 2))
if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
return -EIO;
if (key == 0x00)
return 0;
Expand Down Expand Up @@ -280,6 +286,24 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
Polling code for em28xx
**********************************************************/

static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
{
static u32 ir_key, ir_raw;
int rc;

rc = ir->get_key_i2c(ir->i2c_dev, &ir_key, &ir_raw);
if (rc < 0) {
dprintk("ir->get_key_i2c() failed: %d\n", rc);
return rc;
}

if (rc) {
dprintk("%s: keycode = 0x%04x\n", __func__, ir_key);
rc_keydown(ir->rc, ir_key, 0);
}
return 0;
}

static void em28xx_ir_handle_key(struct em28xx_IR *ir)
{
int result;
Expand All @@ -288,7 +312,7 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
/* read the registers containing the IR status */
result = ir->get_key(ir, &poll_result);
if (unlikely(result < 0)) {
dprintk("ir->get_key() failed %d\n", result);
dprintk("ir->get_key() failed: %d\n", result);
return;
}

Expand Down Expand Up @@ -318,6 +342,14 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
}
}

static void em28xx_i2c_ir_work(struct work_struct *work)
{
struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);

em28xx_i2c_ir_handle_key(ir);
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}

static void em28xx_ir_work(struct work_struct *work)
{
struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
Expand All @@ -330,7 +362,10 @@ static int em28xx_ir_start(struct rc_dev *rc)
{
struct em28xx_IR *ir = rc->priv;

INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
if (ir->i2c_dev) /* external i2c device */
INIT_DELAYED_WORK(&ir->work, em28xx_i2c_ir_work);
else /* internal device */
INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
schedule_delayed_work(&ir->work, 0);

return 0;
Expand Down Expand Up @@ -427,49 +462,33 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
}
}

static void em28xx_register_i2c_ir(struct em28xx *dev)
static struct i2c_client *em28xx_probe_i2c_ir(struct em28xx *dev)
{
int i = 0;
struct i2c_client *i2c_dev = NULL;
/* Leadtek winfast tv USBII deluxe can find a non working IR-device */
/* at address 0x18, so if that address is needed for another board in */
/* the future, please put it after 0x1f. */
struct i2c_board_info info;
const unsigned short addr_list[] = {
0x1f, 0x30, 0x47, I2C_CLIENT_END
};

memset(&info, 0, sizeof(struct i2c_board_info));
memset(&dev->init_data, 0, sizeof(dev->init_data));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);

/* detect & configure */
switch (dev->model) {
case EM2800_BOARD_TERRATEC_CINERGY_200:
case EM2820_BOARD_TERRATEC_CINERGY_250:
dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
dev->init_data.get_key = em28xx_get_key_terratec;
dev->init_data.name = "Terratec Cinergy 200/250";
break;
case EM2820_BOARD_PINNACLE_USB_2:
dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
dev->init_data.name = "Pinnacle USB2";
break;
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
dev->init_data.get_key = em28xx_get_key_em_haup;
dev->init_data.name = "WinTV USB2";
dev->init_data.type = RC_BIT_RC5;
break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
dev->init_data.name = "Winfast TV USBII Deluxe";
break;
while (addr_list[i] != I2C_CLIENT_END) {
if (i2c_probe_func_quick_read(&dev->i2c_adap, addr_list[i]) == 1) {
i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
if (i2c_dev) {
i2c_dev->addr = addr_list[i];
i2c_dev->adapter = &dev->i2c_adap;
/* NOTE: as long as we don't register the device
* at the i2c subsystem, no other fields need to
* be set up */
}
break;
}
i++;
}

if (dev->init_data.name)
info.platform_data = &dev->init_data;
i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
return i2c_dev;
}

/**********************************************************
Expand Down Expand Up @@ -565,19 +584,21 @@ static int em28xx_ir_init(struct em28xx *dev)
struct rc_dev *rc;
int err = -ENOMEM;
u64 rc_type;
struct i2c_client *i2c_rc_dev = NULL;

if (dev->board.has_snapshot_button)
em28xx_register_snapshot_button(dev);

if (dev->board.has_ir_i2c) {
em28xx_register_i2c_ir(dev);
#if defined(CONFIG_MODULES) && defined(MODULE)
request_module("ir-kbd-i2c");
#endif
return 0;
i2c_rc_dev = em28xx_probe_i2c_ir(dev);
if (!i2c_rc_dev) {
dev->board.has_ir_i2c = 0;
em28xx_warn("No i2c IR remote control device found.\n");
return -ENODEV;
}
}

if (dev->board.ir_codes == NULL) {
if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) {
/* No remote control support */
em28xx_warn("Remote control support is not available for "
"this card.\n");
Expand All @@ -594,45 +615,70 @@ static int em28xx_ir_init(struct em28xx *dev)
dev->ir = ir;
ir->rc = rc;

/*
* em2874 supports more protocols. For now, let's just announce
* the two protocols that were already tested
*/
rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
rc->priv = ir;
rc->change_protocol = em28xx_ir_change_protocol;
rc->open = em28xx_ir_start;
rc->close = em28xx_ir_stop;

switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
ir->get_key = default_polling_getkey;
break;
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
ir->get_key = em2874_polling_getkey;
rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | RC_BIT_RC6_0;
break;
default:
err = -ENODEV;
goto error;
if (dev->board.has_ir_i2c) { /* external i2c device */
switch (dev->model) {
case EM2800_BOARD_TERRATEC_CINERGY_200:
case EM2820_BOARD_TERRATEC_CINERGY_250:
rc->map_name = RC_MAP_EM_TERRATEC;
ir->get_key_i2c = em28xx_get_key_terratec;
break;
case EM2820_BOARD_PINNACLE_USB_2:
rc->map_name = RC_MAP_PINNACLE_GREY;
ir->get_key_i2c = em28xx_get_key_pinnacle_usb_grey;
break;
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
rc->map_name = RC_MAP_HAUPPAUGE;
ir->get_key_i2c = em28xx_get_key_em_haup;
rc->allowed_protos = RC_BIT_RC5;
break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
ir->get_key_i2c = em28xx_get_key_winfast_usbii_deluxe;
break;
default:
err = -ENODEV;
goto error;
}

ir->i2c_dev = i2c_rc_dev;
} else { /* internal device */
switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
ir->get_key = default_polling_getkey;
break;
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
ir->get_key = em2874_polling_getkey;
rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC |
RC_BIT_RC6_0;
break;
default:
err = -ENODEV;
goto error;
}

rc->change_protocol = em28xx_ir_change_protocol;
rc->map_name = dev->board.ir_codes;

/* By default, keep protocol field untouched */
rc_type = RC_BIT_UNKNOWN;
err = em28xx_ir_change_protocol(rc, &rc_type);
if (err)
goto error;
}

/* By default, keep protocol field untouched */
rc_type = RC_BIT_UNKNOWN;
err = em28xx_ir_change_protocol(rc, &rc_type);
if (err)
goto error;

/* This is how often we ask the chip for IR information */
ir->polling = 100; /* ms */

/* init input device */
snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)",
dev->name);
snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", dev->name);

usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
Expand All @@ -644,7 +690,6 @@ static int em28xx_ir_init(struct em28xx *dev)
rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
rc->dev.parent = &dev->udev->dev;
rc->map_name = dev->board.ir_codes;
rc->driver_name = MODULE_NAME;

/* all done */
Expand All @@ -655,6 +700,8 @@ static int em28xx_ir_init(struct em28xx *dev)
return 0;

error:
if (ir && ir->i2c_dev)
kfree(ir->i2c_dev);
dev->ir = NULL;
rc_free_device(rc);
kfree(ir);
Expand All @@ -674,6 +721,8 @@ static int em28xx_ir_fini(struct em28xx *dev)
if (ir->rc)
rc_unregister_device(ir->rc);

kfree(ir->i2c_dev);

/* done */
kfree(ir);
dev->ir = NULL;
Expand Down
3 changes: 0 additions & 3 deletions trunk/drivers/media/usb/em28xx/em28xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,6 @@ struct em28xx {
struct delayed_work sbutton_query_work;

struct em28xx_dvb *dvb;

/* I2C keyboard data */
struct IR_i2c_init_data init_data;
};

struct em28xx_ops {
Expand Down

0 comments on commit 1909820

Please sign in to comment.