summaryrefslogtreecommitdiff
path: root/drivers/media/dvb-core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb-core')
-rw-r--r--drivers/media/dvb-core/Kconfig2
-rw-r--r--drivers/media/dvb-core/Makefile2
-rw-r--r--drivers/media/dvb-core/dmxdev.c53
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c51
-rw-r--r--drivers/media/dvb-core/dvb_demux.c48
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c99
-rw-r--r--drivers/media/dvb-core/dvb_math.c141
-rw-r--r--drivers/media/dvb-core/dvb_net.c46
-rw-r--r--drivers/media/dvb-core/dvb_ringbuffer.c40
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c36
-rw-r--r--drivers/media/dvb-core/dvbdev.c304
11 files changed, 434 insertions, 388 deletions
diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig
index 6ffac618417b..8b3f2d53cd62 100644
--- a/drivers/media/dvb-core/Kconfig
+++ b/drivers/media/dvb-core/Kconfig
@@ -6,7 +6,7 @@
config DVB_MMAP
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
depends on DVB_CORE
- depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE
+ depends on VIDEO_DEV=y || VIDEO_DEV=DVB_CORE
select VIDEOBUF2_VMALLOC
help
This option enables DVB experimental memory-mapped API, which
diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
index 62b028ded9f7..1cb3ca67bed9 100644
--- a/drivers/media/dvb-core/Makefile
+++ b/drivers/media/dvb-core/Makefile
@@ -8,6 +8,6 @@ dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \
dvb_ca_en50221.o dvb_frontend.o \
- $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o
+ $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y)
obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 5d5a48475a54..8c6f5aafda1d 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -1,19 +1,9 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dmxdev.c - DVB demultiplexer device
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#define pr_fmt(fmt) "dmxdev: " fmt
@@ -362,7 +352,8 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
static void dvb_dmxdev_filter_timeout(struct timer_list *t)
{
- struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer);
+ struct dmxdev_filter *dmxdevfilter = timer_container_of(dmxdevfilter,
+ t, timer);
dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
@@ -375,7 +366,7 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
{
struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
- del_timer(&dmxdevfilter->timer);
+ timer_delete(&dmxdevfilter->timer);
if (para->timeout) {
dmxdevfilter->timer.expires =
jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
@@ -401,7 +392,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
- del_timer(&dmxdevfilter->timer);
+ timer_delete(&dmxdevfilter->timer);
dprintk("section callback %*ph\n", 6, buffer1);
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
@@ -492,7 +483,7 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
switch (dmxdevfilter->type) {
case DMXDEV_TYPE_SEC:
- del_timer(&dmxdevfilter->timer);
+ timer_delete(&dmxdevfilter->timer);
dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
break;
case DMXDEV_TYPE_PES:
@@ -741,7 +732,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
if (ret < 0) {
dvb_dmxdev_feed_restart(filter);
- filter->feed.sec->start_filtering(*secfeed);
+ *secfeed = NULL;
dprintk("could not get filter\n");
return ret;
}
@@ -800,6 +791,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
for (i = 0; i < dmxdev->filternum; i++)
if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break;
@@ -1413,13 +1409,13 @@ static const struct dvb_device dvbdev_dvr = {
};
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{
- int i;
+ int i, ret;
if (dmxdev->demux->open(dmxdev->demux) < 0)
return -EUSERS;
- dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter),
- dmxdev->filternum));
+ dmxdev->filter = vmalloc_array(dmxdev->filternum,
+ sizeof(struct dmxdev_filter));
if (!dmxdev->filter)
return -ENOMEM;
@@ -1432,21 +1428,36 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
DMXDEV_STATE_FREE);
}
- dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+ ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
DVB_DEVICE_DEMUX, dmxdev->filternum);
- dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+ if (ret < 0)
+ goto err_register_dvbdev;
+
+ ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
+ if (ret < 0)
+ goto err_register_dvr_dvbdev;
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
return 0;
+
+err_register_dvr_dvbdev:
+ dvb_unregister_device(dmxdev->dvbdev);
+err_register_dvbdev:
+ vfree(dmxdev->filter);
+ dmxdev->filter = NULL;
+ return ret;
}
EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
+ mutex_lock(&dmxdev->mutex);
dmxdev->exit = 1;
+ mutex_unlock(&dmxdev->mutex);
+
if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users == 1);
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 15a08d8c69ef..7b591aa1179f 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -151,13 +151,19 @@ struct dvb_ca_private {
/* mutex serializing ioctls */
struct mutex ioctl_mutex;
+
+ /* A mutex used when a device is disconnected */
+ struct mutex remove_mutex;
+
+ /* Whether the device is disconnected */
+ int exit;
};
static void dvb_ca_private_free(struct dvb_ca_private *ca)
{
unsigned int i;
- dvb_free_device(ca->dvbdev);
+ dvb_device_put(ca->dvbdev);
for (i = 0; i < ca->slot_count; i++)
vfree(ca->slot_info[i].rx_buffer.data);
@@ -187,7 +193,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
u8 *ebuf, int ecount);
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
- u8 *ebuf, int ecount);
+ u8 *ebuf, int ecount, int size_write_flag);
/**
* findstr - Safely find needle in haystack.
@@ -370,7 +376,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10);
if (ret)
return ret;
- ret = dvb_ca_en50221_write_data(ca, slot, buf, 2);
+ ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW);
if (ret != 2)
return -EIO;
ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
@@ -778,11 +784,13 @@ exit:
* @buf: The data in this buffer is treated as a complete link-level packet to
* be written.
* @bytes_write: Size of ebuf.
+ * @size_write_flag: A flag on Command Register which says whether the link size
+ * information will be written or not.
*
* return: Number of bytes written, or < 0 on error.
*/
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
- u8 *buf, int bytes_write)
+ u8 *buf, int bytes_write, int size_write_flag)
{
struct dvb_ca_slot *sl = &ca->slot_info[slot];
int status;
@@ -817,7 +825,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
/* OK, set HC bit */
status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
- IRQEN | CMDREG_HC);
+ IRQEN | CMDREG_HC | size_write_flag);
if (status)
goto exit;
@@ -1508,7 +1516,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
mutex_lock(&sl->slot_lock);
status = dvb_ca_en50221_write_data(ca, slot, fragbuf,
- fraglen + 2);
+ fraglen + 2, 0);
mutex_unlock(&sl->slot_lock);
if (status == (fraglen + 2)) {
written = 1;
@@ -1709,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dprintk("%s\n", __func__);
- if (!try_module_get(ca->pub->owner))
+ mutex_lock(&ca->remove_mutex);
+
+ if (ca->exit) {
+ mutex_unlock(&ca->remove_mutex);
+ return -ENODEV;
+ }
+
+ if (!try_module_get(ca->pub->owner)) {
+ mutex_unlock(&ca->remove_mutex);
return -EIO;
+ }
err = dvb_generic_open(inode, file);
if (err < 0) {
module_put(ca->pub->owner);
+ mutex_unlock(&ca->remove_mutex);
return err;
}
@@ -1739,6 +1757,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dvb_ca_private_get(ca);
+ mutex_unlock(&ca->remove_mutex);
return 0;
}
@@ -1758,6 +1777,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dprintk("%s\n", __func__);
+ mutex_lock(&ca->remove_mutex);
+
/* mark the CA device as closed */
ca->open = 0;
dvb_ca_en50221_thread_update_delay(ca);
@@ -1768,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dvb_ca_private_put(ca);
+ if (dvbdev->users == 1 && ca->exit == 1) {
+ mutex_unlock(&ca->remove_mutex);
+ wake_up(&dvbdev->wait_queue);
+ } else {
+ mutex_unlock(&ca->remove_mutex);
+ }
+
return err;
}
@@ -1891,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
}
mutex_init(&ca->ioctl_mutex);
+ mutex_init(&ca->remove_mutex);
if (signal_pending(current)) {
ret = -EINTR;
@@ -1933,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
dprintk("%s\n", __func__);
+ mutex_lock(&ca->remove_mutex);
+ ca->exit = 1;
+ mutex_unlock(&ca->remove_mutex);
+
+ if (ca->dvbdev->users < 1)
+ wait_event(ca->dvbdev->wait_queue,
+ ca->dvbdev->users == 1);
+
/* shutdown the thread if there was one */
kthread_stop(ca->thread);
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index 5fde1d38b3e3..290fc7961647 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -1,20 +1,10 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dvb_demux.c - DVB kernel demux API
*
* Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#define pr_fmt(fmt) "dvb_demux: " fmt
@@ -125,12 +115,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc;
- feed->cc = cc;
if (!ccok) {
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("missed packet: %d instead of %d!\n",
cc, (feed->cc + 1) & 0x0f);
}
+ feed->cc = cc;
if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa;
@@ -243,7 +233,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
{
struct dvb_demux *demux = feed->demux;
struct dmx_section_feed *sec = &feed->feed.sec;
- u16 limit, seclen, n;
+ u16 limit, seclen;
if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
return 0;
@@ -272,7 +262,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* to be sure always set secbuf */
sec->secbuf = sec->secbuf_base + sec->secbufp;
- for (n = 0; sec->secbufp + 2 < limit; n++) {
+ while (sec->secbufp + 2 < limit) {
seclen = section_length(sec->secbuf);
if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit)
@@ -310,7 +300,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc;
- feed->cc = cc;
if (buf[3] & 0x20) {
/* adaption field present, check for discontinuity_indicator */
@@ -346,6 +335,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
feed->pusi_seen = false;
dvb_dmx_swfilter_section_new(feed);
}
+ feed->cc = cc;
if (buf[1] & 0x40) {
/* PUSI=1 (is set), section boundary is here */
@@ -754,7 +744,8 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
return -ENODEV;
}
- if ((ret = demux->start_feed(feed)) < 0) {
+ ret = demux->start_feed(feed);
+ if (ret < 0) {
mutex_unlock(&demux->mutex);
return ret;
}
@@ -807,7 +798,8 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
if (mutex_lock_interruptible(&demux->mutex))
return -ERESTARTSYS;
- if (!(feed = dvb_dmx_feed_alloc(demux))) {
+ feed = dvb_dmx_feed_alloc(demux);
+ if (!feed) {
mutex_unlock(&demux->mutex);
return -EBUSY;
}
@@ -827,7 +819,8 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
(*ts_feed)->set = dmx_ts_feed_set;
- if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
+ feed->filter = dvb_dmx_filter_alloc(demux);
+ if (!feed->filter) {
feed->state = DMX_STATE_FREE;
mutex_unlock(&demux->mutex);
return -EBUSY;
@@ -933,7 +926,8 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
struct dmx_section_filter *sf;
u8 mask, mode, doneq;
- if (!(f = dvbdmxfeed->filter))
+ f = dvbdmxfeed->filter;
+ if (!f)
return;
do {
sf = &f->filter;
@@ -980,7 +974,8 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
prepare_secfilters(dvbdmxfeed);
- if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
+ ret = dvbdmx->start_feed(dvbdmxfeed);
+ if (ret < 0) {
mutex_unlock(&dvbdmx->mutex);
return ret;
}
@@ -1067,7 +1062,8 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
- if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
+ dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx);
+ if (!dvbdmxfeed) {
mutex_unlock(&dvbdmx->mutex);
return -EBUSY;
}
@@ -1233,7 +1229,7 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
return 0;
}
-static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
+static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
@@ -1248,14 +1244,14 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = NULL;
dvbdemux->users = 0;
- dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter),
- dvbdemux->filternum));
+ dvbdemux->filter = vmalloc_array(dvbdemux->filternum,
+ sizeof(struct dvb_demux_filter));
if (!dvbdemux->filter)
return -ENOMEM;
- dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed),
- dvbdemux->feednum));
+ dvbdemux->feed = vmalloc_array(dvbdemux->feednum,
+ sizeof(struct dvb_demux_feed));
if (!dvbdemux->feed) {
vfree(dvbdemux->filter);
dvbdemux->filter = NULL;
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 258637d762d6..a05aa271a1ba 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -136,7 +136,7 @@ static void __dvb_frontend_free(struct dvb_frontend *fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
if (fepriv)
- dvb_free_device(fepriv->dvbdev);
+ dvb_device_put(fepriv->dvbdev);
dvb_frontend_invoke_release(fe, fe->ops.release);
@@ -293,14 +293,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
}
if (events->eventw == events->eventr) {
- int ret;
+ struct wait_queue_entry wait;
+ int ret = 0;
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;
- ret = wait_event_interruptible(events->wait_queue,
- dvb_frontend_test_event(fepriv, events));
-
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&events->wait_queue, &wait);
+ while (!dvb_frontend_test_event(fepriv, events)) {
+ wait_woken(&wait, TASK_INTERRUPTIBLE, 0);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ remove_wait_queue(&events->wait_queue, &wait);
if (ret < 0)
return ret;
}
@@ -435,8 +443,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
default:
fepriv->auto_step++;
- fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
- break;
+ fepriv->auto_sub_step = 0;
+ continue;
}
if (!ready) fepriv->auto_sub_step++;
@@ -671,12 +679,10 @@ static int dvb_frontend_thread(void *data)
set_freezable();
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
-restart:
- wait_event_interruptible_timeout(fepriv->wait_queue,
- dvb_frontend_should_wakeup(fe) ||
- kthread_should_stop() ||
- freezing(current),
- fepriv->delay);
+ wait_event_freezable_timeout(fepriv->wait_queue,
+ dvb_frontend_should_wakeup(fe) ||
+ kthread_should_stop(),
+ fepriv->delay);
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
@@ -686,9 +692,6 @@ restart:
break;
}
- if (try_to_freeze())
- goto restart;
-
if (down_interruptible(&fepriv->sem))
break;
@@ -918,6 +921,7 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
/* If the standard is for satellite, convert frequencies to kHz */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -943,6 +947,7 @@ static u32 dvb_frontend_get_stepsize(struct dvb_frontend *fe)
u32 step = max(fe_step, tuner_step);
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -974,6 +979,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
/* range check: symbol rate */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -1040,6 +1046,10 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
c->scrambling_sequence_index = 0;/* default sequence */
switch (c->delivery_system) {
+ case SYS_DSS:
+ c->modulation = QPSK;
+ c->rolloff = ROLLOFF_20;
+ break;
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -1821,6 +1831,7 @@ static void prepare_tuning_algo_parameters(struct dvb_frontend *fe)
} else {
/* default values */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_ISDBS:
@@ -2152,7 +2163,8 @@ static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user(compat_ptr(tvps->props),
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2183,7 +2195,8 @@ static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user(compat_ptr(tvps->props),
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2288,6 +2301,9 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
case SYS_DVBC_ANNEX_C:
rolloff = 113;
break;
+ case SYS_DSS:
+ rolloff = 120;
+ break;
case SYS_DVBS:
case SYS_TURBO:
case SYS_ISDBS:
@@ -2360,7 +2376,8 @@ static int dvb_get_property(struct dvb_frontend *fe, struct file *file,
if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS)
return -EINVAL;
- tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user((void __user *)tvps->props,
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2438,7 +2455,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user((void __user *)tvps->props,
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2554,8 +2572,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
case FE_DISEQC_SEND_BURST:
if (fe->ops.diseqc_send_burst) {
- err = fe->ops.diseqc_send_burst(fe,
- (enum fe_sec_mini_cmd)parg);
+ err = fe->ops.diseqc_send_burst(fe, (long)parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2563,9 +2580,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
case FE_SET_TONE:
if (fe->ops.set_tone) {
- err = fe->ops.set_tone(fe,
- (enum fe_sec_tone_mode)parg);
- fepriv->tone = (enum fe_sec_tone_mode)parg;
+ fepriv->tone = (long)parg;
+ err = fe->ops.set_tone(fe, fepriv->tone);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2573,9 +2589,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
case FE_SET_VOLTAGE:
if (fe->ops.set_voltage) {
- err = fe->ops.set_voltage(fe,
- (enum fe_sec_voltage)parg);
- fepriv->voltage = (enum fe_sec_voltage)parg;
+ fepriv->voltage = (long)parg;
+ err = fe->ops.set_voltage(fe, fepriv->voltage);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2757,7 +2772,17 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (fe->exit == DVB_FE_DEVICE_REMOVED)
return -ENODEV;
- if (adapter->mfe_shared) {
+ if (adapter->mfe_shared == 2) {
+ mutex_lock(&adapter->mfe_lock);
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (adapter->mfe_dvbdev &&
+ !adapter->mfe_dvbdev->writers) {
+ mutex_unlock(&adapter->mfe_lock);
+ return -EBUSY;
+ }
+ adapter->mfe_dvbdev = dvbdev;
+ }
+ } else if (adapter->mfe_shared) {
mutex_lock(&adapter->mfe_lock);
if (!adapter->mfe_dvbdev)
@@ -2935,7 +2960,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
else if (fe->ops.tuner_ops.sleep)
ret = fe->ops.tuner_ops.sleep(fe);
- if (fe->ops.sleep)
+ if (fe->ops.suspend)
+ ret = fe->ops.suspend(fe);
+ else if (fe->ops.sleep)
ret = fe->ops.sleep(fe);
return ret;
@@ -2951,7 +2978,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
fe->id);
fe->exit = DVB_FE_DEVICE_RESUME;
- if (fe->ops.init)
+ if (fe->ops.resume)
+ ret = fe->ops.resume(fe);
+ else if (fe->ops.init)
ret = fe->ops.init(fe);
if (fe->ops.tuner_ops.resume)
@@ -2985,6 +3014,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
.name = fe->ops.info.name,
#endif
};
+ int ret;
dev_dbg(dvb->device, "%s:\n", __func__);
@@ -3018,8 +3048,13 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
"DVB: registering adapter %i frontend %i (%s)...\n",
fe->dvb->num, fe->id, fe->ops.info.name);
- dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
+ ret = dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND, 0);
+ if (ret) {
+ dvb_frontend_put(fe);
+ mutex_unlock(&frontend_mutex);
+ return ret;
+ }
/*
* Initialize the cache to the proper values according with the
diff --git a/drivers/media/dvb-core/dvb_math.c b/drivers/media/dvb-core/dvb_math.c
deleted file mode 100644
index dc90564d7f34..000000000000
--- a/drivers/media/dvb-core/dvb_math.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/bug.h>
-#include <media/dvb_math.h>
-
-static const unsigned short logtable[256] = {
- 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
- 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
- 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
- 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
- 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
- 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
- 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
- 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
- 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
- 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
- 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
- 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
- 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
- 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
- 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
- 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
- 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
- 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
- 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
- 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
- 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
- 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
- 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
- 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
- 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
- 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
- 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
- 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
- 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
- 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
- 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
- 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
-unsigned int intlog2(u32 value)
-{
- /**
- * returns: log2(value) * 2^24
- * wrong result if value = 0 (log2(0) is undefined)
- */
- unsigned int msb;
- unsigned int logentry;
- unsigned int significand;
- unsigned int interpolation;
-
- if (unlikely(value == 0)) {
- WARN_ON(1);
- return 0;
- }
-
- /* first detect the msb (count begins at 0) */
- msb = fls(value) - 1;
-
- /**
- * now we use a logtable after the following method:
- *
- * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
- * where x = msb and therefore 1 <= y < 2
- * first y is determined by shifting the value left
- * so that msb is bit 31
- * 0x00231f56 -> 0x8C7D5800
- * the result is y * 2^31 -> "significand"
- * then the highest 9 bits are used for a table lookup
- * the highest bit is discarded because it's always set
- * the highest nine bits in our example are 100011000
- * so we would use the entry 0x18
- */
- significand = value << (31 - msb);
- logentry = (significand >> 23) & 0xff;
-
- /**
- * last step we do is interpolation because of the
- * limitations of the log table the error is that part of
- * the significand which isn't used for lookup then we
- * compute the ratio between the error and the next table entry
- * and interpolate it between the log table entry used and the
- * next one the biggest error possible is 0x7fffff
- * (in our example it's 0x7D5800)
- * needed value for next table entry is 0x800000
- * so the interpolation is
- * (error / 0x800000) * (logtable_next - logtable_current)
- * in the implementation the division is moved to the end for
- * better accuracy there is also an overflow correction if
- * logtable_next is 256
- */
- interpolation = ((significand & 0x7fffff) *
- ((logtable[(logentry + 1) & 0xff] -
- logtable[logentry]) & 0xffff)) >> 15;
-
- /* now we return the result */
- return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
-}
-EXPORT_SYMBOL(intlog2);
-
-unsigned int intlog10(u32 value)
-{
- /**
- * returns: log10(value) * 2^24
- * wrong result if value = 0 (log10(0) is undefined)
- */
- u64 log;
-
- if (unlikely(value == 0)) {
- WARN_ON(1);
- return 0;
- }
-
- log = intlog2(value);
-
- /**
- * we use the following method:
- * log10(x) = log2(x) * log10(2)
- */
-
- return (log * 646456993) >> 31;
-}
-EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index dddebea644bb..8bb8dd34c223 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -1008,7 +1008,7 @@ static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static int dvb_net_filter_sec_set(struct net_device *dev,
struct dmx_section_filter **secfilter,
- u8 *mac, u8 *mac_mask)
+ const u8 *mac, u8 *mac_mask)
{
struct dvb_net_priv *priv = netdev_priv(dev);
int ret;
@@ -1052,7 +1052,7 @@ static int dvb_net_feed_start(struct net_device *dev)
int ret = 0, i;
struct dvb_net_priv *priv = netdev_priv(dev);
struct dmx_demux *demux = priv->demux;
- unsigned char *mac = (unsigned char *) dev->dev_addr;
+ const unsigned char *mac = (const unsigned char *) dev->dev_addr;
netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode);
mutex_lock(&priv->mutex);
@@ -1272,7 +1272,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p)
struct dvb_net_priv *priv = netdev_priv(dev);
struct sockaddr *addr=p;
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ eth_hw_addr_set(dev, addr->sa_data);
if (netif_running(dev))
schedule_work(&priv->restart_net_feed_wq);
@@ -1367,7 +1367,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
dvbnet->dvbdev->adapter->num, if_num);
net->addr_len = 6;
- memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
+ eth_hw_addr_set(net, dvbnet->dvbdev->adapter->proposed_mac);
dvbnet->device[if_num] = net;
@@ -1564,15 +1564,43 @@ static long dvb_net_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
}
+static int locked_dvb_net_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_net *dvbnet = dvbdev->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&dvbnet->remove_mutex))
+ return -ERESTARTSYS;
+
+ if (dvbnet->exit) {
+ mutex_unlock(&dvbnet->remove_mutex);
+ return -ENODEV;
+ }
+
+ ret = dvb_generic_open(inode, file);
+
+ mutex_unlock(&dvbnet->remove_mutex);
+
+ return ret;
+}
+
static int dvb_net_close(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
+ mutex_lock(&dvbnet->remove_mutex);
+
dvb_generic_release(inode, file);
- if(dvbdev->users == 1 && dvbnet->exit == 1)
+ if (dvbdev->users == 1 && dvbnet->exit == 1) {
+ mutex_unlock(&dvbnet->remove_mutex);
wake_up(&dvbdev->wait_queue);
+ } else {
+ mutex_unlock(&dvbnet->remove_mutex);
+ }
+
return 0;
}
@@ -1580,7 +1608,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
static const struct file_operations dvb_net_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = dvb_net_ioctl,
- .open = dvb_generic_open,
+ .open = locked_dvb_net_open,
.release = dvb_net_close,
.llseek = noop_llseek,
};
@@ -1599,10 +1627,13 @@ void dvb_net_release (struct dvb_net *dvbnet)
{
int i;
+ mutex_lock(&dvbnet->remove_mutex);
dvbnet->exit = 1;
+ mutex_unlock(&dvbnet->remove_mutex);
+
if (dvbnet->dvbdev->users < 1)
wait_event(dvbnet->dvbdev->wait_queue,
- dvbnet->dvbdev->users==1);
+ dvbnet->dvbdev->users == 1);
dvb_unregister_device(dvbnet->dvbdev);
@@ -1621,6 +1652,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
int i;
mutex_init(&dvbnet->ioctl_mutex);
+ mutex_init(&dvbnet->remove_mutex);
dvbnet->demux = dmx;
for (i=0; i<DVB_NET_DEVICES_MAX; i++)
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
index d1d471af0636..de6226556826 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -37,10 +37,11 @@
void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
{
- rbuf->pread=rbuf->pwrite=0;
- rbuf->data=data;
- rbuf->size=len;
- rbuf->error=0;
+ rbuf->pread = 0;
+ rbuf->pwrite = 0;
+ rbuf->data = data;
+ rbuf->size = len;
+ rbuf->error = 0;
init_waitqueue_head(&rbuf->queue);
@@ -235,7 +236,7 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
return len;
}
-ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
+ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
{
int status;
ssize_t oldpwrite = rbuf->pwrite;
@@ -245,7 +246,8 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
status = dvb_ringbuffer_write(rbuf, buf, len);
- if (status < 0) rbuf->pwrite = oldpwrite;
+ if (status < 0)
+ rbuf->pwrite = oldpwrite;
return status;
}
@@ -258,8 +260,10 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
pktlen = rbuf->data[idx] << 8;
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
- if (offset > pktlen) return -EINVAL;
- if ((offset + len) > pktlen) len = pktlen - offset;
+ if (offset > pktlen)
+ return -EINVAL;
+ if ((offset + len) > pktlen)
+ len = pktlen - offset;
idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
todo = len;
@@ -278,7 +282,7 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
}
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
- int offset, u8* buf, size_t len)
+ int offset, u8 *buf, size_t len)
{
size_t todo;
size_t split;
@@ -286,8 +290,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
pktlen = rbuf->data[idx] << 8;
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
- if (offset > pktlen) return -EINVAL;
- if ((offset + len) > pktlen) len = pktlen - offset;
+ if (offset > pktlen)
+ return -EINVAL;
+ if ((offset + len) > pktlen)
+ len = pktlen - offset;
idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
todo = len;
@@ -309,7 +315,7 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
// clean up disposed packets
- while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
+ while (dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
@@ -321,23 +327,25 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
}
}
-ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
+ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t *pktlen)
{
int consumed;
int curpktlen;
int curpktstatus;
if (idx == -1) {
- idx = rbuf->pread;
+ idx = rbuf->pread;
} else {
curpktlen = rbuf->data[idx] << 8;
curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
- consumed = (idx - rbuf->pread) % rbuf->size;
+ consumed = (idx - rbuf->pread);
+ if (consumed < 0)
+ consumed += rbuf->size;
- while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
+ while ((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
curpktlen = rbuf->data[idx] << 8;
curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 6974f1731529..29edaaff7a5c 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -5,10 +5,6 @@
* Copyright (C) 2015 Samsung Electronics
*
* Author: jh1009.sung@samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
*/
#include <linux/err.h>
@@ -171,17 +167,14 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
memset(ctx, 0, sizeof(struct dvb_vb2_ctx));
q->type = DVB_BUF_TYPE_CAPTURE;
- /**capture type*/
- q->is_output = 0;
/**only mmap is supported currently*/
q->io_modes = VB2_MMAP;
q->drv_priv = ctx;
q->buf_struct_size = sizeof(struct dvb_buffer);
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->ops = &dvb_vb2_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->buf_ops = &dvb_vb2_buf_ops;
- q->num_buffers = 0;
ret = vb2_core_queue_init(q);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
@@ -342,7 +335,7 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
ctx->buf_siz = req->size;
ctx->buf_cnt = req->count;
- ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, &req->count);
+ ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name,
@@ -358,7 +351,14 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
- vb2_core_querybuf(&ctx->vb_q, b->index, b);
+ struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index);
+
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
+ return -EINVAL;
+ }
+ vb2_core_querybuf(&ctx->vb_q, vb2, b);
dprintk(3, "[%s] index=%d\n", ctx->name, b->index);
return 0;
}
@@ -366,9 +366,15 @@ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
{
struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, exp->index);
int ret;
- ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, exp->index,
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
+ return -EINVAL;
+ }
+
+ ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, vb2,
0, exp->flags);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
@@ -382,9 +388,15 @@ int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
+ struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index);
int ret;
- ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL);
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
+ return -EINVAL;
+ }
+ ret = vb2_core_qbuf(&ctx->vb_q, vb2, b, NULL);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
b->index, ret);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 795d9bfaba5c..8b980d371a45 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -1,20 +1,10 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* dvbdev.c
*
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#define pr_fmt(fmt) "dvbdev: " fmt
@@ -37,6 +27,7 @@
#include <media/tuner.h>
static DEFINE_MUTEX(dvbdev_mutex);
+static LIST_HEAD(dvbdevfops_list);
static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644);
@@ -70,21 +61,21 @@ static const char * const dnames[] = {
#define DVB_MAX_IDS 4
static const u8 minor_type[] = {
- [DVB_DEVICE_VIDEO] = 0,
- [DVB_DEVICE_AUDIO] = 1,
- [DVB_DEVICE_SEC] = 2,
- [DVB_DEVICE_FRONTEND] = 3,
- [DVB_DEVICE_DEMUX] = 4,
- [DVB_DEVICE_DVR] = 5,
- [DVB_DEVICE_CA] = 6,
- [DVB_DEVICE_NET] = 7,
- [DVB_DEVICE_OSD] = 8,
+ [DVB_DEVICE_VIDEO] = 0,
+ [DVB_DEVICE_AUDIO] = 1,
+ [DVB_DEVICE_SEC] = 2,
+ [DVB_DEVICE_FRONTEND] = 3,
+ [DVB_DEVICE_DEMUX] = 4,
+ [DVB_DEVICE_DVR] = 5,
+ [DVB_DEVICE_CA] = 6,
+ [DVB_DEVICE_NET] = 7,
+ [DVB_DEVICE_OSD] = 8,
};
#define nums2minor(num, type, id) \
- (((num) << 6) | ((id) << 4) | minor_type[type])
+ (((num) << 6) | ((id) << 4) | minor_type[type])
-#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
+#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS * 64)
#endif
static struct class *dvb_class;
@@ -95,10 +86,15 @@ static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev;
+ unsigned int minor = iminor(inode);
+
+ if (minor >= MAX_DVB_MINORS)
+ return -ENODEV;
mutex_lock(&dvbdev_mutex);
down_read(&minor_rwsem);
- dvbdev = dvb_minors[iminor(inode)];
+
+ dvbdev = dvb_minors[minor];
if (dvbdev && dvbdev->fops) {
int err = 0;
@@ -107,12 +103,14 @@ static int dvb_device_open(struct inode *inode, struct file *file)
new_fops = fops_get(dvbdev->fops);
if (!new_fops)
goto fail;
- file->private_data = dvbdev;
+ file->private_data = dvb_device_get(dvbdev);
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode, file);
up_read(&minor_rwsem);
mutex_unlock(&dvbdev_mutex);
+ if (err)
+ dvb_device_put(dvbdev);
return err;
}
fail:
@@ -121,9 +119,7 @@ fail:
return -ENODEV;
}
-
-static const struct file_operations dvb_device_fops =
-{
+static const struct file_operations dvb_device_fops = {
.owner = THIS_MODULE,
.open = dvb_device_open,
.llseek = noop_llseek,
@@ -156,7 +152,6 @@ int dvb_generic_open(struct inode *inode, struct file *file)
}
EXPORT_SYMBOL(dvb_generic_open);
-
int dvb_generic_release(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
@@ -164,18 +159,19 @@ int dvb_generic_release(struct inode *inode, struct file *file)
if (!dvbdev)
return -ENODEV;
- if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
dvbdev->readers++;
- } else {
+ else
dvbdev->writers++;
- }
dvbdev->users++;
+
+ dvb_device_put(dvbdev);
+
return 0;
}
EXPORT_SYMBOL(dvb_generic_release);
-
long dvb_generic_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -191,13 +187,13 @@ long dvb_generic_ioctl(struct file *file,
}
EXPORT_SYMBOL(dvb_generic_ioctl);
-
-static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
+static int dvbdev_get_free_id(struct dvb_adapter *adap, int type)
{
u32 id = 0;
while (id < DVB_MAX_IDS) {
struct dvb_device *dev;
+
list_for_each_entry(dev, &adap->device_list, list_head)
if (dev->type == type && dev->id == id)
goto skip;
@@ -251,9 +247,9 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
- const char *name, int npads)
+ const char *name, int npads)
{
- int i, ret = 0;
+ int i;
dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
GFP_KERNEL);
@@ -270,6 +266,7 @@ static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
for (i = 0; i < npads; i++) {
struct media_pad *pads = &dvbdev->tsout_pads[i];
struct media_entity *entity = &dvbdev->tsout_entity[i];
+ int ret;
entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
if (!entity->name)
@@ -342,6 +339,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
GFP_KERNEL);
if (!dvbdev->pads) {
kfree(dvbdev->entity);
+ dvbdev->entity = NULL;
return -ENOMEM;
}
}
@@ -391,7 +389,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
static int dvb_register_media_device(struct dvb_device *dvbdev,
int type, int minor,
- unsigned demux_sink_pads)
+ unsigned int demux_sink_pads)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_link *link;
@@ -458,14 +456,16 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
enum dvb_device_type type, int demux_sink_pads)
{
struct dvb_device *dvbdev;
- struct file_operations *dvbdevfops;
+ struct file_operations *dvbdevfops = NULL;
+ struct dvbdevfops_node *node = NULL, *new_node = NULL;
struct device *clsdev;
int minor;
int id, ret;
mutex_lock(&dvbdev_register_lock);
- if ((id = dvbdev_get_free_id (adap, type)) < 0){
+ id = dvbdev_get_free_id(adap, type);
+ if (id < 0) {
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
pr_err("%s: couldn't find free device id\n", __func__);
@@ -473,89 +473,127 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
}
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
-
- if (!dvbdev){
+ if (!dvbdev) {
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
- dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
+ /*
+ * When a device of the same type is probe()d more than once,
+ * the first allocated fops are used. This prevents memory leaks
+ * that can occur when the same device is probe()d repeatedly.
+ */
+ list_for_each_entry(node, &dvbdevfops_list, list_head) {
+ if (node->fops->owner == adap->module &&
+ node->type == type && node->template == template) {
+ dvbdevfops = node->fops;
+ break;
+ }
+ }
- if (!dvbdevfops){
- kfree (dvbdev);
- mutex_unlock(&dvbdev_register_lock);
- return -ENOMEM;
+ if (!dvbdevfops) {
+ dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
+ if (!dvbdevfops) {
+ kfree(dvbdev);
+ *pdvbdev = NULL;
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
+ if (!new_node) {
+ kfree(dvbdevfops);
+ kfree(dvbdev);
+ *pdvbdev = NULL;
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ new_node->fops = dvbdevfops;
+ new_node->type = type;
+ new_node->template = template;
+ list_add_tail(&new_node->list_head, &dvbdevfops_list);
}
memcpy(dvbdev, template, sizeof(struct dvb_device));
+ kref_init(&dvbdev->ref);
dvbdev->type = type;
dvbdev->id = id;
dvbdev->adapter = adap;
dvbdev->priv = priv;
dvbdev->fops = dvbdevfops;
- init_waitqueue_head (&dvbdev->wait_queue);
-
+ init_waitqueue_head(&dvbdev->wait_queue);
dvbdevfops->owner = adap->module;
-
- list_add_tail (&dvbdev->list_head, &adap->device_list);
-
+ list_add_tail(&dvbdev->list_head, &adap->device_list);
down_write(&minor_rwsem);
#ifdef CONFIG_DVB_DYNAMIC_MINORS
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
- if (dvb_minors[minor] == NULL)
+ if (!dvb_minors[minor])
break;
-
- if (minor == MAX_DVB_MINORS) {
- list_del (&dvbdev->list_head);
- kfree(dvbdevfops);
+#else
+ minor = nums2minor(adap->num, type, id);
+#endif
+ if (minor >= MAX_DVB_MINORS) {
+ if (new_node) {
+ list_del(&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
+ list_del(&dvbdev->list_head);
kfree(dvbdev);
+ *pdvbdev = NULL;
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
return -EINVAL;
}
-#else
- minor = nums2minor(adap->num, type, id);
-#endif
dvbdev->minor = minor;
- dvb_minors[minor] = dvbdev;
+ dvb_minors[minor] = dvb_device_get(dvbdev);
up_write(&minor_rwsem);
-
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
if (ret) {
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
- __func__);
-
+ __func__);
+ if (new_node) {
+ list_del(&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
dvb_media_device_free(dvbdev);
- list_del (&dvbdev->list_head);
- kfree(dvbdevfops);
+ list_del(&dvbdev->list_head);
kfree(dvbdev);
+ *pdvbdev = NULL;
mutex_unlock(&dvbdev_register_lock);
return ret;
}
- mutex_unlock(&dvbdev_register_lock);
-
clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
- pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
- __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+ pr_err("%s: failed to create device dvb%d.%s%d (%pe)\n",
+ __func__, adap->num, dnames[type], id, clsdev);
+ if (new_node) {
+ list_del(&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
dvb_media_device_free(dvbdev);
- list_del (&dvbdev->list_head);
- kfree(dvbdevfops);
+ list_del(&dvbdev->list_head);
kfree(dvbdev);
+ *pdvbdev = NULL;
+ mutex_unlock(&dvbdev_register_lock);
return PTR_ERR(clsdev);
}
+
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor);
+ mutex_unlock(&dvbdev_register_lock);
return 0;
}
EXPORT_SYMBOL(dvb_register_device);
-
void dvb_remove_device(struct dvb_device *dvbdev)
{
if (!dvbdev)
@@ -563,36 +601,44 @@ void dvb_remove_device(struct dvb_device *dvbdev)
down_write(&minor_rwsem);
dvb_minors[dvbdev->minor] = NULL;
+ dvb_device_put(dvbdev);
up_write(&minor_rwsem);
dvb_media_device_free(dvbdev);
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
- list_del (&dvbdev->list_head);
+ list_del(&dvbdev->list_head);
}
EXPORT_SYMBOL(dvb_remove_device);
-
-void dvb_free_device(struct dvb_device *dvbdev)
+static void dvb_free_device(struct kref *ref)
{
- if (!dvbdev)
- return;
+ struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
- kfree (dvbdev->fops);
- kfree (dvbdev);
+ kfree(dvbdev);
}
-EXPORT_SYMBOL(dvb_free_device);
+struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
+{
+ kref_get(&dvbdev->ref);
+ return dvbdev;
+}
+EXPORT_SYMBOL(dvb_device_get);
+
+void dvb_device_put(struct dvb_device *dvbdev)
+{
+ if (dvbdev)
+ kref_put(&dvbdev->ref, dvb_free_device);
+}
void dvb_unregister_device(struct dvb_device *dvbdev)
{
dvb_remove_device(dvbdev);
- dvb_free_device(dvbdev);
+ dvb_device_put(dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
-
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
@@ -625,9 +671,9 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
struct media_entity *demux = NULL, *ca = NULL;
struct media_link *link;
struct media_interface *intf;
- unsigned demux_pad = 0;
- unsigned dvr_pad = 0;
- unsigned ntuner = 0, ndemod = 0;
+ unsigned int demux_pad = 0;
+ unsigned int dvr_pad = 0;
+ unsigned int ntuner = 0, ndemod = 0;
int ret, pad_source, pad_sink;
static const char *connector_name = "Television";
@@ -697,7 +743,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
MEDIA_LNK_FL_ENABLED,
false);
} else {
- pad_sink = media_get_pad_index(tuner, true,
+ pad_sink = media_get_pad_index(tuner, MEDIA_PAD_FL_SINK,
PAD_SIGNAL_ANALOG);
if (pad_sink < 0)
return -EINVAL;
@@ -715,7 +761,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
if (ntuner && ndemod) {
/* NOTE: first found tuner source pad presumed correct */
- pad_source = media_get_pad_index(tuner, false,
+ pad_source = media_get_pad_index(tuner, MEDIA_PAD_FL_SOURCE,
PAD_SIGNAL_ANALOG);
if (pad_source < 0)
return -EINVAL;
@@ -751,18 +797,18 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
media_device_for_each_entity(entity, mdev) {
if (entity->function == MEDIA_ENT_F_IO_DTV) {
if (!strncmp(entity->name, DVR_TSOUT,
- strlen(DVR_TSOUT))) {
+ strlen(DVR_TSOUT))) {
ret = media_create_pad_link(demux,
- ++dvr_pad,
- entity, 0, 0);
+ ++dvr_pad,
+ entity, 0, 0);
if (ret)
return ret;
}
if (!strncmp(entity->name, DEMUX_TSOUT,
- strlen(DEMUX_TSOUT))) {
+ strlen(DEMUX_TSOUT))) {
ret = media_create_pad_link(demux,
- ++demux_pad,
- entity, 0, 0);
+ ++demux_pad,
+ entity, 0, 0);
if (ret)
return ret;
}
@@ -820,8 +866,10 @@ EXPORT_SYMBOL_GPL(dvb_create_media_graph);
static int dvbdev_check_free_adapter_num(int num)
{
struct list_head *entry;
+
list_for_each(entry, &dvb_adapter_list) {
struct dvb_adapter *adap;
+
adap = list_entry(entry, struct dvb_adapter, list_head);
if (adap->num == num)
return 0;
@@ -829,7 +877,7 @@ static int dvbdev_check_free_adapter_num(int num)
return 1;
}
-static int dvbdev_get_free_adapter_num (void)
+static int dvbdev_get_free_adapter_num(void)
{
int num = 0;
@@ -842,7 +890,6 @@ static int dvbdev_get_free_adapter_num (void)
return -ENFILE;
}
-
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
struct module *module, struct device *device,
short *adapter_nums)
@@ -869,8 +916,8 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
return -ENFILE;
}
- memset (adap, 0, sizeof(struct dvb_adapter));
- INIT_LIST_HEAD (&adap->device_list);
+ memset(adap, 0, sizeof(struct dvb_adapter));
+ INIT_LIST_HEAD(&adap->device_list);
pr_info("DVB: registering new adapter (%s)\n", name);
@@ -880,13 +927,13 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
adap->device = device;
adap->mfe_shared = 0;
adap->mfe_dvbdev = NULL;
- mutex_init (&adap->mfe_lock);
+ mutex_init(&adap->mfe_lock);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
mutex_init(&adap->mdev_lock);
#endif
- list_add_tail (&adap->list_head, &dvb_adapter_list);
+ list_add_tail(&adap->list_head, &dvb_adapter_list);
mutex_unlock(&dvbdev_register_lock);
@@ -894,27 +941,28 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
}
EXPORT_SYMBOL(dvb_register_adapter);
-
int dvb_unregister_adapter(struct dvb_adapter *adap)
{
mutex_lock(&dvbdev_register_lock);
- list_del (&adap->list_head);
+ list_del(&adap->list_head);
mutex_unlock(&dvbdev_register_lock);
return 0;
}
EXPORT_SYMBOL(dvb_unregister_adapter);
-/* if the miracle happens and "generic_usercopy()" is included into
- the kernel, then this can vanish. please don't make the mistake and
- define this as video_usercopy(). this will introduce a dependency
- to the v4l "videodev.o" module, which is unnecessary for some
- cards (ie. the budget dvb-cards don't need the v4l module...) */
+/*
+ * if the miracle happens and "generic_usercopy()" is included into
+ * the kernel, then this can vanish. please don't make the mistake and
+ * define this as video_usercopy(). this will introduce a dependency
+ * to the v4l "videodev.o" module, which is unnecessary for some
+ * cards (ie. the budget dvb-cards don't need the v4l module...)
+ */
int dvb_usercopy(struct file *file,
- unsigned int cmd, unsigned long arg,
- int (*func)(struct file *file,
- unsigned int cmd, void *arg))
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file,
+ unsigned int cmd, void *arg))
{
- char sbuf[128];
+ char sbuf[128] = {};
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
@@ -926,7 +974,7 @@ int dvb_usercopy(struct file *file,
* For this command, the pointer is actually an integer
* argument.
*/
- parg = (void *) arg;
+ parg = (void *)arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
@@ -936,7 +984,7 @@ int dvb_usercopy(struct file *file,
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
- if (NULL == mbuf)
+ if (!mbuf)
return -ENOMEM;
parg = mbuf;
}
@@ -948,15 +996,15 @@ int dvb_usercopy(struct file *file,
}
/* call driver */
- if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
+ err = func(file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
err = -ENOTTY;
if (err < 0)
goto out;
/* Copy results into user buffer */
- switch (_IOC_DIR(cmd))
- {
+ switch (_IOC_DIR(cmd)) {
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
@@ -1018,9 +1066,9 @@ void dvb_module_release(struct i2c_client *client)
EXPORT_SYMBOL_GPL(dvb_module_release);
#endif
-static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int dvb_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct dvb_device *dvbdev = dev_get_drvdata(dev);
+ const struct dvb_device *dvbdev = dev_get_drvdata(dev);
add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
@@ -1028,32 +1076,33 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-static char *dvb_devnode(struct device *dev, umode_t *mode)
+static char *dvb_devnode(const struct device *dev, umode_t *mode)
{
- struct dvb_device *dvbdev = dev_get_drvdata(dev);
+ const struct dvb_device *dvbdev = dev_get_drvdata(dev);
return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
}
-
static int __init init_dvbdev(void)
{
int retval;
dev_t dev = MKDEV(DVB_MAJOR, 0);
- if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
+ retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB");
+ if (retval != 0) {
pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
- if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
+ retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS);
+ if (retval != 0) {
pr_err("dvb-core: unable register character device\n");
goto error;
}
- dvb_class = class_create(THIS_MODULE, "dvb");
+ dvb_class = class_create("dvb");
if (IS_ERR(dvb_class)) {
retval = PTR_ERR(dvb_class);
goto error;
@@ -1068,12 +1117,19 @@ error:
return retval;
}
-
static void __exit exit_dvbdev(void)
{
+ struct dvbdevfops_node *node, *next;
+
class_destroy(dvb_class);
cdev_del(&dvb_device_cdev);
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
+
+ list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) {
+ list_del(&node->list_head);
+ kfree(node->fops);
+ kfree(node);
+ }
}
subsys_initcall(init_dvbdev);