1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Common methods for dibusb-based-receivers.
3  *
4  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
5  *
6  * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
7  */
8 
9 #include "dibusb.h"
10 
11 /* Max transfer size done by I2C transfer functions */
12 #define MAX_XFER_SIZE  64
13 
14 static int debug;
15 module_param(debug, int, 0644);
16 MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
17 MODULE_LICENSE("GPL");
18 
19 #define deb_info(args...) dprintk(debug,0x01,args)
20 
21 /* common stuff used by the different dibusb modules */
dibusb_streaming_ctrl(struct dvb_usb_adapter * adap,int onoff)22 int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
23 {
24 	if (adap->priv != NULL) {
25 		struct dibusb_state *st = adap->priv;
26 		if (st->ops.fifo_ctrl != NULL)
27 			if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) {
28 				err("error while controlling the fifo of the demod.");
29 				return -ENODEV;
30 			}
31 	}
32 	return 0;
33 }
34 EXPORT_SYMBOL(dibusb_streaming_ctrl);
35 
dibusb_pid_filter(struct dvb_usb_adapter * adap,int index,u16 pid,int onoff)36 int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
37 {
38 	if (adap->priv != NULL) {
39 		struct dibusb_state *st = adap->priv;
40 		if (st->ops.pid_ctrl != NULL)
41 			st->ops.pid_ctrl(adap->fe_adap[0].fe,
42 					 index, pid, onoff);
43 	}
44 	return 0;
45 }
46 EXPORT_SYMBOL(dibusb_pid_filter);
47 
dibusb_pid_filter_ctrl(struct dvb_usb_adapter * adap,int onoff)48 int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
49 {
50 	if (adap->priv != NULL) {
51 		struct dibusb_state *st = adap->priv;
52 		if (st->ops.pid_parse != NULL)
53 			if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0)
54 				err("could not handle pid_parser");
55 	}
56 	return 0;
57 }
58 EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
59 
dibusb_power_ctrl(struct dvb_usb_device * d,int onoff)60 int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
61 {
62 	u8 *b;
63 	int ret;
64 
65 	b = kmalloc(3, GFP_KERNEL);
66 	if (!b)
67 		return -ENOMEM;
68 
69 	b[0] = DIBUSB_REQ_SET_IOCTL;
70 	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
71 	b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
72 
73 	ret = dvb_usb_generic_write(d, b, 3);
74 
75 	kfree(b);
76 
77 	msleep(10);
78 
79 	return ret;
80 }
81 EXPORT_SYMBOL(dibusb_power_ctrl);
82 
dibusb2_0_streaming_ctrl(struct dvb_usb_adapter * adap,int onoff)83 int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
84 {
85 	int ret;
86 	u8 *b;
87 
88 	b = kmalloc(3, GFP_KERNEL);
89 	if (!b)
90 		return -ENOMEM;
91 
92 	if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
93 		goto ret;
94 
95 	if (onoff) {
96 		b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
97 		b[1] = 0x00;
98 		ret = dvb_usb_generic_write(adap->dev, b, 2);
99 		if (ret  < 0)
100 			goto ret;
101 	}
102 
103 	b[0] = DIBUSB_REQ_SET_IOCTL;
104 	b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
105 	ret = dvb_usb_generic_write(adap->dev, b, 3);
106 
107 ret:
108 	kfree(b);
109 	return ret;
110 }
111 EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
112 
dibusb2_0_power_ctrl(struct dvb_usb_device * d,int onoff)113 int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
114 {
115 	u8 *b;
116 	int ret;
117 
118 	if (!onoff)
119 		return 0;
120 
121 	b = kmalloc(3, GFP_KERNEL);
122 	if (!b)
123 		return -ENOMEM;
124 
125 	b[0] = DIBUSB_REQ_SET_IOCTL;
126 	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
127 	b[2] = DIBUSB_IOCTL_POWER_WAKEUP;
128 
129 	ret = dvb_usb_generic_write(d, b, 3);
130 
131 	kfree(b);
132 
133 	return ret;
134 }
135 EXPORT_SYMBOL(dibusb2_0_power_ctrl);
136 
dibusb_i2c_msg(struct dvb_usb_device * d,u8 addr,u8 * wbuf,u16 wlen,u8 * rbuf,u16 rlen)137 static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
138 			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
139 {
140 	u8 *sndbuf;
141 	int ret, wo, len;
142 
143 	/* write only ? */
144 	wo = (rbuf == NULL || rlen == 0);
145 
146 	len = 2 + wlen + (wo ? 0 : 2);
147 
148 	sndbuf = kmalloc(MAX_XFER_SIZE, GFP_KERNEL);
149 	if (!sndbuf)
150 		return -ENOMEM;
151 
152 	if (4 + wlen > MAX_XFER_SIZE) {
153 		warn("i2c wr: len=%d is too big!\n", wlen);
154 		ret = -EOPNOTSUPP;
155 		goto ret;
156 	}
157 
158 	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
159 	sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
160 
161 	memcpy(&sndbuf[2], wbuf, wlen);
162 
163 	if (!wo) {
164 		sndbuf[wlen + 2] = (rlen >> 8) & 0xff;
165 		sndbuf[wlen + 3] = rlen & 0xff;
166 	}
167 
168 	ret = dvb_usb_generic_rw(d, sndbuf, len, rbuf, rlen, 0);
169 
170 ret:
171 	kfree(sndbuf);
172 	return ret;
173 }
174 
175 /*
176  * I2C master xfer function
177  */
dibusb_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg msg[],int num)178 static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
179 {
180 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
181 	int i;
182 
183 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
184 		return -EAGAIN;
185 
186 	for (i = 0; i < num; i++) {
187 		/* write/read request */
188 		if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
189 					  && (msg[i+1].flags & I2C_M_RD)) {
190 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
191 						msg[i+1].buf,msg[i+1].len) < 0)
192 				break;
193 			i++;
194 		} else if ((msg[i].flags & I2C_M_RD) == 0) {
195 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
196 				break;
197 		} else if (msg[i].addr != 0x50) {
198 			/* 0x50 is the address of the eeprom - we need to protect it
199 			 * from dibusb's bad i2c implementation: reads without
200 			 * writing the offset before are forbidden */
201 			if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0)
202 				break;
203 		}
204 	}
205 
206 	mutex_unlock(&d->i2c_mutex);
207 	return i;
208 }
209 
dibusb_i2c_func(struct i2c_adapter * adapter)210 static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
211 {
212 	return I2C_FUNC_I2C;
213 }
214 
215 struct i2c_algorithm dibusb_i2c_algo = {
216 	.master_xfer   = dibusb_i2c_xfer,
217 	.functionality = dibusb_i2c_func,
218 };
219 EXPORT_SYMBOL(dibusb_i2c_algo);
220 
dibusb_read_eeprom_byte(struct dvb_usb_device * d,u8 offs,u8 * val)221 int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
222 {
223 	u8 *buf;
224 	int rc;
225 
226 	buf = kzalloc(2, GFP_KERNEL);
227 	if (!buf)
228 		return -ENOMEM;
229 
230 	buf[0] = offs;
231 
232 	rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1);
233 	*val = buf[1];
234 	kfree(buf);
235 
236 	return rc;
237 }
238 EXPORT_SYMBOL(dibusb_read_eeprom_byte);
239 
240 /*
241  * common remote control stuff
242  */
243 struct rc_map_table rc_map_dibusb_table[] = {
244 	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
245 	{ 0x0016, KEY_POWER },
246 	{ 0x0010, KEY_MUTE },
247 	{ 0x0003, KEY_1 },
248 	{ 0x0001, KEY_2 },
249 	{ 0x0006, KEY_3 },
250 	{ 0x0009, KEY_4 },
251 	{ 0x001d, KEY_5 },
252 	{ 0x001f, KEY_6 },
253 	{ 0x000d, KEY_7 },
254 	{ 0x0019, KEY_8 },
255 	{ 0x001b, KEY_9 },
256 	{ 0x0015, KEY_0 },
257 	{ 0x0005, KEY_CHANNELUP },
258 	{ 0x0002, KEY_CHANNELDOWN },
259 	{ 0x001e, KEY_VOLUMEUP },
260 	{ 0x000a, KEY_VOLUMEDOWN },
261 	{ 0x0011, KEY_RECORD },
262 	{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
263 	{ 0x0014, KEY_PLAY },
264 	{ 0x001a, KEY_STOP },
265 	{ 0x0040, KEY_REWIND },
266 	{ 0x0012, KEY_FASTFORWARD },
267 	{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
268 	{ 0x004c, KEY_PAUSE },
269 	{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
270 	{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
271 	/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
272 	{ 0x000c, KEY_CANCEL }, /* Cancel */
273 	{ 0x001c, KEY_EPG }, /* EPG */
274 	{ 0x0000, KEY_TAB }, /* Tab */
275 	{ 0x0048, KEY_INFO }, /* Preview */
276 	{ 0x0004, KEY_LIST }, /* RecordList */
277 	{ 0x000f, KEY_TEXT }, /* Teletext */
278 	/* Key codes for the KWorld/ADSTech/JetWay remote. */
279 	{ 0x8612, KEY_POWER },
280 	{ 0x860f, KEY_SELECT }, /* source */
281 	{ 0x860c, KEY_UNKNOWN }, /* scan */
282 	{ 0x860b, KEY_EPG },
283 	{ 0x8610, KEY_MUTE },
284 	{ 0x8601, KEY_1 },
285 	{ 0x8602, KEY_2 },
286 	{ 0x8603, KEY_3 },
287 	{ 0x8604, KEY_4 },
288 	{ 0x8605, KEY_5 },
289 	{ 0x8606, KEY_6 },
290 	{ 0x8607, KEY_7 },
291 	{ 0x8608, KEY_8 },
292 	{ 0x8609, KEY_9 },
293 	{ 0x860a, KEY_0 },
294 	{ 0x8618, KEY_ZOOM },
295 	{ 0x861c, KEY_UNKNOWN }, /* preview */
296 	{ 0x8613, KEY_UNKNOWN }, /* snap */
297 	{ 0x8600, KEY_UNDO },
298 	{ 0x861d, KEY_RECORD },
299 	{ 0x860d, KEY_STOP },
300 	{ 0x860e, KEY_PAUSE },
301 	{ 0x8616, KEY_PLAY },
302 	{ 0x8611, KEY_BACK },
303 	{ 0x8619, KEY_FORWARD },
304 	{ 0x8614, KEY_UNKNOWN }, /* pip */
305 	{ 0x8615, KEY_ESC },
306 	{ 0x861a, KEY_UP },
307 	{ 0x861e, KEY_DOWN },
308 	{ 0x861f, KEY_LEFT },
309 	{ 0x861b, KEY_RIGHT },
310 
311 	/* Key codes for the DiBcom MOD3000 remote. */
312 	{ 0x8000, KEY_MUTE },
313 	{ 0x8001, KEY_TEXT },
314 	{ 0x8002, KEY_HOME },
315 	{ 0x8003, KEY_POWER },
316 
317 	{ 0x8004, KEY_RED },
318 	{ 0x8005, KEY_GREEN },
319 	{ 0x8006, KEY_YELLOW },
320 	{ 0x8007, KEY_BLUE },
321 
322 	{ 0x8008, KEY_DVD },
323 	{ 0x8009, KEY_AUDIO },
324 	{ 0x800a, KEY_IMAGES },      /* Pictures */
325 	{ 0x800b, KEY_VIDEO },
326 
327 	{ 0x800c, KEY_BACK },
328 	{ 0x800d, KEY_UP },
329 	{ 0x800e, KEY_RADIO },
330 	{ 0x800f, KEY_EPG },
331 
332 	{ 0x8010, KEY_LEFT },
333 	{ 0x8011, KEY_OK },
334 	{ 0x8012, KEY_RIGHT },
335 	{ 0x8013, KEY_UNKNOWN },    /* SAP */
336 
337 	{ 0x8014, KEY_TV },
338 	{ 0x8015, KEY_DOWN },
339 	{ 0x8016, KEY_MENU },       /* DVD Menu */
340 	{ 0x8017, KEY_LAST },
341 
342 	{ 0x8018, KEY_RECORD },
343 	{ 0x8019, KEY_STOP },
344 	{ 0x801a, KEY_PAUSE },
345 	{ 0x801b, KEY_PLAY },
346 
347 	{ 0x801c, KEY_PREVIOUS },
348 	{ 0x801d, KEY_REWIND },
349 	{ 0x801e, KEY_FASTFORWARD },
350 	{ 0x801f, KEY_NEXT},
351 
352 	{ 0x8040, KEY_1 },
353 	{ 0x8041, KEY_2 },
354 	{ 0x8042, KEY_3 },
355 	{ 0x8043, KEY_CHANNELUP },
356 
357 	{ 0x8044, KEY_4 },
358 	{ 0x8045, KEY_5 },
359 	{ 0x8046, KEY_6 },
360 	{ 0x8047, KEY_CHANNELDOWN },
361 
362 	{ 0x8048, KEY_7 },
363 	{ 0x8049, KEY_8 },
364 	{ 0x804a, KEY_9 },
365 	{ 0x804b, KEY_VOLUMEUP },
366 
367 	{ 0x804c, KEY_CLEAR },
368 	{ 0x804d, KEY_0 },
369 	{ 0x804e, KEY_ENTER },
370 	{ 0x804f, KEY_VOLUMEDOWN },
371 };
372 EXPORT_SYMBOL(rc_map_dibusb_table);
373 
dibusb_rc_query(struct dvb_usb_device * d,u32 * event,int * state)374 int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
375 {
376 	u8 *buf;
377 	int ret;
378 
379 	buf = kmalloc(5, GFP_KERNEL);
380 	if (!buf)
381 		return -ENOMEM;
382 
383 	buf[0] = DIBUSB_REQ_POLL_REMOTE;
384 
385 	ret = dvb_usb_generic_rw(d, buf, 1, buf, 5, 0);
386 	if (ret < 0)
387 		goto ret;
388 
389 	dvb_usb_nec_rc_key_to_event(d, buf, event, state);
390 
391 	if (buf[0] != 0)
392 		deb_info("key: %*ph\n", 5, buf);
393 
394 ret:
395 	kfree(buf);
396 
397 	return ret;
398 }
399 EXPORT_SYMBOL(dibusb_rc_query);
400