V4L/DVB (9639): Make dib0700 remote control support work with firmware v1.20
The format for reading the IR controller changed in firmware 1.20. It now provides the events on bulk endpoint 1 instead of using a control request. Support the new format, providing backward compatibility for users who might be using older firmware. Thanks to Patrick Boettcher <patrick.boettcher@desy.de> for providing the required information on how the version 1.20 firmware works. Signed-off-by: Devin Heitmueller <devin.heitmueller@gmail.com> Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Родитель
deaf53e3c8
Коммит
99afb989b0
|
@ -22,7 +22,7 @@ extern int dvb_usb_dib0700_debug;
|
||||||
|
|
||||||
#define REQUEST_I2C_READ 0x2
|
#define REQUEST_I2C_READ 0x2
|
||||||
#define REQUEST_I2C_WRITE 0x3
|
#define REQUEST_I2C_WRITE 0x3
|
||||||
#define REQUEST_POLL_RC 0x4
|
#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */
|
||||||
#define REQUEST_JUMPRAM 0x8
|
#define REQUEST_JUMPRAM 0x8
|
||||||
#define REQUEST_SET_CLOCK 0xB
|
#define REQUEST_SET_CLOCK 0xB
|
||||||
#define REQUEST_SET_GPIO 0xC
|
#define REQUEST_SET_GPIO 0xC
|
||||||
|
@ -40,11 +40,14 @@ struct dib0700_state {
|
||||||
u16 mt2060_if1[2];
|
u16 mt2060_if1[2];
|
||||||
u8 rc_toggle;
|
u8 rc_toggle;
|
||||||
u8 rc_counter;
|
u8 rc_counter;
|
||||||
|
u8 rc_func_version;
|
||||||
u8 is_dib7000pc;
|
u8 is_dib7000pc;
|
||||||
u8 fw_use_new_i2c_api;
|
u8 fw_use_new_i2c_api;
|
||||||
u8 disable_streaming_master_mode;
|
u8 disable_streaming_master_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
|
||||||
|
u32 *romversion, u32 *ramversion, u32 *fwtype);
|
||||||
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
|
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
|
||||||
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
|
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
|
||||||
extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
|
extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
|
||||||
|
|
|
@ -19,6 +19,22 @@ MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (defau
|
||||||
|
|
||||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||||
|
|
||||||
|
|
||||||
|
int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
|
||||||
|
u32 *romversion, u32 *ramversion, u32 *fwtype)
|
||||||
|
{
|
||||||
|
u8 b[16];
|
||||||
|
int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
|
||||||
|
REQUEST_GET_VERSION,
|
||||||
|
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
|
||||||
|
b, sizeof(b), USB_CTRL_GET_TIMEOUT);
|
||||||
|
*hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
|
||||||
|
*romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7];
|
||||||
|
*ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
|
||||||
|
*fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* expecting rx buffer: request data[0] data[1] ... data[2] */
|
/* expecting rx buffer: request data[0] data[1] ... data[2] */
|
||||||
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
|
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@ static struct mt2060_config bristol_mt2060_config[2] = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
|
static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
|
||||||
.band_caps = BAND_VHF | BAND_UHF,
|
.band_caps = BAND_VHF | BAND_UHF,
|
||||||
.setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
|
.setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
|
||||||
|
@ -451,8 +452,13 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
|
||||||
|
|
||||||
/* Number of keypresses to ignore before start repeating */
|
/* Number of keypresses to ignore before start repeating */
|
||||||
#define RC_REPEAT_DELAY 2
|
#define RC_REPEAT_DELAY 2
|
||||||
|
#define RC_REPEAT_DELAY_V1_20 5
|
||||||
|
|
||||||
static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|
||||||
|
|
||||||
|
/* Used by firmware versions < 1.20 (deprecated) */
|
||||||
|
static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
|
||||||
|
int *state)
|
||||||
{
|
{
|
||||||
u8 key[4];
|
u8 key[4];
|
||||||
int i;
|
int i;
|
||||||
|
@ -529,6 +535,137 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is the structure of the RC response packet starting in firmware 1.20 */
|
||||||
|
struct dib0700_rc_response {
|
||||||
|
u8 report_id;
|
||||||
|
u8 data_state;
|
||||||
|
u8 system_msb;
|
||||||
|
u8 system_lsb;
|
||||||
|
u8 data;
|
||||||
|
u8 not_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This supports the new IR response format for firmware v1.20 */
|
||||||
|
static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
|
||||||
|
int *state)
|
||||||
|
{
|
||||||
|
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||||
|
struct dib0700_state *st = d->priv;
|
||||||
|
struct dib0700_rc_response poll_reply;
|
||||||
|
u8 buf[6];
|
||||||
|
int i;
|
||||||
|
int status;
|
||||||
|
int actlen;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
/* Set initial results in case we exit the function early */
|
||||||
|
*event = 0;
|
||||||
|
*state = REMOTE_NO_KEY_PRESSED;
|
||||||
|
|
||||||
|
/* Firmware v1.20 provides RC data via bulk endpoint 1 */
|
||||||
|
status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf,
|
||||||
|
sizeof(buf), &actlen, 50);
|
||||||
|
if (status < 0) {
|
||||||
|
/* No data available (meaning no key press) */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actlen != sizeof(buf)) {
|
||||||
|
/* We didn't get back the 6 byte message we expected */
|
||||||
|
err("Unexpected RC response size [%d]", actlen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_reply.report_id = buf[0];
|
||||||
|
poll_reply.data_state = buf[1];
|
||||||
|
poll_reply.system_msb = buf[2];
|
||||||
|
poll_reply.system_lsb = buf[3];
|
||||||
|
poll_reply.data = buf[4];
|
||||||
|
poll_reply.not_data = buf[5];
|
||||||
|
|
||||||
|
/*
|
||||||
|
info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n",
|
||||||
|
poll_reply.report_id, poll_reply.data_state,
|
||||||
|
poll_reply.system_msb, poll_reply.system_lsb,
|
||||||
|
poll_reply.data, poll_reply.not_data);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((poll_reply.data + poll_reply.not_data) != 0xff) {
|
||||||
|
/* Key failed integrity check */
|
||||||
|
err("key failed integrity check: %02x %02x %02x %02x",
|
||||||
|
poll_reply.system_msb, poll_reply.system_lsb,
|
||||||
|
poll_reply.data, poll_reply.not_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the key in the map */
|
||||||
|
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||||
|
if (keymap[i].custom == poll_reply.system_lsb &&
|
||||||
|
keymap[i].data == poll_reply.data) {
|
||||||
|
*event = keymap[i].event;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found == 0) {
|
||||||
|
err("Unknown remote controller key: %02x %02x %02x %02x",
|
||||||
|
poll_reply.system_msb, poll_reply.system_lsb,
|
||||||
|
poll_reply.data, poll_reply.not_data);
|
||||||
|
d->last_event = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll_reply.data_state == 1) {
|
||||||
|
/* New key hit */
|
||||||
|
st->rc_counter = 0;
|
||||||
|
*event = keymap[i].event;
|
||||||
|
*state = REMOTE_KEY_PRESSED;
|
||||||
|
d->last_event = keymap[i].event;
|
||||||
|
} else if (poll_reply.data_state == 2) {
|
||||||
|
/* Key repeated */
|
||||||
|
st->rc_counter++;
|
||||||
|
|
||||||
|
/* prevents unwanted double hits */
|
||||||
|
if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
|
||||||
|
*event = d->last_event;
|
||||||
|
*state = REMOTE_KEY_PRESSED;
|
||||||
|
st->rc_counter = RC_REPEAT_DELAY_V1_20;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err("Unknown data state [%d]", poll_reply.data_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||||
|
{
|
||||||
|
struct dib0700_state *st = d->priv;
|
||||||
|
|
||||||
|
/* Because some people may have improperly named firmware files,
|
||||||
|
let's figure out whether to use the new firmware call or the legacy
|
||||||
|
call based on the firmware version embedded in the file */
|
||||||
|
if (st->rc_func_version == 0) {
|
||||||
|
u32 hwver, romver, ramver, fwtype;
|
||||||
|
int ret = dib0700_get_version(d, &hwver, &romver, &ramver,
|
||||||
|
&fwtype);
|
||||||
|
if (ret < 0) {
|
||||||
|
err("Could not determine version info");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ramver < 0x10200)
|
||||||
|
st->rc_func_version = 1;
|
||||||
|
else
|
||||||
|
st->rc_func_version = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->rc_func_version == 2)
|
||||||
|
return dib0700_rc_query_v1_20(d, event, state);
|
||||||
|
else
|
||||||
|
return dib0700_rc_query_legacy(d, event, state);
|
||||||
|
}
|
||||||
|
|
||||||
static struct dvb_usb_rc_key dib0700_rc_keys[] = {
|
static struct dvb_usb_rc_key dib0700_rc_keys[] = {
|
||||||
/* Key codes for the tiny Pinnacle remote*/
|
/* Key codes for the tiny Pinnacle remote*/
|
||||||
{ 0x07, 0x00, KEY_MUTE },
|
{ 0x07, 0x00, KEY_MUTE },
|
||||||
|
|
Загрузка…
Ссылка в новой задаче