diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb/dib0700_devices.c')
| -rw-r--r-- | drivers/media/dvb/dvb-usb/dib0700_devices.c | 139 | 
1 files changed, 138 insertions, 1 deletions
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0cfccc24b19..f28d3ae59e0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -38,6 +38,7 @@ static struct mt2060_config bristol_mt2060_config[2] = {  	}  }; +  static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {  	.band_caps = BAND_VHF | BAND_UHF,  	.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 */  #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];  	int i; @@ -529,6 +535,137 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)  	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[] = {  	/* Key codes for the tiny Pinnacle remote*/  	{ 0x07, 0x00, KEY_MUTE },  |