brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 20f1ef3 Raw
401 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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 information7 */8 9#include "dibusb.h"10 11/* Max transfer size done by I2C transfer functions */12#define MAX_XFER_SIZE  6413 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 function178 */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) == 0190					  && (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 it200			 * from dibusb's bad i2c implementation: reads without201			 * 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 stuff243 */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);401