xref: /openbmc/linux/drivers/media/usb/dvb-usb/af9005.c (revision f4ee84f2)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2786baecfSMauro Carvalho Chehab /* DVB USB compliant Linux driver for the Afatech 9005
3786baecfSMauro Carvalho Chehab  * USB1.1 DVB-T receiver.
4786baecfSMauro Carvalho Chehab  *
5786baecfSMauro Carvalho Chehab  * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
6786baecfSMauro Carvalho Chehab  *
7786baecfSMauro Carvalho Chehab  * Thanks to Afatech who kindly provided information.
8786baecfSMauro Carvalho Chehab  *
9577a7ad3SMauro Carvalho Chehab  * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
10786baecfSMauro Carvalho Chehab  */
11786baecfSMauro Carvalho Chehab #include "af9005.h"
12786baecfSMauro Carvalho Chehab 
13786baecfSMauro Carvalho Chehab /* debug */
14786baecfSMauro Carvalho Chehab int dvb_usb_af9005_debug;
15786baecfSMauro Carvalho Chehab module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
16786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(debug,
17786baecfSMauro Carvalho Chehab 		 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
18786baecfSMauro Carvalho Chehab 		 DVB_USB_DEBUG_STATUS);
19786baecfSMauro Carvalho Chehab /* enable obnoxious led */
2061f6a056SMauro Carvalho Chehab bool dvb_usb_af9005_led = true;
21786baecfSMauro Carvalho Chehab module_param_named(led, dvb_usb_af9005_led, bool, 0644);
22786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(led, "enable led (default: 1).");
23786baecfSMauro Carvalho Chehab 
24786baecfSMauro Carvalho Chehab /* eeprom dump */
25786baecfSMauro Carvalho Chehab static int dvb_usb_af9005_dump_eeprom;
26786baecfSMauro Carvalho Chehab module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
27786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
28786baecfSMauro Carvalho Chehab 
29786baecfSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
30786baecfSMauro Carvalho Chehab 
31786baecfSMauro Carvalho Chehab /* remote control decoder */
32786baecfSMauro Carvalho Chehab static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
33786baecfSMauro Carvalho Chehab 		u32 *event, int *state);
34786baecfSMauro Carvalho Chehab static void *rc_keys;
35786baecfSMauro Carvalho Chehab static int *rc_keys_size;
36786baecfSMauro Carvalho Chehab 
37786baecfSMauro Carvalho Chehab u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
38786baecfSMauro Carvalho Chehab 
39786baecfSMauro Carvalho Chehab struct af9005_device_state {
40786baecfSMauro Carvalho Chehab 	u8 sequence;
41786baecfSMauro Carvalho Chehab 	int led_state;
42c58b84eeSMauro Carvalho Chehab 	unsigned char data[256];
43786baecfSMauro Carvalho Chehab };
44786baecfSMauro Carvalho Chehab 
af9005_generic_read_write(struct dvb_usb_device * d,u16 reg,int readwrite,int type,u8 * values,int len)45786baecfSMauro Carvalho Chehab static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
46786baecfSMauro Carvalho Chehab 			      int readwrite, int type, u8 * values, int len)
47786baecfSMauro Carvalho Chehab {
48786baecfSMauro Carvalho Chehab 	struct af9005_device_state *st = d->priv;
49c58b84eeSMauro Carvalho Chehab 	u8 command, seq;
50c58b84eeSMauro Carvalho Chehab 	int i, ret;
51786baecfSMauro Carvalho Chehab 
52786baecfSMauro Carvalho Chehab 	if (len < 1) {
53786baecfSMauro Carvalho Chehab 		err("generic read/write, less than 1 byte. Makes no sense.");
54786baecfSMauro Carvalho Chehab 		return -EINVAL;
55786baecfSMauro Carvalho Chehab 	}
56786baecfSMauro Carvalho Chehab 	if (len > 8) {
57786baecfSMauro Carvalho Chehab 		err("generic read/write, more than 8 bytes. Not supported.");
58786baecfSMauro Carvalho Chehab 		return -EINVAL;
59786baecfSMauro Carvalho Chehab 	}
60786baecfSMauro Carvalho Chehab 
617724325aSMauro Carvalho Chehab 	mutex_lock(&d->data_mutex);
62c58b84eeSMauro Carvalho Chehab 	st->data[0] = 14;		/* rest of buffer length low */
63c58b84eeSMauro Carvalho Chehab 	st->data[1] = 0;		/* rest of buffer length high */
64786baecfSMauro Carvalho Chehab 
65c58b84eeSMauro Carvalho Chehab 	st->data[2] = AF9005_REGISTER_RW;	/* register operation */
66c58b84eeSMauro Carvalho Chehab 	st->data[3] = 12;		/* rest of buffer length */
67786baecfSMauro Carvalho Chehab 
68c58b84eeSMauro Carvalho Chehab 	st->data[4] = seq = st->sequence++;	/* sequence number */
69786baecfSMauro Carvalho Chehab 
70c58b84eeSMauro Carvalho Chehab 	st->data[5] = (u8) (reg >> 8);	/* register address */
71c58b84eeSMauro Carvalho Chehab 	st->data[6] = (u8) (reg & 0xff);
72786baecfSMauro Carvalho Chehab 
73786baecfSMauro Carvalho Chehab 	if (type == AF9005_OFDM_REG) {
74786baecfSMauro Carvalho Chehab 		command = AF9005_CMD_OFDM_REG;
75786baecfSMauro Carvalho Chehab 	} else {
76786baecfSMauro Carvalho Chehab 		command = AF9005_CMD_TUNER;
77786baecfSMauro Carvalho Chehab 	}
78786baecfSMauro Carvalho Chehab 
79786baecfSMauro Carvalho Chehab 	if (len > 1)
80786baecfSMauro Carvalho Chehab 		command |=
81786baecfSMauro Carvalho Chehab 		    AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
82786baecfSMauro Carvalho Chehab 	command |= readwrite;
83786baecfSMauro Carvalho Chehab 	if (readwrite == AF9005_CMD_WRITE)
84786baecfSMauro Carvalho Chehab 		for (i = 0; i < len; i++)
85c58b84eeSMauro Carvalho Chehab 			st->data[8 + i] = values[i];
86786baecfSMauro Carvalho Chehab 	else if (type == AF9005_TUNER_REG)
87786baecfSMauro Carvalho Chehab 		/* read command for tuner, the first byte contains the i2c address */
88c58b84eeSMauro Carvalho Chehab 		st->data[8] = values[0];
89c58b84eeSMauro Carvalho Chehab 	st->data[7] = command;
90786baecfSMauro Carvalho Chehab 
91c58b84eeSMauro Carvalho Chehab 	ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 17, 0);
92786baecfSMauro Carvalho Chehab 	if (ret)
93c58b84eeSMauro Carvalho Chehab 		goto ret;
94786baecfSMauro Carvalho Chehab 
95786baecfSMauro Carvalho Chehab 	/* sanity check */
96c58b84eeSMauro Carvalho Chehab 	if (st->data[2] != AF9005_REGISTER_RW_ACK) {
97786baecfSMauro Carvalho Chehab 		err("generic read/write, wrong reply code.");
98c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
99c58b84eeSMauro Carvalho Chehab 		goto ret;
100786baecfSMauro Carvalho Chehab 	}
101c58b84eeSMauro Carvalho Chehab 	if (st->data[3] != 0x0d) {
102786baecfSMauro Carvalho Chehab 		err("generic read/write, wrong length in reply.");
103c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
104c58b84eeSMauro Carvalho Chehab 		goto ret;
105786baecfSMauro Carvalho Chehab 	}
106c58b84eeSMauro Carvalho Chehab 	if (st->data[4] != seq) {
107786baecfSMauro Carvalho Chehab 		err("generic read/write, wrong sequence in reply.");
108c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
109c58b84eeSMauro Carvalho Chehab 		goto ret;
110786baecfSMauro Carvalho Chehab 	}
111786baecfSMauro Carvalho Chehab 	/*
112c58b84eeSMauro Carvalho Chehab 	 * In thesis, both input and output buffers should have
113c58b84eeSMauro Carvalho Chehab 	 * identical values for st->data[5] to st->data[8].
114c58b84eeSMauro Carvalho Chehab 	 * However, windows driver doesn't check these fields, in fact
115c58b84eeSMauro Carvalho Chehab 	 * sometimes the register in the reply is different that what
116c58b84eeSMauro Carvalho Chehab 	 * has been sent
117786baecfSMauro Carvalho Chehab 	 */
118c58b84eeSMauro Carvalho Chehab 	if (st->data[16] != 0x01) {
119786baecfSMauro Carvalho Chehab 		err("generic read/write wrong status code in reply.");
120c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
121c58b84eeSMauro Carvalho Chehab 		goto ret;
122786baecfSMauro Carvalho Chehab 	}
123c58b84eeSMauro Carvalho Chehab 
124786baecfSMauro Carvalho Chehab 	if (readwrite == AF9005_CMD_READ)
125786baecfSMauro Carvalho Chehab 		for (i = 0; i < len; i++)
126c58b84eeSMauro Carvalho Chehab 			values[i] = st->data[8 + i];
127786baecfSMauro Carvalho Chehab 
128c58b84eeSMauro Carvalho Chehab ret:
1297724325aSMauro Carvalho Chehab 	mutex_unlock(&d->data_mutex);
130c58b84eeSMauro Carvalho Chehab 	return ret;
131786baecfSMauro Carvalho Chehab 
132786baecfSMauro Carvalho Chehab }
133786baecfSMauro Carvalho Chehab 
af9005_read_ofdm_register(struct dvb_usb_device * d,u16 reg,u8 * value)134786baecfSMauro Carvalho Chehab int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
135786baecfSMauro Carvalho Chehab {
136786baecfSMauro Carvalho Chehab 	int ret;
137786baecfSMauro Carvalho Chehab 	deb_reg("read register %x ", reg);
138786baecfSMauro Carvalho Chehab 	ret = af9005_generic_read_write(d, reg,
139786baecfSMauro Carvalho Chehab 					AF9005_CMD_READ, AF9005_OFDM_REG,
140786baecfSMauro Carvalho Chehab 					value, 1);
141786baecfSMauro Carvalho Chehab 	if (ret)
142786baecfSMauro Carvalho Chehab 		deb_reg("failed\n");
143786baecfSMauro Carvalho Chehab 	else
144786baecfSMauro Carvalho Chehab 		deb_reg("value %x\n", *value);
145786baecfSMauro Carvalho Chehab 	return ret;
146786baecfSMauro Carvalho Chehab }
147786baecfSMauro Carvalho Chehab 
af9005_read_ofdm_registers(struct dvb_usb_device * d,u16 reg,u8 * values,int len)148786baecfSMauro Carvalho Chehab int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
149786baecfSMauro Carvalho Chehab 			       u8 * values, int len)
150786baecfSMauro Carvalho Chehab {
151786baecfSMauro Carvalho Chehab 	int ret;
152786baecfSMauro Carvalho Chehab 	deb_reg("read %d registers %x ", len, reg);
153786baecfSMauro Carvalho Chehab 	ret = af9005_generic_read_write(d, reg,
154786baecfSMauro Carvalho Chehab 					AF9005_CMD_READ, AF9005_OFDM_REG,
155786baecfSMauro Carvalho Chehab 					values, len);
156786baecfSMauro Carvalho Chehab 	if (ret)
157786baecfSMauro Carvalho Chehab 		deb_reg("failed\n");
158786baecfSMauro Carvalho Chehab 	else
159786baecfSMauro Carvalho Chehab 		debug_dump(values, len, deb_reg);
160786baecfSMauro Carvalho Chehab 	return ret;
161786baecfSMauro Carvalho Chehab }
162786baecfSMauro Carvalho Chehab 
af9005_write_ofdm_register(struct dvb_usb_device * d,u16 reg,u8 value)163786baecfSMauro Carvalho Chehab int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
164786baecfSMauro Carvalho Chehab {
165786baecfSMauro Carvalho Chehab 	int ret;
166786baecfSMauro Carvalho Chehab 	u8 temp = value;
167786baecfSMauro Carvalho Chehab 	deb_reg("write register %x value %x ", reg, value);
168786baecfSMauro Carvalho Chehab 	ret = af9005_generic_read_write(d, reg,
169786baecfSMauro Carvalho Chehab 					AF9005_CMD_WRITE, AF9005_OFDM_REG,
170786baecfSMauro Carvalho Chehab 					&temp, 1);
171786baecfSMauro Carvalho Chehab 	if (ret)
172786baecfSMauro Carvalho Chehab 		deb_reg("failed\n");
173786baecfSMauro Carvalho Chehab 	else
174786baecfSMauro Carvalho Chehab 		deb_reg("ok\n");
175786baecfSMauro Carvalho Chehab 	return ret;
176786baecfSMauro Carvalho Chehab }
177786baecfSMauro Carvalho Chehab 
af9005_write_ofdm_registers(struct dvb_usb_device * d,u16 reg,u8 * values,int len)178786baecfSMauro Carvalho Chehab int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
179786baecfSMauro Carvalho Chehab 				u8 * values, int len)
180786baecfSMauro Carvalho Chehab {
181786baecfSMauro Carvalho Chehab 	int ret;
182786baecfSMauro Carvalho Chehab 	deb_reg("write %d registers %x values ", len, reg);
183786baecfSMauro Carvalho Chehab 	debug_dump(values, len, deb_reg);
184786baecfSMauro Carvalho Chehab 
185786baecfSMauro Carvalho Chehab 	ret = af9005_generic_read_write(d, reg,
186786baecfSMauro Carvalho Chehab 					AF9005_CMD_WRITE, AF9005_OFDM_REG,
187786baecfSMauro Carvalho Chehab 					values, len);
188786baecfSMauro Carvalho Chehab 	if (ret)
189786baecfSMauro Carvalho Chehab 		deb_reg("failed\n");
190786baecfSMauro Carvalho Chehab 	else
191786baecfSMauro Carvalho Chehab 		deb_reg("ok\n");
192786baecfSMauro Carvalho Chehab 	return ret;
193786baecfSMauro Carvalho Chehab }
194786baecfSMauro Carvalho Chehab 
af9005_read_register_bits(struct dvb_usb_device * d,u16 reg,u8 pos,u8 len,u8 * value)195786baecfSMauro Carvalho Chehab int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
196786baecfSMauro Carvalho Chehab 			      u8 len, u8 * value)
197786baecfSMauro Carvalho Chehab {
198786baecfSMauro Carvalho Chehab 	u8 temp;
199786baecfSMauro Carvalho Chehab 	int ret;
200786baecfSMauro Carvalho Chehab 	deb_reg("read bits %x %x %x", reg, pos, len);
201786baecfSMauro Carvalho Chehab 	ret = af9005_read_ofdm_register(d, reg, &temp);
202786baecfSMauro Carvalho Chehab 	if (ret) {
203786baecfSMauro Carvalho Chehab 		deb_reg(" failed\n");
204786baecfSMauro Carvalho Chehab 		return ret;
205786baecfSMauro Carvalho Chehab 	}
206786baecfSMauro Carvalho Chehab 	*value = (temp >> pos) & regmask[len - 1];
207786baecfSMauro Carvalho Chehab 	deb_reg(" value %x\n", *value);
208786baecfSMauro Carvalho Chehab 	return 0;
209786baecfSMauro Carvalho Chehab 
210786baecfSMauro Carvalho Chehab }
211786baecfSMauro Carvalho Chehab 
af9005_write_register_bits(struct dvb_usb_device * d,u16 reg,u8 pos,u8 len,u8 value)212786baecfSMauro Carvalho Chehab int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
213786baecfSMauro Carvalho Chehab 			       u8 len, u8 value)
214786baecfSMauro Carvalho Chehab {
215786baecfSMauro Carvalho Chehab 	u8 temp, mask;
216786baecfSMauro Carvalho Chehab 	int ret;
217786baecfSMauro Carvalho Chehab 	deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
218786baecfSMauro Carvalho Chehab 	if (pos == 0 && len == 8)
219786baecfSMauro Carvalho Chehab 		return af9005_write_ofdm_register(d, reg, value);
220786baecfSMauro Carvalho Chehab 	ret = af9005_read_ofdm_register(d, reg, &temp);
221786baecfSMauro Carvalho Chehab 	if (ret)
222786baecfSMauro Carvalho Chehab 		return ret;
223786baecfSMauro Carvalho Chehab 	mask = regmask[len - 1] << pos;
224786baecfSMauro Carvalho Chehab 	temp = (temp & ~mask) | ((value << pos) & mask);
225786baecfSMauro Carvalho Chehab 	return af9005_write_ofdm_register(d, reg, temp);
226786baecfSMauro Carvalho Chehab 
227786baecfSMauro Carvalho Chehab }
228786baecfSMauro Carvalho Chehab 
af9005_usb_read_tuner_registers(struct dvb_usb_device * d,u16 reg,u8 * values,int len)229786baecfSMauro Carvalho Chehab static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
230786baecfSMauro Carvalho Chehab 					   u16 reg, u8 * values, int len)
231786baecfSMauro Carvalho Chehab {
232786baecfSMauro Carvalho Chehab 	return af9005_generic_read_write(d, reg,
233786baecfSMauro Carvalho Chehab 					 AF9005_CMD_READ, AF9005_TUNER_REG,
234786baecfSMauro Carvalho Chehab 					 values, len);
235786baecfSMauro Carvalho Chehab }
236786baecfSMauro Carvalho Chehab 
af9005_usb_write_tuner_registers(struct dvb_usb_device * d,u16 reg,u8 * values,int len)237786baecfSMauro Carvalho Chehab static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
238786baecfSMauro Carvalho Chehab 					    u16 reg, u8 * values, int len)
239786baecfSMauro Carvalho Chehab {
240786baecfSMauro Carvalho Chehab 	return af9005_generic_read_write(d, reg,
241786baecfSMauro Carvalho Chehab 					 AF9005_CMD_WRITE,
242786baecfSMauro Carvalho Chehab 					 AF9005_TUNER_REG, values, len);
243786baecfSMauro Carvalho Chehab }
244786baecfSMauro Carvalho Chehab 
af9005_write_tuner_registers(struct dvb_usb_device * d,u16 reg,u8 * values,int len)245786baecfSMauro Carvalho Chehab int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
246786baecfSMauro Carvalho Chehab 				 u8 * values, int len)
247786baecfSMauro Carvalho Chehab {
248786baecfSMauro Carvalho Chehab 	/* don't let the name of this function mislead you: it's just used
249786baecfSMauro Carvalho Chehab 	   as an interface from the firmware to the i2c bus. The actual
250786baecfSMauro Carvalho Chehab 	   i2c addresses are contained in the data */
251786baecfSMauro Carvalho Chehab 	int ret, i, done = 0, fail = 0;
252786baecfSMauro Carvalho Chehab 	u8 temp;
253786baecfSMauro Carvalho Chehab 	ret = af9005_usb_write_tuner_registers(d, reg, values, len);
254786baecfSMauro Carvalho Chehab 	if (ret)
255786baecfSMauro Carvalho Chehab 		return ret;
256786baecfSMauro Carvalho Chehab 	if (reg != 0xffff) {
257786baecfSMauro Carvalho Chehab 		/* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
258786baecfSMauro Carvalho Chehab 		for (i = 0; i < 200; i++) {
259786baecfSMauro Carvalho Chehab 			ret =
260786baecfSMauro Carvalho Chehab 			    af9005_read_ofdm_register(d,
261786baecfSMauro Carvalho Chehab 						      xd_I2C_i2c_m_status_wdat_done,
262786baecfSMauro Carvalho Chehab 						      &temp);
263786baecfSMauro Carvalho Chehab 			if (ret)
264786baecfSMauro Carvalho Chehab 				return ret;
265786baecfSMauro Carvalho Chehab 			done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
266786baecfSMauro Carvalho Chehab 				       << i2c_m_status_wdat_done_pos);
267786baecfSMauro Carvalho Chehab 			if (done)
268786baecfSMauro Carvalho Chehab 				break;
269786baecfSMauro Carvalho Chehab 			fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
270786baecfSMauro Carvalho Chehab 				       << i2c_m_status_wdat_fail_pos);
271786baecfSMauro Carvalho Chehab 			if (fail)
272786baecfSMauro Carvalho Chehab 				break;
273786baecfSMauro Carvalho Chehab 			msleep(50);
274786baecfSMauro Carvalho Chehab 		}
275786baecfSMauro Carvalho Chehab 		if (i == 200)
276786baecfSMauro Carvalho Chehab 			return -ETIMEDOUT;
277786baecfSMauro Carvalho Chehab 		if (fail) {
278786baecfSMauro Carvalho Chehab 			/* clear write fail bit */
279786baecfSMauro Carvalho Chehab 			af9005_write_register_bits(d,
280786baecfSMauro Carvalho Chehab 						   xd_I2C_i2c_m_status_wdat_fail,
281786baecfSMauro Carvalho Chehab 						   i2c_m_status_wdat_fail_pos,
282786baecfSMauro Carvalho Chehab 						   i2c_m_status_wdat_fail_len,
283786baecfSMauro Carvalho Chehab 						   1);
284786baecfSMauro Carvalho Chehab 			return -EIO;
285786baecfSMauro Carvalho Chehab 		}
286786baecfSMauro Carvalho Chehab 		/* clear write done bit */
287786baecfSMauro Carvalho Chehab 		ret =
288786baecfSMauro Carvalho Chehab 		    af9005_write_register_bits(d,
289786baecfSMauro Carvalho Chehab 					       xd_I2C_i2c_m_status_wdat_fail,
290786baecfSMauro Carvalho Chehab 					       i2c_m_status_wdat_done_pos,
291786baecfSMauro Carvalho Chehab 					       i2c_m_status_wdat_done_len, 1);
292786baecfSMauro Carvalho Chehab 		if (ret)
293786baecfSMauro Carvalho Chehab 			return ret;
294786baecfSMauro Carvalho Chehab 	}
295786baecfSMauro Carvalho Chehab 	return 0;
296786baecfSMauro Carvalho Chehab }
297786baecfSMauro Carvalho Chehab 
af9005_read_tuner_registers(struct dvb_usb_device * d,u16 reg,u8 addr,u8 * values,int len)298786baecfSMauro Carvalho Chehab int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
299786baecfSMauro Carvalho Chehab 				u8 * values, int len)
300786baecfSMauro Carvalho Chehab {
301786baecfSMauro Carvalho Chehab 	/* don't let the name of this function mislead you: it's just used
302786baecfSMauro Carvalho Chehab 	   as an interface from the firmware to the i2c bus. The actual
303786baecfSMauro Carvalho Chehab 	   i2c addresses are contained in the data */
304786baecfSMauro Carvalho Chehab 	int ret, i;
305786baecfSMauro Carvalho Chehab 	u8 temp, buf[2];
306786baecfSMauro Carvalho Chehab 
307786baecfSMauro Carvalho Chehab 	buf[0] = addr;		/* tuner i2c address */
308786baecfSMauro Carvalho Chehab 	buf[1] = values[0];	/* tuner register */
309786baecfSMauro Carvalho Chehab 
310786baecfSMauro Carvalho Chehab 	values[0] = addr + 0x01;	/* i2c read address */
311786baecfSMauro Carvalho Chehab 
312786baecfSMauro Carvalho Chehab 	if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
313786baecfSMauro Carvalho Chehab 		/* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
314786baecfSMauro Carvalho Chehab 		ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
315786baecfSMauro Carvalho Chehab 		if (ret)
316786baecfSMauro Carvalho Chehab 			return ret;
317786baecfSMauro Carvalho Chehab 	}
318786baecfSMauro Carvalho Chehab 
319786baecfSMauro Carvalho Chehab 	/* send read command to ofsm */
320786baecfSMauro Carvalho Chehab 	ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
321786baecfSMauro Carvalho Chehab 	if (ret)
322786baecfSMauro Carvalho Chehab 		return ret;
323786baecfSMauro Carvalho Chehab 
324786baecfSMauro Carvalho Chehab 	/* check if read done */
325786baecfSMauro Carvalho Chehab 	for (i = 0; i < 200; i++) {
326786baecfSMauro Carvalho Chehab 		ret = af9005_read_ofdm_register(d, 0xa408, &temp);
327786baecfSMauro Carvalho Chehab 		if (ret)
328786baecfSMauro Carvalho Chehab 			return ret;
329786baecfSMauro Carvalho Chehab 		if (temp & 0x01)
330786baecfSMauro Carvalho Chehab 			break;
331786baecfSMauro Carvalho Chehab 		msleep(50);
332786baecfSMauro Carvalho Chehab 	}
333786baecfSMauro Carvalho Chehab 	if (i == 200)
334786baecfSMauro Carvalho Chehab 		return -ETIMEDOUT;
335786baecfSMauro Carvalho Chehab 
336786baecfSMauro Carvalho Chehab 	/* clear read done bit (by writing 1) */
337786baecfSMauro Carvalho Chehab 	ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
338786baecfSMauro Carvalho Chehab 	if (ret)
339786baecfSMauro Carvalho Chehab 		return ret;
340786baecfSMauro Carvalho Chehab 
341786baecfSMauro Carvalho Chehab 	/* get read data (available from 0xa400) */
342786baecfSMauro Carvalho Chehab 	for (i = 0; i < len; i++) {
343786baecfSMauro Carvalho Chehab 		ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
344786baecfSMauro Carvalho Chehab 		if (ret)
345786baecfSMauro Carvalho Chehab 			return ret;
346786baecfSMauro Carvalho Chehab 		values[i] = temp;
347786baecfSMauro Carvalho Chehab 	}
348786baecfSMauro Carvalho Chehab 	return 0;
349786baecfSMauro Carvalho Chehab }
350786baecfSMauro Carvalho Chehab 
af9005_i2c_write(struct dvb_usb_device * d,u8 i2caddr,u8 reg,u8 * data,int len)351786baecfSMauro Carvalho Chehab static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
352786baecfSMauro Carvalho Chehab 			    u8 * data, int len)
353786baecfSMauro Carvalho Chehab {
354786baecfSMauro Carvalho Chehab 	int ret, i;
355786baecfSMauro Carvalho Chehab 	u8 buf[3];
356786baecfSMauro Carvalho Chehab 	deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
357786baecfSMauro Carvalho Chehab 		reg, len);
358786baecfSMauro Carvalho Chehab 	debug_dump(data, len, deb_i2c);
359786baecfSMauro Carvalho Chehab 
360786baecfSMauro Carvalho Chehab 	for (i = 0; i < len; i++) {
361786baecfSMauro Carvalho Chehab 		buf[0] = i2caddr;
362786baecfSMauro Carvalho Chehab 		buf[1] = reg + (u8) i;
363786baecfSMauro Carvalho Chehab 		buf[2] = data[i];
364786baecfSMauro Carvalho Chehab 		ret =
365786baecfSMauro Carvalho Chehab 		    af9005_write_tuner_registers(d,
366786baecfSMauro Carvalho Chehab 						 APO_REG_I2C_RW_SILICON_TUNER,
367786baecfSMauro Carvalho Chehab 						 buf, 3);
368786baecfSMauro Carvalho Chehab 		if (ret) {
369786baecfSMauro Carvalho Chehab 			deb_i2c("i2c_write failed\n");
370786baecfSMauro Carvalho Chehab 			return ret;
371786baecfSMauro Carvalho Chehab 		}
372786baecfSMauro Carvalho Chehab 	}
373786baecfSMauro Carvalho Chehab 	deb_i2c("i2c_write ok\n");
374786baecfSMauro Carvalho Chehab 	return 0;
375786baecfSMauro Carvalho Chehab }
376786baecfSMauro Carvalho Chehab 
af9005_i2c_read(struct dvb_usb_device * d,u8 i2caddr,u8 reg,u8 * data,int len)377786baecfSMauro Carvalho Chehab static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
378786baecfSMauro Carvalho Chehab 			   u8 * data, int len)
379786baecfSMauro Carvalho Chehab {
380786baecfSMauro Carvalho Chehab 	int ret, i;
381786baecfSMauro Carvalho Chehab 	u8 temp;
382786baecfSMauro Carvalho Chehab 	deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
383786baecfSMauro Carvalho Chehab 	for (i = 0; i < len; i++) {
384786baecfSMauro Carvalho Chehab 		temp = reg + i;
385786baecfSMauro Carvalho Chehab 		ret =
386786baecfSMauro Carvalho Chehab 		    af9005_read_tuner_registers(d,
387786baecfSMauro Carvalho Chehab 						APO_REG_I2C_RW_SILICON_TUNER,
388786baecfSMauro Carvalho Chehab 						i2caddr, &temp, 1);
389786baecfSMauro Carvalho Chehab 		if (ret) {
390786baecfSMauro Carvalho Chehab 			deb_i2c("i2c_read failed\n");
391786baecfSMauro Carvalho Chehab 			return ret;
392786baecfSMauro Carvalho Chehab 		}
393786baecfSMauro Carvalho Chehab 		data[i] = temp;
394786baecfSMauro Carvalho Chehab 	}
395786baecfSMauro Carvalho Chehab 	deb_i2c("i2c data read: ");
396786baecfSMauro Carvalho Chehab 	debug_dump(data, len, deb_i2c);
397786baecfSMauro Carvalho Chehab 	return 0;
398786baecfSMauro Carvalho Chehab }
399786baecfSMauro Carvalho Chehab 
af9005_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg msg[],int num)400786baecfSMauro Carvalho Chehab static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
401786baecfSMauro Carvalho Chehab 			   int num)
402786baecfSMauro Carvalho Chehab {
403786baecfSMauro Carvalho Chehab 	/* only implements what the mt2060 module does, don't know how
404786baecfSMauro Carvalho Chehab 	   to make it really generic */
405786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
406786baecfSMauro Carvalho Chehab 	int ret;
407786baecfSMauro Carvalho Chehab 	u8 reg, addr;
408786baecfSMauro Carvalho Chehab 	u8 *value;
409786baecfSMauro Carvalho Chehab 
410786baecfSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
411786baecfSMauro Carvalho Chehab 		return -EAGAIN;
412786baecfSMauro Carvalho Chehab 
413786baecfSMauro Carvalho Chehab 	if (num > 2)
414786baecfSMauro Carvalho Chehab 		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
415786baecfSMauro Carvalho Chehab 
416786baecfSMauro Carvalho Chehab 	if (num == 2) {
417786baecfSMauro Carvalho Chehab 		/* reads a single register */
418786baecfSMauro Carvalho Chehab 		reg = *msg[0].buf;
419786baecfSMauro Carvalho Chehab 		addr = msg[0].addr;
420786baecfSMauro Carvalho Chehab 		value = msg[1].buf;
421786baecfSMauro Carvalho Chehab 		ret = af9005_i2c_read(d, addr, reg, value, 1);
422786baecfSMauro Carvalho Chehab 		if (ret == 0)
423786baecfSMauro Carvalho Chehab 			ret = 2;
424786baecfSMauro Carvalho Chehab 	} else {
425*f4ee84f2SZhang Shurong 		if (msg[0].len < 2) {
426*f4ee84f2SZhang Shurong 			ret = -EOPNOTSUPP;
427*f4ee84f2SZhang Shurong 			goto unlock;
428*f4ee84f2SZhang Shurong 		}
429786baecfSMauro Carvalho Chehab 		/* write one or more registers */
430786baecfSMauro Carvalho Chehab 		reg = msg[0].buf[0];
431786baecfSMauro Carvalho Chehab 		addr = msg[0].addr;
432786baecfSMauro Carvalho Chehab 		value = &msg[0].buf[1];
433786baecfSMauro Carvalho Chehab 		ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
434786baecfSMauro Carvalho Chehab 		if (ret == 0)
435786baecfSMauro Carvalho Chehab 			ret = 1;
436786baecfSMauro Carvalho Chehab 	}
437786baecfSMauro Carvalho Chehab 
438*f4ee84f2SZhang Shurong unlock:
439786baecfSMauro Carvalho Chehab 	mutex_unlock(&d->i2c_mutex);
440786baecfSMauro Carvalho Chehab 	return ret;
441786baecfSMauro Carvalho Chehab }
442786baecfSMauro Carvalho Chehab 
af9005_i2c_func(struct i2c_adapter * adapter)443786baecfSMauro Carvalho Chehab static u32 af9005_i2c_func(struct i2c_adapter *adapter)
444786baecfSMauro Carvalho Chehab {
445786baecfSMauro Carvalho Chehab 	return I2C_FUNC_I2C;
446786baecfSMauro Carvalho Chehab }
447786baecfSMauro Carvalho Chehab 
448786baecfSMauro Carvalho Chehab static struct i2c_algorithm af9005_i2c_algo = {
449786baecfSMauro Carvalho Chehab 	.master_xfer = af9005_i2c_xfer,
450786baecfSMauro Carvalho Chehab 	.functionality = af9005_i2c_func,
451786baecfSMauro Carvalho Chehab };
452786baecfSMauro Carvalho Chehab 
af9005_send_command(struct dvb_usb_device * d,u8 command,u8 * wbuf,int wlen,u8 * rbuf,int rlen)453786baecfSMauro Carvalho Chehab int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
454786baecfSMauro Carvalho Chehab 			int wlen, u8 * rbuf, int rlen)
455786baecfSMauro Carvalho Chehab {
456786baecfSMauro Carvalho Chehab 	struct af9005_device_state *st = d->priv;
457786baecfSMauro Carvalho Chehab 
458786baecfSMauro Carvalho Chehab 	int ret, i, packet_len;
459c58b84eeSMauro Carvalho Chehab 	u8 seq;
460786baecfSMauro Carvalho Chehab 
461786baecfSMauro Carvalho Chehab 	if (wlen < 0) {
462786baecfSMauro Carvalho Chehab 		err("send command, wlen less than 0 bytes. Makes no sense.");
463786baecfSMauro Carvalho Chehab 		return -EINVAL;
464786baecfSMauro Carvalho Chehab 	}
465786baecfSMauro Carvalho Chehab 	if (wlen > 54) {
466786baecfSMauro Carvalho Chehab 		err("send command, wlen more than 54 bytes. Not supported.");
467786baecfSMauro Carvalho Chehab 		return -EINVAL;
468786baecfSMauro Carvalho Chehab 	}
469786baecfSMauro Carvalho Chehab 	if (rlen > 54) {
470786baecfSMauro Carvalho Chehab 		err("send command, rlen more than 54 bytes. Not supported.");
471786baecfSMauro Carvalho Chehab 		return -EINVAL;
472786baecfSMauro Carvalho Chehab 	}
473786baecfSMauro Carvalho Chehab 	packet_len = wlen + 5;
474786baecfSMauro Carvalho Chehab 
4757724325aSMauro Carvalho Chehab 	mutex_lock(&d->data_mutex);
476c58b84eeSMauro Carvalho Chehab 
477c58b84eeSMauro Carvalho Chehab 	st->data[0] = (u8) (packet_len & 0xff);
478c58b84eeSMauro Carvalho Chehab 	st->data[1] = (u8) ((packet_len & 0xff00) >> 8);
479c58b84eeSMauro Carvalho Chehab 
480c58b84eeSMauro Carvalho Chehab 	st->data[2] = 0x26;		/* packet type */
481c58b84eeSMauro Carvalho Chehab 	st->data[3] = wlen + 3;
482c58b84eeSMauro Carvalho Chehab 	st->data[4] = seq = st->sequence++;
483c58b84eeSMauro Carvalho Chehab 	st->data[5] = command;
484c58b84eeSMauro Carvalho Chehab 	st->data[6] = wlen;
485786baecfSMauro Carvalho Chehab 	for (i = 0; i < wlen; i++)
486c58b84eeSMauro Carvalho Chehab 		st->data[7 + i] = wbuf[i];
487c58b84eeSMauro Carvalho Chehab 	ret = dvb_usb_generic_rw(d, st->data, wlen + 7, st->data, rlen + 7, 0);
488c58b84eeSMauro Carvalho Chehab 	if (st->data[2] != 0x27) {
489786baecfSMauro Carvalho Chehab 		err("send command, wrong reply code.");
490c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
491c58b84eeSMauro Carvalho Chehab 	} else if (st->data[4] != seq) {
492786baecfSMauro Carvalho Chehab 		err("send command, wrong sequence in reply.");
493c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
494c58b84eeSMauro Carvalho Chehab 	} else if (st->data[5] != 0x01) {
495786baecfSMauro Carvalho Chehab 		err("send command, wrong status code in reply.");
496c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
497c58b84eeSMauro Carvalho Chehab 	} else if (st->data[6] != rlen) {
498786baecfSMauro Carvalho Chehab 		err("send command, invalid data length in reply.");
499c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
500786baecfSMauro Carvalho Chehab 	}
501c58b84eeSMauro Carvalho Chehab 	if (!ret) {
502786baecfSMauro Carvalho Chehab 		for (i = 0; i < rlen; i++)
503c58b84eeSMauro Carvalho Chehab 			rbuf[i] = st->data[i + 7];
504c58b84eeSMauro Carvalho Chehab 	}
505c58b84eeSMauro Carvalho Chehab 
5067724325aSMauro Carvalho Chehab 	mutex_unlock(&d->data_mutex);
507c58b84eeSMauro Carvalho Chehab 	return ret;
508786baecfSMauro Carvalho Chehab }
509786baecfSMauro Carvalho Chehab 
af9005_read_eeprom(struct dvb_usb_device * d,u8 address,u8 * values,int len)510786baecfSMauro Carvalho Chehab int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
511786baecfSMauro Carvalho Chehab 		       int len)
512786baecfSMauro Carvalho Chehab {
513786baecfSMauro Carvalho Chehab 	struct af9005_device_state *st = d->priv;
514c58b84eeSMauro Carvalho Chehab 	u8 seq;
515786baecfSMauro Carvalho Chehab 	int ret, i;
516786baecfSMauro Carvalho Chehab 
5177724325aSMauro Carvalho Chehab 	mutex_lock(&d->data_mutex);
518786baecfSMauro Carvalho Chehab 
519c58b84eeSMauro Carvalho Chehab 	memset(st->data, 0, sizeof(st->data));
520786baecfSMauro Carvalho Chehab 
521c58b84eeSMauro Carvalho Chehab 	st->data[0] = 14;		/* length of rest of packet low */
522c58b84eeSMauro Carvalho Chehab 	st->data[1] = 0;		/* length of rest of packer high */
523786baecfSMauro Carvalho Chehab 
524c58b84eeSMauro Carvalho Chehab 	st->data[2] = 0x2a;		/* read/write eeprom */
525786baecfSMauro Carvalho Chehab 
526c58b84eeSMauro Carvalho Chehab 	st->data[3] = 12;		/* size */
527786baecfSMauro Carvalho Chehab 
528c58b84eeSMauro Carvalho Chehab 	st->data[4] = seq = st->sequence++;
529786baecfSMauro Carvalho Chehab 
530c58b84eeSMauro Carvalho Chehab 	st->data[5] = 0;		/* read */
531c58b84eeSMauro Carvalho Chehab 
532c58b84eeSMauro Carvalho Chehab 	st->data[6] = len;
533c58b84eeSMauro Carvalho Chehab 	st->data[7] = address;
534c58b84eeSMauro Carvalho Chehab 	ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 14, 0);
535c58b84eeSMauro Carvalho Chehab 	if (st->data[2] != 0x2b) {
536786baecfSMauro Carvalho Chehab 		err("Read eeprom, invalid reply code");
537c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
538c58b84eeSMauro Carvalho Chehab 	} else if (st->data[3] != 10) {
539786baecfSMauro Carvalho Chehab 		err("Read eeprom, invalid reply length");
540c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
541c58b84eeSMauro Carvalho Chehab 	} else if (st->data[4] != seq) {
542786baecfSMauro Carvalho Chehab 		err("Read eeprom, wrong sequence in reply ");
543c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
544c58b84eeSMauro Carvalho Chehab 	} else if (st->data[5] != 1) {
545786baecfSMauro Carvalho Chehab 		err("Read eeprom, wrong status in reply ");
546c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
547786baecfSMauro Carvalho Chehab 	}
548786baecfSMauro Carvalho Chehab 
549c58b84eeSMauro Carvalho Chehab 	if (!ret) {
550c58b84eeSMauro Carvalho Chehab 		for (i = 0; i < len; i++)
551c58b84eeSMauro Carvalho Chehab 			values[i] = st->data[6 + i];
552c58b84eeSMauro Carvalho Chehab 	}
5537724325aSMauro Carvalho Chehab 	mutex_unlock(&d->data_mutex);
554c58b84eeSMauro Carvalho Chehab 
555c58b84eeSMauro Carvalho Chehab 	return ret;
556c58b84eeSMauro Carvalho Chehab }
557c58b84eeSMauro Carvalho Chehab 
af9005_boot_packet(struct usb_device * udev,int type,u8 * reply,u8 * buf,int size)558c58b84eeSMauro Carvalho Chehab static int af9005_boot_packet(struct usb_device *udev, int type, u8 *reply,
559c58b84eeSMauro Carvalho Chehab 			      u8 *buf, int size)
560786baecfSMauro Carvalho Chehab {
561786baecfSMauro Carvalho Chehab 	u16 checksum;
56251d0c99bSSean Young 	int act_len = 0, i, ret;
563c58b84eeSMauro Carvalho Chehab 
564c58b84eeSMauro Carvalho Chehab 	memset(buf, 0, size);
565786baecfSMauro Carvalho Chehab 	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
566786baecfSMauro Carvalho Chehab 	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
567786baecfSMauro Carvalho Chehab 	switch (type) {
568786baecfSMauro Carvalho Chehab 	case FW_CONFIG:
569786baecfSMauro Carvalho Chehab 		buf[2] = 0x11;
570786baecfSMauro Carvalho Chehab 		buf[3] = 0x04;
571786baecfSMauro Carvalho Chehab 		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
572786baecfSMauro Carvalho Chehab 		buf[5] = 0x03;
573786baecfSMauro Carvalho Chehab 		checksum = buf[4] + buf[5];
574786baecfSMauro Carvalho Chehab 		buf[6] = (u8) ((checksum >> 8) & 0xff);
575786baecfSMauro Carvalho Chehab 		buf[7] = (u8) (checksum & 0xff);
576786baecfSMauro Carvalho Chehab 		break;
577786baecfSMauro Carvalho Chehab 	case FW_CONFIRM:
578786baecfSMauro Carvalho Chehab 		buf[2] = 0x11;
579786baecfSMauro Carvalho Chehab 		buf[3] = 0x04;
580786baecfSMauro Carvalho Chehab 		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
581786baecfSMauro Carvalho Chehab 		buf[5] = 0x01;
582786baecfSMauro Carvalho Chehab 		checksum = buf[4] + buf[5];
583786baecfSMauro Carvalho Chehab 		buf[6] = (u8) ((checksum >> 8) & 0xff);
584786baecfSMauro Carvalho Chehab 		buf[7] = (u8) (checksum & 0xff);
585786baecfSMauro Carvalho Chehab 		break;
586786baecfSMauro Carvalho Chehab 	case FW_BOOT:
587786baecfSMauro Carvalho Chehab 		buf[2] = 0x10;
588786baecfSMauro Carvalho Chehab 		buf[3] = 0x08;
589786baecfSMauro Carvalho Chehab 		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
590786baecfSMauro Carvalho Chehab 		buf[5] = 0x97;
591786baecfSMauro Carvalho Chehab 		buf[6] = 0xaa;
592786baecfSMauro Carvalho Chehab 		buf[7] = 0x55;
593786baecfSMauro Carvalho Chehab 		buf[8] = 0xa5;
594786baecfSMauro Carvalho Chehab 		buf[9] = 0x5a;
595786baecfSMauro Carvalho Chehab 		checksum = 0;
596786baecfSMauro Carvalho Chehab 		for (i = 4; i <= 9; i++)
597786baecfSMauro Carvalho Chehab 			checksum += buf[i];
598786baecfSMauro Carvalho Chehab 		buf[10] = (u8) ((checksum >> 8) & 0xff);
599786baecfSMauro Carvalho Chehab 		buf[11] = (u8) (checksum & 0xff);
600786baecfSMauro Carvalho Chehab 		break;
601786baecfSMauro Carvalho Chehab 	default:
602786baecfSMauro Carvalho Chehab 		err("boot packet invalid boot packet type");
603786baecfSMauro Carvalho Chehab 		return -EINVAL;
604786baecfSMauro Carvalho Chehab 	}
605786baecfSMauro Carvalho Chehab 	deb_fw(">>> ");
606786baecfSMauro Carvalho Chehab 	debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
607786baecfSMauro Carvalho Chehab 
608786baecfSMauro Carvalho Chehab 	ret = usb_bulk_msg(udev,
609786baecfSMauro Carvalho Chehab 			   usb_sndbulkpipe(udev, 0x02),
610786baecfSMauro Carvalho Chehab 			   buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
611786baecfSMauro Carvalho Chehab 	if (ret)
612786baecfSMauro Carvalho Chehab 		err("boot packet bulk message failed: %d (%d/%d)", ret,
613786baecfSMauro Carvalho Chehab 		    FW_BULKOUT_SIZE + 2, act_len);
614786baecfSMauro Carvalho Chehab 	else
615786baecfSMauro Carvalho Chehab 		ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
616786baecfSMauro Carvalho Chehab 	if (ret)
617786baecfSMauro Carvalho Chehab 		return ret;
618786baecfSMauro Carvalho Chehab 	memset(buf, 0, 9);
619786baecfSMauro Carvalho Chehab 	ret = usb_bulk_msg(udev,
620786baecfSMauro Carvalho Chehab 			   usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
621786baecfSMauro Carvalho Chehab 	if (ret) {
622786baecfSMauro Carvalho Chehab 		err("boot packet recv bulk message failed: %d", ret);
623786baecfSMauro Carvalho Chehab 		return ret;
624786baecfSMauro Carvalho Chehab 	}
625786baecfSMauro Carvalho Chehab 	deb_fw("<<< ");
626786baecfSMauro Carvalho Chehab 	debug_dump(buf, act_len, deb_fw);
627786baecfSMauro Carvalho Chehab 	checksum = 0;
628786baecfSMauro Carvalho Chehab 	switch (type) {
629786baecfSMauro Carvalho Chehab 	case FW_CONFIG:
630786baecfSMauro Carvalho Chehab 		if (buf[2] != 0x11) {
631786baecfSMauro Carvalho Chehab 			err("boot bad config header.");
632786baecfSMauro Carvalho Chehab 			return -EIO;
633786baecfSMauro Carvalho Chehab 		}
634786baecfSMauro Carvalho Chehab 		if (buf[3] != 0x05) {
635786baecfSMauro Carvalho Chehab 			err("boot bad config size.");
636786baecfSMauro Carvalho Chehab 			return -EIO;
637786baecfSMauro Carvalho Chehab 		}
638786baecfSMauro Carvalho Chehab 		if (buf[4] != 0x00) {
639786baecfSMauro Carvalho Chehab 			err("boot bad config sequence.");
640786baecfSMauro Carvalho Chehab 			return -EIO;
641786baecfSMauro Carvalho Chehab 		}
642786baecfSMauro Carvalho Chehab 		if (buf[5] != 0x04) {
643786baecfSMauro Carvalho Chehab 			err("boot bad config subtype.");
644786baecfSMauro Carvalho Chehab 			return -EIO;
645786baecfSMauro Carvalho Chehab 		}
646786baecfSMauro Carvalho Chehab 		for (i = 4; i <= 6; i++)
647786baecfSMauro Carvalho Chehab 			checksum += buf[i];
648786baecfSMauro Carvalho Chehab 		if (buf[7] * 256 + buf[8] != checksum) {
649786baecfSMauro Carvalho Chehab 			err("boot bad config checksum.");
650786baecfSMauro Carvalho Chehab 			return -EIO;
651786baecfSMauro Carvalho Chehab 		}
652786baecfSMauro Carvalho Chehab 		*reply = buf[6];
653786baecfSMauro Carvalho Chehab 		break;
654786baecfSMauro Carvalho Chehab 	case FW_CONFIRM:
655786baecfSMauro Carvalho Chehab 		if (buf[2] != 0x11) {
656786baecfSMauro Carvalho Chehab 			err("boot bad confirm header.");
657786baecfSMauro Carvalho Chehab 			return -EIO;
658786baecfSMauro Carvalho Chehab 		}
659786baecfSMauro Carvalho Chehab 		if (buf[3] != 0x05) {
660786baecfSMauro Carvalho Chehab 			err("boot bad confirm size.");
661786baecfSMauro Carvalho Chehab 			return -EIO;
662786baecfSMauro Carvalho Chehab 		}
663786baecfSMauro Carvalho Chehab 		if (buf[4] != 0x00) {
664786baecfSMauro Carvalho Chehab 			err("boot bad confirm sequence.");
665786baecfSMauro Carvalho Chehab 			return -EIO;
666786baecfSMauro Carvalho Chehab 		}
667786baecfSMauro Carvalho Chehab 		if (buf[5] != 0x02) {
668786baecfSMauro Carvalho Chehab 			err("boot bad confirm subtype.");
669786baecfSMauro Carvalho Chehab 			return -EIO;
670786baecfSMauro Carvalho Chehab 		}
671786baecfSMauro Carvalho Chehab 		for (i = 4; i <= 6; i++)
672786baecfSMauro Carvalho Chehab 			checksum += buf[i];
673786baecfSMauro Carvalho Chehab 		if (buf[7] * 256 + buf[8] != checksum) {
674786baecfSMauro Carvalho Chehab 			err("boot bad confirm checksum.");
675786baecfSMauro Carvalho Chehab 			return -EIO;
676786baecfSMauro Carvalho Chehab 		}
677786baecfSMauro Carvalho Chehab 		*reply = buf[6];
678786baecfSMauro Carvalho Chehab 		break;
679786baecfSMauro Carvalho Chehab 	case FW_BOOT:
680786baecfSMauro Carvalho Chehab 		if (buf[2] != 0x10) {
681786baecfSMauro Carvalho Chehab 			err("boot bad boot header.");
682786baecfSMauro Carvalho Chehab 			return -EIO;
683786baecfSMauro Carvalho Chehab 		}
684786baecfSMauro Carvalho Chehab 		if (buf[3] != 0x05) {
685786baecfSMauro Carvalho Chehab 			err("boot bad boot size.");
686786baecfSMauro Carvalho Chehab 			return -EIO;
687786baecfSMauro Carvalho Chehab 		}
688786baecfSMauro Carvalho Chehab 		if (buf[4] != 0x00) {
689786baecfSMauro Carvalho Chehab 			err("boot bad boot sequence.");
690786baecfSMauro Carvalho Chehab 			return -EIO;
691786baecfSMauro Carvalho Chehab 		}
692786baecfSMauro Carvalho Chehab 		if (buf[5] != 0x01) {
693786baecfSMauro Carvalho Chehab 			err("boot bad boot pattern 01.");
694786baecfSMauro Carvalho Chehab 			return -EIO;
695786baecfSMauro Carvalho Chehab 		}
696786baecfSMauro Carvalho Chehab 		if (buf[6] != 0x10) {
697786baecfSMauro Carvalho Chehab 			err("boot bad boot pattern 10.");
698786baecfSMauro Carvalho Chehab 			return -EIO;
699786baecfSMauro Carvalho Chehab 		}
700786baecfSMauro Carvalho Chehab 		for (i = 4; i <= 6; i++)
701786baecfSMauro Carvalho Chehab 			checksum += buf[i];
702786baecfSMauro Carvalho Chehab 		if (buf[7] * 256 + buf[8] != checksum) {
703786baecfSMauro Carvalho Chehab 			err("boot bad boot checksum.");
704786baecfSMauro Carvalho Chehab 			return -EIO;
705786baecfSMauro Carvalho Chehab 		}
706786baecfSMauro Carvalho Chehab 		break;
707786baecfSMauro Carvalho Chehab 
708786baecfSMauro Carvalho Chehab 	}
709786baecfSMauro Carvalho Chehab 
710786baecfSMauro Carvalho Chehab 	return 0;
711786baecfSMauro Carvalho Chehab }
712786baecfSMauro Carvalho Chehab 
af9005_download_firmware(struct usb_device * udev,const struct firmware * fw)713786baecfSMauro Carvalho Chehab static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
714786baecfSMauro Carvalho Chehab {
715786baecfSMauro Carvalho Chehab 	int i, packets, ret, act_len;
716786baecfSMauro Carvalho Chehab 
717c58b84eeSMauro Carvalho Chehab 	u8 *buf;
718786baecfSMauro Carvalho Chehab 	u8 reply;
719786baecfSMauro Carvalho Chehab 
720c58b84eeSMauro Carvalho Chehab 	buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL);
721c58b84eeSMauro Carvalho Chehab 	if (!buf)
722c58b84eeSMauro Carvalho Chehab 		return -ENOMEM;
723c58b84eeSMauro Carvalho Chehab 
724c58b84eeSMauro Carvalho Chehab 	ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf,
725c58b84eeSMauro Carvalho Chehab 				 FW_BULKOUT_SIZE + 2);
726786baecfSMauro Carvalho Chehab 	if (ret)
727c58b84eeSMauro Carvalho Chehab 		goto err;
728786baecfSMauro Carvalho Chehab 	if (reply != 0x01) {
729786baecfSMauro Carvalho Chehab 		err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
730c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
731c58b84eeSMauro Carvalho Chehab 		goto err;
732786baecfSMauro Carvalho Chehab 	}
733786baecfSMauro Carvalho Chehab 	packets = fw->size / FW_BULKOUT_SIZE;
734786baecfSMauro Carvalho Chehab 	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
735786baecfSMauro Carvalho Chehab 	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
736786baecfSMauro Carvalho Chehab 	for (i = 0; i < packets; i++) {
737786baecfSMauro Carvalho Chehab 		memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
738786baecfSMauro Carvalho Chehab 		       FW_BULKOUT_SIZE);
739786baecfSMauro Carvalho Chehab 		deb_fw(">>> ");
740786baecfSMauro Carvalho Chehab 		debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
741786baecfSMauro Carvalho Chehab 		ret = usb_bulk_msg(udev,
742786baecfSMauro Carvalho Chehab 				   usb_sndbulkpipe(udev, 0x02),
743786baecfSMauro Carvalho Chehab 				   buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
744786baecfSMauro Carvalho Chehab 		if (ret) {
745786baecfSMauro Carvalho Chehab 			err("firmware download failed at packet %d with code %d", i, ret);
746c58b84eeSMauro Carvalho Chehab 			goto err;
747786baecfSMauro Carvalho Chehab 		}
748786baecfSMauro Carvalho Chehab 	}
749c58b84eeSMauro Carvalho Chehab 	ret = af9005_boot_packet(udev, FW_CONFIRM, &reply,
750c58b84eeSMauro Carvalho Chehab 				 buf, FW_BULKOUT_SIZE + 2);
751786baecfSMauro Carvalho Chehab 	if (ret)
752c58b84eeSMauro Carvalho Chehab 		goto err;
753786baecfSMauro Carvalho Chehab 	if (reply != (u8) (packets & 0xff)) {
754786baecfSMauro Carvalho Chehab 		err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
755c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
756c58b84eeSMauro Carvalho Chehab 		goto err;
757786baecfSMauro Carvalho Chehab 	}
758c58b84eeSMauro Carvalho Chehab 	ret = af9005_boot_packet(udev, FW_BOOT, &reply, buf,
759c58b84eeSMauro Carvalho Chehab 				 FW_BULKOUT_SIZE + 2);
760786baecfSMauro Carvalho Chehab 	if (ret)
761c58b84eeSMauro Carvalho Chehab 		goto err;
762c58b84eeSMauro Carvalho Chehab 	ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf,
763c58b84eeSMauro Carvalho Chehab 				 FW_BULKOUT_SIZE + 2);
764786baecfSMauro Carvalho Chehab 	if (ret)
765c58b84eeSMauro Carvalho Chehab 		goto err;
766786baecfSMauro Carvalho Chehab 	if (reply != 0x02) {
767786baecfSMauro Carvalho Chehab 		err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
768c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
769c58b84eeSMauro Carvalho Chehab 		goto err;
770786baecfSMauro Carvalho Chehab 	}
771786baecfSMauro Carvalho Chehab 
772c58b84eeSMauro Carvalho Chehab err:
773c58b84eeSMauro Carvalho Chehab 	kfree(buf);
774c58b84eeSMauro Carvalho Chehab 	return ret;
775786baecfSMauro Carvalho Chehab 
776786baecfSMauro Carvalho Chehab }
777786baecfSMauro Carvalho Chehab 
af9005_led_control(struct dvb_usb_device * d,int onoff)778786baecfSMauro Carvalho Chehab int af9005_led_control(struct dvb_usb_device *d, int onoff)
779786baecfSMauro Carvalho Chehab {
780786baecfSMauro Carvalho Chehab 	struct af9005_device_state *st = d->priv;
781786baecfSMauro Carvalho Chehab 	int temp, ret;
782786baecfSMauro Carvalho Chehab 
783786baecfSMauro Carvalho Chehab 	if (onoff && dvb_usb_af9005_led)
784786baecfSMauro Carvalho Chehab 		temp = 1;
785786baecfSMauro Carvalho Chehab 	else
786786baecfSMauro Carvalho Chehab 		temp = 0;
787786baecfSMauro Carvalho Chehab 	if (st->led_state != temp) {
788786baecfSMauro Carvalho Chehab 		ret =
789786baecfSMauro Carvalho Chehab 		    af9005_write_register_bits(d, xd_p_reg_top_locken1,
790786baecfSMauro Carvalho Chehab 					       reg_top_locken1_pos,
791786baecfSMauro Carvalho Chehab 					       reg_top_locken1_len, temp);
792786baecfSMauro Carvalho Chehab 		if (ret)
793786baecfSMauro Carvalho Chehab 			return ret;
794786baecfSMauro Carvalho Chehab 		ret =
795786baecfSMauro Carvalho Chehab 		    af9005_write_register_bits(d, xd_p_reg_top_lock1,
796786baecfSMauro Carvalho Chehab 					       reg_top_lock1_pos,
797786baecfSMauro Carvalho Chehab 					       reg_top_lock1_len, temp);
798786baecfSMauro Carvalho Chehab 		if (ret)
799786baecfSMauro Carvalho Chehab 			return ret;
800786baecfSMauro Carvalho Chehab 		st->led_state = temp;
801786baecfSMauro Carvalho Chehab 	}
802786baecfSMauro Carvalho Chehab 	return 0;
803786baecfSMauro Carvalho Chehab }
804786baecfSMauro Carvalho Chehab 
af9005_frontend_attach(struct dvb_usb_adapter * adap)805786baecfSMauro Carvalho Chehab static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
806786baecfSMauro Carvalho Chehab {
807786baecfSMauro Carvalho Chehab 	u8 buf[8];
808786baecfSMauro Carvalho Chehab 	int i;
809786baecfSMauro Carvalho Chehab 
810786baecfSMauro Carvalho Chehab 	/* without these calls the first commands after downloading
811786baecfSMauro Carvalho Chehab 	   the firmware fail. I put these calls here to simulate
812786baecfSMauro Carvalho Chehab 	   what it is done in dvb-usb-init.c.
813786baecfSMauro Carvalho Chehab 	 */
814786baecfSMauro Carvalho Chehab 	struct usb_device *udev = adap->dev->udev;
815786baecfSMauro Carvalho Chehab 	usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
816786baecfSMauro Carvalho Chehab 	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
817786baecfSMauro Carvalho Chehab 	if (dvb_usb_af9005_dump_eeprom) {
818786baecfSMauro Carvalho Chehab 		printk("EEPROM DUMP\n");
819786baecfSMauro Carvalho Chehab 		for (i = 0; i < 255; i += 8) {
820786baecfSMauro Carvalho Chehab 			af9005_read_eeprom(adap->dev, i, buf, 8);
821786baecfSMauro Carvalho Chehab 			debug_dump(buf, 8, printk);
822786baecfSMauro Carvalho Chehab 		}
823786baecfSMauro Carvalho Chehab 	}
824786baecfSMauro Carvalho Chehab 	adap->fe_adap[0].fe = af9005_fe_attach(adap->dev);
825786baecfSMauro Carvalho Chehab 	return 0;
826786baecfSMauro Carvalho Chehab }
827786baecfSMauro Carvalho Chehab 
af9005_rc_query(struct dvb_usb_device * d,u32 * event,int * state)828786baecfSMauro Carvalho Chehab static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
829786baecfSMauro Carvalho Chehab {
830786baecfSMauro Carvalho Chehab 	struct af9005_device_state *st = d->priv;
831786baecfSMauro Carvalho Chehab 	int ret, len;
832c58b84eeSMauro Carvalho Chehab 	u8 seq;
833786baecfSMauro Carvalho Chehab 
834786baecfSMauro Carvalho Chehab 	*state = REMOTE_NO_KEY_PRESSED;
835786baecfSMauro Carvalho Chehab 	if (rc_decode == NULL) {
836786baecfSMauro Carvalho Chehab 		/* it shouldn't never come here */
837786baecfSMauro Carvalho Chehab 		return 0;
838786baecfSMauro Carvalho Chehab 	}
839c58b84eeSMauro Carvalho Chehab 
8407724325aSMauro Carvalho Chehab 	mutex_lock(&d->data_mutex);
841c58b84eeSMauro Carvalho Chehab 
842786baecfSMauro Carvalho Chehab 	/* deb_info("rc_query\n"); */
843c58b84eeSMauro Carvalho Chehab 	st->data[0] = 3;		/* rest of packet length low */
8443e4d8f48SMauro Carvalho Chehab 	st->data[1] = 0;		/* rest of packet length high */
845c58b84eeSMauro Carvalho Chehab 	st->data[2] = 0x40;		/* read remote */
846c58b84eeSMauro Carvalho Chehab 	st->data[3] = 1;		/* rest of packet length */
847c58b84eeSMauro Carvalho Chehab 	st->data[4] = seq = st->sequence++;	/* sequence number */
848c58b84eeSMauro Carvalho Chehab 	ret = dvb_usb_generic_rw(d, st->data, 5, st->data, 256, 0);
849786baecfSMauro Carvalho Chehab 	if (ret) {
850786baecfSMauro Carvalho Chehab 		err("rc query failed");
851c58b84eeSMauro Carvalho Chehab 		goto ret;
852786baecfSMauro Carvalho Chehab 	}
853c58b84eeSMauro Carvalho Chehab 	if (st->data[2] != 0x41) {
854786baecfSMauro Carvalho Chehab 		err("rc query bad header.");
855c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
856c58b84eeSMauro Carvalho Chehab 		goto ret;
857c58b84eeSMauro Carvalho Chehab 	} else if (st->data[4] != seq) {
858786baecfSMauro Carvalho Chehab 		err("rc query bad sequence.");
859c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
860c58b84eeSMauro Carvalho Chehab 		goto ret;
861786baecfSMauro Carvalho Chehab 	}
862c58b84eeSMauro Carvalho Chehab 	len = st->data[5];
863786baecfSMauro Carvalho Chehab 	if (len > 246) {
864786baecfSMauro Carvalho Chehab 		err("rc query invalid length");
865c58b84eeSMauro Carvalho Chehab 		ret = -EIO;
866c58b84eeSMauro Carvalho Chehab 		goto ret;
867786baecfSMauro Carvalho Chehab 	}
868786baecfSMauro Carvalho Chehab 	if (len > 0) {
869786baecfSMauro Carvalho Chehab 		deb_rc("rc data (%d) ", len);
870c58b84eeSMauro Carvalho Chehab 		debug_dump((st->data + 6), len, deb_rc);
871c58b84eeSMauro Carvalho Chehab 		ret = rc_decode(d, &st->data[6], len, event, state);
872786baecfSMauro Carvalho Chehab 		if (ret) {
873786baecfSMauro Carvalho Chehab 			err("rc_decode failed");
874c58b84eeSMauro Carvalho Chehab 			goto ret;
875786baecfSMauro Carvalho Chehab 		} else {
876786baecfSMauro Carvalho Chehab 			deb_rc("rc_decode state %x event %x\n", *state, *event);
877786baecfSMauro Carvalho Chehab 			if (*state == REMOTE_KEY_REPEAT)
878786baecfSMauro Carvalho Chehab 				*event = d->last_event;
879786baecfSMauro Carvalho Chehab 		}
880786baecfSMauro Carvalho Chehab 	}
881c58b84eeSMauro Carvalho Chehab 
882c58b84eeSMauro Carvalho Chehab ret:
8837724325aSMauro Carvalho Chehab 	mutex_unlock(&d->data_mutex);
884c58b84eeSMauro Carvalho Chehab 	return ret;
885786baecfSMauro Carvalho Chehab }
886786baecfSMauro Carvalho Chehab 
af9005_power_ctrl(struct dvb_usb_device * d,int onoff)887786baecfSMauro Carvalho Chehab static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
888786baecfSMauro Carvalho Chehab {
889786baecfSMauro Carvalho Chehab 
890786baecfSMauro Carvalho Chehab 	return 0;
891786baecfSMauro Carvalho Chehab }
892786baecfSMauro Carvalho Chehab 
af9005_pid_filter_control(struct dvb_usb_adapter * adap,int onoff)893786baecfSMauro Carvalho Chehab static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
894786baecfSMauro Carvalho Chehab {
895786baecfSMauro Carvalho Chehab 	int ret;
896786baecfSMauro Carvalho Chehab 	deb_info("pid filter control  onoff %d\n", onoff);
897786baecfSMauro Carvalho Chehab 	if (onoff) {
898786baecfSMauro Carvalho Chehab 		ret =
899786baecfSMauro Carvalho Chehab 		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
900786baecfSMauro Carvalho Chehab 		if (ret)
901786baecfSMauro Carvalho Chehab 			return ret;
902786baecfSMauro Carvalho Chehab 		ret =
903786baecfSMauro Carvalho Chehab 		    af9005_write_register_bits(adap->dev,
904786baecfSMauro Carvalho Chehab 					       XD_MP2IF_DMX_CTRL, 1, 1, 1);
905786baecfSMauro Carvalho Chehab 		if (ret)
906786baecfSMauro Carvalho Chehab 			return ret;
907786baecfSMauro Carvalho Chehab 		ret =
908786baecfSMauro Carvalho Chehab 		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
909786baecfSMauro Carvalho Chehab 	} else
910786baecfSMauro Carvalho Chehab 		ret =
911786baecfSMauro Carvalho Chehab 		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
912786baecfSMauro Carvalho Chehab 	if (ret)
913786baecfSMauro Carvalho Chehab 		return ret;
914786baecfSMauro Carvalho Chehab 	deb_info("pid filter control ok\n");
915786baecfSMauro Carvalho Chehab 	return 0;
916786baecfSMauro Carvalho Chehab }
917786baecfSMauro Carvalho Chehab 
af9005_pid_filter(struct dvb_usb_adapter * adap,int index,u16 pid,int onoff)918786baecfSMauro Carvalho Chehab static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
919786baecfSMauro Carvalho Chehab 			     u16 pid, int onoff)
920786baecfSMauro Carvalho Chehab {
921786baecfSMauro Carvalho Chehab 	u8 cmd = index & 0x1f;
922786baecfSMauro Carvalho Chehab 	int ret;
923786baecfSMauro Carvalho Chehab 	deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
924786baecfSMauro Carvalho Chehab 		 pid, onoff);
925786baecfSMauro Carvalho Chehab 	if (onoff) {
926786baecfSMauro Carvalho Chehab 		/* cannot use it as pid_filter_ctrl since it has to be done
927786baecfSMauro Carvalho Chehab 		   before setting the first pid */
928786baecfSMauro Carvalho Chehab 		if (adap->feedcount == 1) {
929786baecfSMauro Carvalho Chehab 			deb_info("first pid set, enable pid table\n");
930786baecfSMauro Carvalho Chehab 			ret = af9005_pid_filter_control(adap, onoff);
931786baecfSMauro Carvalho Chehab 			if (ret)
932786baecfSMauro Carvalho Chehab 				return ret;
933786baecfSMauro Carvalho Chehab 		}
934786baecfSMauro Carvalho Chehab 		ret =
935786baecfSMauro Carvalho Chehab 		    af9005_write_ofdm_register(adap->dev,
936786baecfSMauro Carvalho Chehab 					       XD_MP2IF_PID_DATA_L,
937786baecfSMauro Carvalho Chehab 					       (u8) (pid & 0xff));
938786baecfSMauro Carvalho Chehab 		if (ret)
939786baecfSMauro Carvalho Chehab 			return ret;
940786baecfSMauro Carvalho Chehab 		ret =
941786baecfSMauro Carvalho Chehab 		    af9005_write_ofdm_register(adap->dev,
942786baecfSMauro Carvalho Chehab 					       XD_MP2IF_PID_DATA_H,
943786baecfSMauro Carvalho Chehab 					       (u8) (pid >> 8));
944786baecfSMauro Carvalho Chehab 		if (ret)
945786baecfSMauro Carvalho Chehab 			return ret;
946786baecfSMauro Carvalho Chehab 		cmd |= 0x20 | 0x40;
947786baecfSMauro Carvalho Chehab 	} else {
948786baecfSMauro Carvalho Chehab 		if (adap->feedcount == 0) {
949786baecfSMauro Carvalho Chehab 			deb_info("last pid unset, disable pid table\n");
950786baecfSMauro Carvalho Chehab 			ret = af9005_pid_filter_control(adap, onoff);
951786baecfSMauro Carvalho Chehab 			if (ret)
952786baecfSMauro Carvalho Chehab 				return ret;
953786baecfSMauro Carvalho Chehab 		}
954786baecfSMauro Carvalho Chehab 	}
955786baecfSMauro Carvalho Chehab 	ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
956786baecfSMauro Carvalho Chehab 	if (ret)
957786baecfSMauro Carvalho Chehab 		return ret;
958786baecfSMauro Carvalho Chehab 	deb_info("set pid ok\n");
959786baecfSMauro Carvalho Chehab 	return 0;
960786baecfSMauro Carvalho Chehab }
961786baecfSMauro Carvalho Chehab 
af9005_identify_state(struct usb_device * udev,const struct dvb_usb_device_properties * props,const struct dvb_usb_device_description ** desc,int * cold)962786baecfSMauro Carvalho Chehab static int af9005_identify_state(struct usb_device *udev,
963d27958dfSSean Young 				 const struct dvb_usb_device_properties *props,
964d27958dfSSean Young 				 const struct dvb_usb_device_description **desc,
965786baecfSMauro Carvalho Chehab 				 int *cold)
966786baecfSMauro Carvalho Chehab {
967786baecfSMauro Carvalho Chehab 	int ret;
968c58b84eeSMauro Carvalho Chehab 	u8 reply, *buf;
969c58b84eeSMauro Carvalho Chehab 
970c58b84eeSMauro Carvalho Chehab 	buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL);
971c58b84eeSMauro Carvalho Chehab 	if (!buf)
972c58b84eeSMauro Carvalho Chehab 		return -ENOMEM;
973c58b84eeSMauro Carvalho Chehab 
974c58b84eeSMauro Carvalho Chehab 	ret = af9005_boot_packet(udev, FW_CONFIG, &reply,
975c58b84eeSMauro Carvalho Chehab 				 buf, FW_BULKOUT_SIZE + 2);
976786baecfSMauro Carvalho Chehab 	if (ret)
977c58b84eeSMauro Carvalho Chehab 		goto err;
978786baecfSMauro Carvalho Chehab 	deb_info("result of FW_CONFIG in identify state %d\n", reply);
979786baecfSMauro Carvalho Chehab 	if (reply == 0x01)
980786baecfSMauro Carvalho Chehab 		*cold = 1;
981786baecfSMauro Carvalho Chehab 	else if (reply == 0x02)
982786baecfSMauro Carvalho Chehab 		*cold = 0;
983786baecfSMauro Carvalho Chehab 	else
9842289adbfSNavid Emamdoost 		ret = -EIO;
9852289adbfSNavid Emamdoost 	if (!ret)
986786baecfSMauro Carvalho Chehab 		deb_info("Identify state cold = %d\n", *cold);
987c58b84eeSMauro Carvalho Chehab 
988c58b84eeSMauro Carvalho Chehab err:
989c58b84eeSMauro Carvalho Chehab 	kfree(buf);
990c58b84eeSMauro Carvalho Chehab 	return ret;
991786baecfSMauro Carvalho Chehab }
992786baecfSMauro Carvalho Chehab 
993786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties af9005_properties;
994786baecfSMauro Carvalho Chehab 
af9005_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)995786baecfSMauro Carvalho Chehab static int af9005_usb_probe(struct usb_interface *intf,
996786baecfSMauro Carvalho Chehab 			    const struct usb_device_id *id)
997786baecfSMauro Carvalho Chehab {
9987724325aSMauro Carvalho Chehab 	return dvb_usb_device_init(intf, &af9005_properties,
9997724325aSMauro Carvalho Chehab 				  THIS_MODULE, NULL, adapter_nr);
1000786baecfSMauro Carvalho Chehab }
1001786baecfSMauro Carvalho Chehab 
100241c7eb33SMauro Carvalho Chehab enum {
1003786baecfSMauro Carvalho Chehab 	AFATECH_AF9005,
100441c7eb33SMauro Carvalho Chehab 	TERRATEC_CINERGY_T_USB_XE,
100541c7eb33SMauro Carvalho Chehab 	ANSONIC_DVBT_USB,
1006786baecfSMauro Carvalho Chehab };
1007786baecfSMauro Carvalho Chehab 
1008786baecfSMauro Carvalho Chehab static struct usb_device_id af9005_usb_table[] = {
100941c7eb33SMauro Carvalho Chehab 	DVB_USB_DEV(AFATECH, AFATECH_AF9005),
101041c7eb33SMauro Carvalho Chehab 	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T_USB_XE),
101141c7eb33SMauro Carvalho Chehab 	DVB_USB_DEV(ANSONIC, ANSONIC_DVBT_USB),
1012786baecfSMauro Carvalho Chehab 	{ }
1013786baecfSMauro Carvalho Chehab };
1014786baecfSMauro Carvalho Chehab 
1015786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, af9005_usb_table);
1016786baecfSMauro Carvalho Chehab 
1017786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties af9005_properties = {
1018786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
1019786baecfSMauro Carvalho Chehab 
1020786baecfSMauro Carvalho Chehab 	.usb_ctrl = DEVICE_SPECIFIC,
1021786baecfSMauro Carvalho Chehab 	.firmware = "af9005.fw",
1022786baecfSMauro Carvalho Chehab 	.download_firmware = af9005_download_firmware,
1023786baecfSMauro Carvalho Chehab 	.no_reconnect = 1,
1024786baecfSMauro Carvalho Chehab 
1025786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct af9005_device_state),
1026786baecfSMauro Carvalho Chehab 
1027786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
1028786baecfSMauro Carvalho Chehab 	.adapter = {
1029786baecfSMauro Carvalho Chehab 		    {
1030786baecfSMauro Carvalho Chehab 		    .num_frontends = 1,
1031786baecfSMauro Carvalho Chehab 		    .fe = {{
1032786baecfSMauro Carvalho Chehab 		     .caps =
1033786baecfSMauro Carvalho Chehab 		     DVB_USB_ADAP_HAS_PID_FILTER |
1034786baecfSMauro Carvalho Chehab 		     DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
1035786baecfSMauro Carvalho Chehab 		     .pid_filter_count = 32,
1036786baecfSMauro Carvalho Chehab 		     .pid_filter = af9005_pid_filter,
1037786baecfSMauro Carvalho Chehab 		     /* .pid_filter_ctrl = af9005_pid_filter_control, */
1038786baecfSMauro Carvalho Chehab 		     .frontend_attach = af9005_frontend_attach,
1039786baecfSMauro Carvalho Chehab 		     /* .tuner_attach     = af9005_tuner_attach, */
1040786baecfSMauro Carvalho Chehab 		     /* parameter for the MPEG2-data transfer */
1041786baecfSMauro Carvalho Chehab 		     .stream = {
1042786baecfSMauro Carvalho Chehab 				.type = USB_BULK,
1043786baecfSMauro Carvalho Chehab 				.count = 10,
1044786baecfSMauro Carvalho Chehab 				.endpoint = 0x04,
1045786baecfSMauro Carvalho Chehab 				.u = {
1046786baecfSMauro Carvalho Chehab 				      .bulk = {
1047786baecfSMauro Carvalho Chehab 					       .buffersize = 4096,	/* actual size seen is 3948 */
1048786baecfSMauro Carvalho Chehab 					       }
1049786baecfSMauro Carvalho Chehab 				      }
1050786baecfSMauro Carvalho Chehab 				},
1051786baecfSMauro Carvalho Chehab 		     }},
1052786baecfSMauro Carvalho Chehab 		     }
1053786baecfSMauro Carvalho Chehab 		    },
1054786baecfSMauro Carvalho Chehab 	.power_ctrl = af9005_power_ctrl,
1055786baecfSMauro Carvalho Chehab 	.identify_state = af9005_identify_state,
1056786baecfSMauro Carvalho Chehab 
1057786baecfSMauro Carvalho Chehab 	.i2c_algo = &af9005_i2c_algo,
1058786baecfSMauro Carvalho Chehab 
1059786baecfSMauro Carvalho Chehab 	.rc.legacy = {
1060786baecfSMauro Carvalho Chehab 		.rc_interval = 200,
1061786baecfSMauro Carvalho Chehab 		.rc_map_table = NULL,
1062786baecfSMauro Carvalho Chehab 		.rc_map_size = 0,
1063786baecfSMauro Carvalho Chehab 		.rc_query = af9005_rc_query,
1064786baecfSMauro Carvalho Chehab 	},
1065786baecfSMauro Carvalho Chehab 
1066786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint          = 2,
1067786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint_response = 1,
1068786baecfSMauro Carvalho Chehab 
1069786baecfSMauro Carvalho Chehab 	.num_device_descs = 3,
1070786baecfSMauro Carvalho Chehab 	.devices = {
1071786baecfSMauro Carvalho Chehab 		    {.name = "Afatech DVB-T USB1.1 stick",
1072786baecfSMauro Carvalho Chehab 		     .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL},
1073786baecfSMauro Carvalho Chehab 		     .warm_ids = {NULL},
1074786baecfSMauro Carvalho Chehab 		     },
1075786baecfSMauro Carvalho Chehab 		    {.name = "TerraTec Cinergy T USB XE",
107641c7eb33SMauro Carvalho Chehab 		     .cold_ids = {&af9005_usb_table[TERRATEC_CINERGY_T_USB_XE], NULL},
1077786baecfSMauro Carvalho Chehab 		     .warm_ids = {NULL},
1078786baecfSMauro Carvalho Chehab 		     },
1079786baecfSMauro Carvalho Chehab 		    {.name = "Ansonic DVB-T USB1.1 stick",
108041c7eb33SMauro Carvalho Chehab 		     .cold_ids = {&af9005_usb_table[ANSONIC_DVBT_USB], NULL},
1081786baecfSMauro Carvalho Chehab 		     .warm_ids = {NULL},
1082786baecfSMauro Carvalho Chehab 		     },
1083786baecfSMauro Carvalho Chehab 		    {NULL},
1084786baecfSMauro Carvalho Chehab 		    }
1085786baecfSMauro Carvalho Chehab };
1086786baecfSMauro Carvalho Chehab 
1087786baecfSMauro Carvalho Chehab /* usb specific object needed to register this driver with the usb subsystem */
1088786baecfSMauro Carvalho Chehab static struct usb_driver af9005_usb_driver = {
1089786baecfSMauro Carvalho Chehab 	.name = "dvb_usb_af9005",
1090786baecfSMauro Carvalho Chehab 	.probe = af9005_usb_probe,
1091786baecfSMauro Carvalho Chehab 	.disconnect = dvb_usb_device_exit,
1092786baecfSMauro Carvalho Chehab 	.id_table = af9005_usb_table,
1093786baecfSMauro Carvalho Chehab };
1094786baecfSMauro Carvalho Chehab 
1095786baecfSMauro Carvalho Chehab /* module stuff */
af9005_usb_module_init(void)1096786baecfSMauro Carvalho Chehab static int __init af9005_usb_module_init(void)
1097786baecfSMauro Carvalho Chehab {
1098786baecfSMauro Carvalho Chehab 	int result;
1099786baecfSMauro Carvalho Chehab 	if ((result = usb_register(&af9005_usb_driver))) {
1100786baecfSMauro Carvalho Chehab 		err("usb_register failed. (%d)", result);
1101786baecfSMauro Carvalho Chehab 		return result;
1102786baecfSMauro Carvalho Chehab 	}
110322799487SFrank Schaefer #if IS_MODULE(CONFIG_DVB_USB_AF9005) || defined(CONFIG_DVB_USB_AF9005_REMOTE)
110422799487SFrank Schaefer 	/* FIXME: convert to todays kernel IR infrastructure */
1105786baecfSMauro Carvalho Chehab 	rc_decode = symbol_request(af9005_rc_decode);
1106786baecfSMauro Carvalho Chehab 	rc_keys = symbol_request(rc_map_af9005_table);
1107786baecfSMauro Carvalho Chehab 	rc_keys_size = symbol_request(rc_map_af9005_table_size);
110822799487SFrank Schaefer #endif
1109786baecfSMauro Carvalho Chehab 	if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
1110786baecfSMauro Carvalho Chehab 		err("af9005_rc_decode function not found, disabling remote");
1111786baecfSMauro Carvalho Chehab 		af9005_properties.rc.legacy.rc_query = NULL;
1112786baecfSMauro Carvalho Chehab 	} else {
1113786baecfSMauro Carvalho Chehab 		af9005_properties.rc.legacy.rc_map_table = rc_keys;
1114786baecfSMauro Carvalho Chehab 		af9005_properties.rc.legacy.rc_map_size = *rc_keys_size;
1115786baecfSMauro Carvalho Chehab 	}
1116786baecfSMauro Carvalho Chehab 
1117786baecfSMauro Carvalho Chehab 	return 0;
1118786baecfSMauro Carvalho Chehab }
1119786baecfSMauro Carvalho Chehab 
af9005_usb_module_exit(void)1120786baecfSMauro Carvalho Chehab static void __exit af9005_usb_module_exit(void)
1121786baecfSMauro Carvalho Chehab {
1122786baecfSMauro Carvalho Chehab 	/* release rc decode symbols */
1123786baecfSMauro Carvalho Chehab 	if (rc_decode != NULL)
1124786baecfSMauro Carvalho Chehab 		symbol_put(af9005_rc_decode);
1125786baecfSMauro Carvalho Chehab 	if (rc_keys != NULL)
1126786baecfSMauro Carvalho Chehab 		symbol_put(rc_map_af9005_table);
1127786baecfSMauro Carvalho Chehab 	if (rc_keys_size != NULL)
1128786baecfSMauro Carvalho Chehab 		symbol_put(rc_map_af9005_table_size);
1129786baecfSMauro Carvalho Chehab 	/* deregister this driver from the USB subsystem */
1130786baecfSMauro Carvalho Chehab 	usb_deregister(&af9005_usb_driver);
1131786baecfSMauro Carvalho Chehab }
1132786baecfSMauro Carvalho Chehab 
1133786baecfSMauro Carvalho Chehab module_init(af9005_usb_module_init);
1134786baecfSMauro Carvalho Chehab module_exit(af9005_usb_module_exit);
1135786baecfSMauro Carvalho Chehab 
1136786baecfSMauro Carvalho Chehab MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
1137786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
1138786baecfSMauro Carvalho Chehab MODULE_VERSION("1.0");
1139786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL");
1140