Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 124190
b: refs/heads/master
c: a924a49
h: refs/heads/master
v: v3
  • Loading branch information
Mauro Carvalho Chehab committed Dec 29, 2008
1 parent c008cdc commit 503d62a
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 16 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: 1958578da6f3971227fca94a62429cdf0bd3c699
refs/heads/master: a924a499adb89f52046936deac87264774652a81
2 changes: 2 additions & 0 deletions trunk/drivers/media/video/em28xx/em28xx-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -1843,4 +1843,6 @@ void em28xx_card_setup(struct em28xx *dev)
#endif

em28xx_config_tuner(dev);

em28xx_ir_init(dev);
}
233 changes: 219 additions & 14 deletions trunk/drivers/media/video/em28xx/em28xx-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,58 @@ static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");

#define dprintk(fmt, arg...) \
#define i2cdprintk(fmt, arg...) \
if (ir_debug) { \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
}

/* ----------------------------------------------------------------------- */
#define dprintk(fmt, arg...) \
if (ir_debug) { \
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
}

/**********************************************************
Polling structure used by em28xx IR's
**********************************************************/

struct em28xx_IR {
struct em28xx *dev;
struct input_dev *input;
struct ir_input_state ir;
char name[32];
char phys[32];

/* poll external decoder */
int polling;
struct work_struct work;
struct timer_list timer;
u32 last_gpio;
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;

int (*get_key)(struct em28xx_IR *);
};

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

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

/* poll IR chip */
if (1 != i2c_master_recv(&ir->c, &b, 1)) {
dprintk("read error\n");
i2cdprintk("read error\n");
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 */

dprintk("key %02x\n", b);
i2cdprintk("key %02x\n", b);

if (b == 0xff)
return 0;
Expand All @@ -73,7 +103,6 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}


int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[2];
Expand All @@ -97,7 +126,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
((buf[0]&0x10)>>3) | /* 0000 0010 */
((buf[0]&0x20)>>5); /* 0000 0001 */

dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
code, buf[0]);

/* return key */
Expand All @@ -114,11 +143,11 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
/* poll IR chip */

if (3 != i2c_master_recv(&ir->c, buf, 3)) {
dprintk("read error\n");
i2cdprintk("read error\n");
return -EIO;
}

dprintk("key %02x\n", buf[2]&0x3f);
i2cdprintk("key %02x\n", buf[2]&0x3f);
if (buf[0] != 0x00)
return 0;

Expand All @@ -128,6 +157,188 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
return 1;
}

/**********************************************************
Poll based get keycode functions
**********************************************************/

static int default_polling_getkey(struct em28xx_IR *ir)
{
struct em28xx *dev = ir->dev;
int rc;
u32 msg;

/* Read key toggle, brand, and key code */
rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
(u8 *)&msg, sizeof(msg));
if (rc < 0)
return rc;

return (int)(msg & 0x7fffffffl);
}

/**********************************************************
Polling code for em28xx
**********************************************************/

static void em28xx_ir_handle_key(struct em28xx_IR *ir)
{
int gpio;
u32 data;

/* read gpio value */
gpio = ir->get_key(ir);
if (gpio < 0)
return;

if (gpio == ir->last_gpio)
return;
ir->last_gpio = gpio;

/* extract data */
data = ir_extract_bits(gpio, ir->mask_keycode);
dprintk("irq gpio=0x%x code=%d | poll%s%s\n",
gpio, data,
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");

/* Generate keyup/keydown events */
if (ir->mask_keydown) {
/* bit set on keydown */
if (gpio & ir->mask_keydown)
ir_input_keydown(ir->input, &ir->ir, data, data);
else
ir_input_nokey(ir->input, &ir->ir);
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
if (!(gpio & ir->mask_keyup))
ir_input_keydown(ir->input, &ir->ir, data, data);
else
ir_input_nokey(ir->input, &ir->ir);
} else {
/* can't distinguish keydown/up :-/ */
ir_input_keydown(ir->input, &ir->ir, data, data);
ir_input_nokey(ir->input, &ir->ir);
}
}

static void ir_timer(unsigned long data)
{
struct em28xx_IR *ir = (struct em28xx_IR *)data;

schedule_work(&ir->work);
}

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

em28xx_ir_handle_key(ir);
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}

void em28xx_ir_start(struct em28xx_IR *ir)
{
setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
INIT_WORK(&ir->work, em28xx_ir_work);
schedule_work(&ir->work);
}

static void em28xx_ir_stop(struct em28xx_IR *ir)
{
del_timer_sync(&ir->timer);
flush_scheduled_work();
}

int em28xx_ir_init(struct em28xx *dev)
{
struct em28xx_IR *ir;
struct input_dev *input_dev;
IR_KEYTAB_TYPE *ir_codes = NULL;
int ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;

ir = kzalloc(sizeof(*ir), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev)
goto err_out_free;

ir->input = input_dev;

/* */
ir->get_key = default_polling_getkey;
ir->polling = 50; /* ms */

/* detect & configure */
switch (dev->model) {
}

if (NULL == ir_codes) {
err = -ENODEV;
goto err_out_free;
}

/* Get the current key status, to avoid adding an
unexistent key code */
ir->last_gpio = ir->get_key(ir);

/* init input device */
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));

ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_USB;
input_dev->id.version = 1;
input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);

input_dev->dev.parent = &dev->udev->dev;
/* record handles to ourself */
ir->dev = dev;
dev->ir = ir;

em28xx_ir_start(ir);

/* all done */
err = input_register_device(ir->input);
if (err)
goto err_out_stop;

return 0;
err_out_stop:
em28xx_ir_stop(ir);
dev->ir = NULL;
err_out_free:
input_free_device(input_dev);
kfree(ir);
return err;
}

int em28xx_ir_fini(struct em28xx *dev)
{
struct em28xx_IR *ir = dev->ir;

/* skip detach on non attached boards */
if (!ir)
return 0;

em28xx_ir_stop(ir);
input_unregister_device(ir->input);
kfree(ir);

/* done */
dev->ir = NULL;
return 0;
}

/**********************************************************
Handle Webcam snapshot button
**********************************************************/

static void em28xx_query_sbutton(struct work_struct *work)
{
/* Poll the register and see if the button is depressed */
Expand Down Expand Up @@ -210,9 +421,3 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)
}
return;
}

/* ----------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/
7 changes: 7 additions & 0 deletions trunk/drivers/media/video/em28xx/em28xx-reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@
#define EM28XX_R42_AC97ADDR 0x42
#define EM28XX_R43_AC97BUSY 0x43

#define EM28XX_R45_IR 0x45
/* 0x45 bit 7 - parity bit
bits 6-0 - count
0x46 IR brand
0x47 IR data
*/

/* em202 registers */
#define EM28XX_R02_MASTER_AC97 0x02
#define EM28XX_R10_LINE_IN_AC97 0x10
Expand Down
4 changes: 4 additions & 0 deletions trunk/drivers/media/video/em28xx/em28xx-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,10 @@ static void em28xx_release_resources(struct em28xx *dev)
list_del(&dev->devlist);
if (dev->sbutton_input_dev)
em28xx_deregister_snapshot_button(dev);

if (dev->ir)
em28xx_ir_fini(dev);

if (dev->radio_dev) {
if (-1 != dev->radio_dev->minor)
video_unregister_device(dev->radio_dev);
Expand Down
6 changes: 5 additions & 1 deletion trunk/drivers/media/video/em28xx/em28xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ struct em28xx {
unsigned int has_snapshot_button:1;
unsigned int valid:1; /* report for validated boards */

struct em28xx_IR *ir;

/* Some older em28xx chips needs a waiting time after writing */
unsigned int wait_after_write;

Expand Down Expand Up @@ -544,14 +546,16 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);

/* Provided by em28xx-input.c */
/* TODO: Check if the standard get_key handlers on ir-common can be used */
int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw);
void em28xx_register_snapshot_button(struct em28xx *dev);
void em28xx_deregister_snapshot_button(struct em28xx *dev);

int em28xx_ir_init(struct em28xx *dev);
int em28xx_ir_fini(struct em28xx *dev);

/* printk macros */

#define em28xx_err(fmt, arg...) do {\
Expand Down

0 comments on commit 503d62a

Please sign in to comment.