Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[linux-dvb] Re: Remote control for Hauppauge Nova-T
Hi,
I've been playing with the budget-ci module with a view to adding loadable
keymap support as per the av7110 module.
Thus far, I have separated out the "generic keymap support" functions into a
new module called dvb_ir - the hope being that the facilities can be shared
and even extended.
I have also started to separate out the keymap support from the av7110 module
- but since I do not have the appropriate hardware or experience, I do not
know whether this will work... or if this is a good idea.
The code below works for me with my Nova-T card on a 2.4 kernel build.
I can use the av7110_loadkeys utility to output a keymap to /proc/dvb_ir0 (I
would expect to choose a more sensible naming convention for the proc entry
at a later date).
./av7110_loadkeys nova-t.rc5 > /proc/dvb_ir0
I have never written a linux module before and am really just "copying other
people's code". I'm posting this here, in the early stages of development, in
the hope that people might provide some feedback/comments, etc.
Is this of interest to anyone? Is it a good idea? Am I wasting my time and/or
am I making a complete hash of things!?
As I said, I've *never* written a kernel module so please feel free to tell me
that I don't have a clue and that my code sucks. ;)
budget-ci.c (latest cvs, 23rd Nov 2003)
30a31
> #include "dvb_ir.h"
36,42d36
< #include <linux/input.h>
<
< #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
< #include "input_fake.h"
< #endif
<
<
46d39
< struct input_dev input_dev;
47a41
> struct dvb_ir dvb_ir;
74,145d67
< /* from reading the following remotes:
< Zenith Universal 7 / TV Mode 807 / VCR Mode 837
< Hauppauge (from NOVA-CI-s box product)
< i've taken a "middle of the road" approach and note the differences
< */
< static u16 key_map[64] = {
< /* 0x0X */
< KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
< KEY_9,
< KEY_ENTER,
< KEY_RED,
< KEY_POWER, /* RADIO on Hauppauge */
< KEY_MUTE,
< 0,
< KEY_A, /* TV on Hauppauge */
< /* 0x1X */
< KEY_VOLUMEUP, KEY_VOLUMEDOWN,
< 0, 0,
< KEY_B,
< 0, 0, 0, 0, 0, 0, 0,
< KEY_UP, KEY_DOWN,
< KEY_OPTION, /* RESERVED on Hauppauge */
< KEY_BREAK,
< /* 0x2X */
< KEY_CHANNELUP, KEY_CHANNELDOWN,
< KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
< 0, KEY_RESTART, KEY_OK,
< KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
< 0,
< KEY_ENTER, /* VCR mode on Zenith */
< KEY_PAUSE,
< 0,
< KEY_RIGHT, KEY_LEFT,
< 0,
< KEY_MENU, /* FULL SCREEN on Hauppauge */
< 0,
< /* 0x3X */
< KEY_SLOW,
< KEY_PREVIOUS, /* VCR mode on Zenith */
< KEY_REWIND,
< 0,
< KEY_FASTFORWARD,
< KEY_PLAY, KEY_STOP,
< KEY_RECORD,
< KEY_TUNER, /* TV/VCR on Zenith */
< 0,
< KEY_C,
< 0,
< KEY_EXIT,
< KEY_POWER2,
< KEY_TUNER, /* VCR mode on Zenith */
< 0,
< };
<
<
< static void msp430_ir_debounce (unsigned long data)
< {
< struct input_dev *dev = (struct input_dev *) data;
<
< if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
< input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
< return;
< }
<
< dev->rep[0] = 0;
< dev->timer.expires = jiffies + HZ * 350 / 1000;
< add_timer(&dev->timer);
< input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
< }
<
<
<
150,151d71
< struct input_dev *dev = &budget_ci->input_dev;
< unsigned int code = budget_debiread4(saa, DEBINOSWAP, 0x1234, 2) >> 8;
152a73
> unsigned int code = budget_debiread4(saa, DEBINOSWAP, 0x1234, 2) >> 8;
155,179c76
<
< if (timer_pending(&dev->timer)) {
< if (code == dev->repeat_key) {
< ++dev->rep[0];
< return;
< }
< del_timer(&dev->timer);
< input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
< }
<
< if (!key_map[code]) {
< printk ("DVB (%s): no key for %02x!\n",
< __FUNCTION__, code);
< return;
< }
<
< /* initialize debounce and repeat */
< dev->repeat_key = code;
< /* Zenith remote _always_ sends 2 sequences */
< dev->rep[0] = ~0;
< /* 350 milliseconds */
< dev->timer.expires = jiffies + HZ * 350 / 1000;
< /* MAKE */
< input_event(dev, EV_KEY, key_map[code], !0);
< add_timer(&dev->timer);
---
> dvb_ir_event(&budget_ci->dvb_ir, code, 0);
187,189c84
< int i;
<
< memset(&budget_ci->input_dev, 0, sizeof(struct input_dev));
---
> struct input_dev *input_dev = &budget_ci->dvb_ir.input_dev;
191,201c86,88
< budget_ci->input_dev.name = saa->name;
<
< set_bit(EV_KEY, budget_ci->input_dev.evbit);
<
< for (i=0; i<sizeof(key_map)/sizeof(*key_map); i++)
< if (key_map[i])
< set_bit(key_map[i], budget_ci->input_dev.keybit);
<
< input_register_device(&budget_ci->input_dev);
<
< budget_ci->input_dev.timer.function = msp430_ir_debounce;
---
> memset(&budget_ci->dvb_ir, 0, sizeof(struct dvb_ir));
> dvb_ir_register(&budget_ci->dvb_ir, budget_ci->budget.dvb_adapter);
> input_dev->name = saa->name;
214d100
< struct input_dev *dev = &budget_ci->input_dev;
220,223c106
< if (del_timer(&dev->timer))
< input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
<
< input_unregister_device(dev);
---
> dvb_ir_unregister(&budget_ci->dvb_ir);
/*
* dvb_ir.h
*/
#ifndef _DVB_IR_H_
#define _DVB_IR_H_
#include "dvbdev.h"
#include <linux/input.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#include "input_fake.h"
#endif
struct dvb_ir {
struct dvb_adapter *dvb_adapter;
struct input_dev input_dev;
u16 key_map[256];
u32 key_debounce;
u32 key_repeat;
u32 ir_config;
void (*setup_ir_config) (void *data, u32 ir_config);
void *setup_ir_config_data;
};
extern int dvb_ir_register(struct dvb_ir *dvb_ir, struct dvb_adapter*
dvb_adapter);
extern void dvb_ir_unregister(struct dvb_ir *dvb_ir);
extern void dvb_ir_event(struct dvb_ir *dvb_ir, u16 keycode, u16 toggle);
#endif /* #ifndef _DVB_IR_H_ */
/*
* dvb_ir.c: DVB IR Receiver Support (including loadable keymaps)
*/
#include "dvb_ir.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
static int dvb_ir_debug = 0;
#define dprintk(x...) do { if (dvb_ir_debug) printk (x); } while (0)
#define KEY_DEBOUNCE_TIMEOUT (HZ * 350 / 1000)
#define KEY_REPEAT_TIMEOUT (HZ * 350 / 1000)
static void input_register_keys (struct dvb_ir* dvb_ir)
{
int i;
struct input_dev *input_dev = &dvb_ir->input_dev;
memset (input_dev->keybit, 0, sizeof(input_dev->keybit));
for (i=0; i<sizeof(dvb_ir->key_map)/sizeof(dvb_ir->key_map[0]); i++) {
if (dvb_ir->key_map[i] > KEY_MAX)
dvb_ir->key_map[i] = 0;
else if (dvb_ir->key_map[i] > KEY_RESERVED)
set_bit (dvb_ir->key_map[i], input_dev->keybit);
}
}
static int dvb_ir_write_proc (struct file *file, const char *buffer,
unsigned long count, void *data)
{
struct dvb_ir *dvb_ir = (struct dvb_ir*) data;
char *page;
int size = 4 + 256 * sizeof(u16);
if (count < size)
return -EINVAL;
page = (char *)vmalloc(size);
if( NULL == page ) {
return -ENOMEM;
}
if (copy_from_user(page, buffer, size)) {
vfree(page);
return -EFAULT;
}
memcpy (&dvb_ir->ir_config, page, 4);
memcpy (&dvb_ir->key_map, page + 4, 256 * sizeof(u16));
vfree(page);
if (dvb_ir->setup_ir_config) {
dvb_ir->setup_ir_config(dvb_ir->setup_ir_config_data, dvb_ir->ir_config);
}
input_register_keys (dvb_ir);
return count;
}
static void dvb_ir_debounce (unsigned long data)
{
struct dvb_ir *dvb_ir = (struct dvb_ir*) data;
struct input_dev *input_dev = &dvb_ir->input_dev;
if (input_dev->rep[0] == 0 || input_dev->rep[0] == ~0) {
input_event(input_dev, EV_KEY, dvb_ir->key_map[input_dev->repeat_key], !!0);
return;
}
input_dev->rep[0] = 0;
input_dev->timer.expires = jiffies + dvb_ir->key_repeat;
add_timer(&input_dev->timer);
input_event(input_dev, EV_KEY, dvb_ir->key_map[input_dev->repeat_key], 2);
/* REPEAT */
}
void dvb_ir_event(struct dvb_ir *dvb_ir, u16 keycode, u16 toggle)
{
struct input_dev *input_dev = &dvb_ir->input_dev;
if (timer_pending(&input_dev->timer)) {
if (keycode == input_dev->repeat_key) {
++input_dev->rep[0];
return;
}
del_timer(&input_dev->timer);
input_event(input_dev, EV_KEY,
dvb_ir->key_map[input_dev->repeat_key], !!0);
}
if (!dvb_ir->key_map[keycode]) {
printk ("DVB (%s): no key for %02x!\n",
__FUNCTION__, keycode);
return;
}
/* initialize debounce and repeat */
input_dev->repeat_key = keycode;
input_dev->rep[0] = ~0;
input_dev->timer.expires = jiffies + dvb_ir->key_debounce;
input_event(input_dev, EV_KEY, dvb_ir->key_map[keycode], !0);
add_timer(&input_dev->timer);
}
int dvb_ir_register(struct dvb_ir *dvb_ir, struct dvb_adapter *dvb_adapter)
{
char procname[64];
struct proc_dir_entry *e;
struct input_dev *input_dev = &dvb_ir->input_dev;
if (dvb_adapter) dvb_ir->dvb_adapter = dvb_adapter;
else dvb_adapter = dvb_ir->dvb_adapter;
dvb_ir->key_debounce = KEY_DEBOUNCE_TIMEOUT;
dvb_ir->key_repeat = KEY_REPEAT_TIMEOUT;
memset(input_dev, 0, sizeof(struct input_dev));
memset(&dvb_ir->key_map, 0, sizeof(dvb_ir->key_map));
input_register_keys(dvb_ir);
set_bit (EV_KEY, input_dev->evbit);
set_bit (EV_REP, input_dev->evbit);
input_register_device(input_dev);
input_dev->timer.function = dvb_ir_debounce;
input_dev->timer.data = (unsigned long)dvb_ir;
if (dvb_adapter) {
snprintf(procname, sizeof(procname), "dvb_ir%d", dvb_ir->dvb_adapter->num);
e = create_proc_entry (procname, S_IFREG | S_IRUGO | S_IWUSR, NULL);
if (e) {
e->write_proc = dvb_ir_write_proc;
e->size = 4 + 256 * sizeof(u16);
e->data = (void*)dvb_ir;
}
}
return 0;
}
void dvb_ir_unregister(struct dvb_ir *dvb_ir)
{
char procname[64];
struct input_dev *input_dev = &dvb_ir->input_dev;
if (dvb_ir->dvb_adapter) {
snprintf(procname, sizeof(procname), "dvb_ir%d", dvb_ir->dvb_adapter->num);
remove_proc_entry (procname, NULL);
}
if (del_timer(&input_dev->timer))
input_event(input_dev, EV_KEY, dvb_ir->key_map[input_dev->repeat_key], !!0);
input_unregister_device(input_dev);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DVB IR Receiver Support");
MODULE_PARM(dvb_ir_debug,"i");
MODULE_PARM_DESC(dvb_ir_debug, "enable DVB IR receiver debug messages");
example nova-t.rc5 file:
0x00 KEY_0
0x01 KEY_1
0x02 KEY_2
0x03 KEY_3
0x04 KEY_4
0x05 KEY_5
0x06 KEY_6
0x07 KEY_7
0x08 KEY_8
0x09 KEY_9
0x0B KEY_RED
0x0C KEY_OPTION
0x0D KEY_MENU
0x0F KEY_MUTE
0x10 KEY_VOLUMEUP
0x11 KEY_VOLUMEDOWN
0x18 KEY_REWIND
0x1E KEY_FORWARD
0x1F KEY_EXIT
0x20 KEY_CHANNELUP
0x21 KEY_CHANNELDOWN
0x24 KEY_BACK
0x25 KEY_OK
0x29 KEY_BLUE
0x2E KEY_GREEN
0x30 KEY_PLAYPAUSE
0x32 KEY_REWIND
0x34 KEY_FASTFORWARD
0x35 KEY_PLAY
0x36 KEY_STOP
0x37 KEY_RECORD
0x38 KEY_YELLOW
0x3B KEY_GOTO
0x3C KEY_ZOOM
0x3D KEY_POWER
Best wishes,
--
Adrian Look
--
Info:
To unsubscribe send a mail to ecartis@linuxtv.org with "unsubscribe linux-dvb" as subject.
Home |
Main Index |
Thread Index