File Index
Files and directories
Sign in
FILE

dibusb-common.c

File preview with syntax highlighting.

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