// SPDX-License-Identifier: GPL-2.0-or-later
/*
* DVB USB framework
*
* Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@posteo.de>
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
*/
#include "dvb_usb_common.h"
#include <media/media-device.h>
static int dvb_usbv2_disable_rc_polling;
module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
MODULE_PARM_DESC(disable_rc_polling,
"disable remote control polling (default: 0)");
static int dvb_usb_force_pid_filter_usage;
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage,
int, 0444);
MODULE_PARM_DESC(force_pid_filter_usage,
"force all DVB USB devices to use a PID filter, if any (default: 0)");
static int dvb_usbv2_download_firmware(struct dvb_usb_device *d,
const char *name)
{
int ret;
const struct firmware *fw;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
if (!d->props->download_firmware) {
ret = -EINVAL;
goto err;
}
ret = request_firmware(&fw, name, &d->udev->dev);
if (ret < 0) {
dev_err(&d->udev->dev,
"%s: Did not find the firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware\n",
KBUILD_MODNAME, name, ret);
goto err;
}
dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n",
KBUILD_MODNAME, name);
ret = d->props->download_firmware(d, fw);
release_firmware(fw);
if (ret < 0)
goto err;
return ret;
err:
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
{
int ret;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
if (!d->props->i2c_algo)
return 0;
strscpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name));
d->i2c_adap.algo = d->props->i2c_algo;
d->i2c_adap.dev.parent = &d->udev->dev;
i2c_set_adapdata(&d->i2c_adap, d);
ret = i2c_add_adapter(&d->i2c_adap);
if (ret < 0) {
d->i2c_adap.algo = NULL;
goto err;
}
return 0;
err:
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d)
{
dev_dbg(&d->udev->dev, "%s:\n", __func__);
if (d->i2c_adap.algo)
i2c_del_adapter(&d->i2c_adap);
return 0;
}
#if IS_ENABLED(CONFIG_RC_CORE)
static void dvb_usb_read_remote_control(struct work_struct *work)
{
struct dvb_usb_device *d = container_of(work,
struct dvb_usb_device, rc_query_work.work);
int ret;
/*
* When the parameter has been set to 1 via sysfs while the
* driver was running, or when bulk mode is enabled after IR init.
*/
if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) {
d->rc_polling_active = false;
return;
}
ret = d->rc.query(d);
if (ret < 0) {
dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n",
KBUILD_MODNAME, ret);
d->rc_polling_active = false;
return; /* stop polling */
}
schedule_delayed_work(&d->rc_query_work,
msecs_to_jiffies(d->rc.interval));
}
static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
{
int ret;
struct rc_dev *dev;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
return 0;
d->rc.map_name = d->rc_map;
ret = d->props->get_rc_config(d, &d->rc);
if (ret < 0)
goto err;
/* disable rc when there is no keymap defined */
if (!d->rc.map_name)
return 0;