diff --git a/dvb-core/dmxdev.c b/dvb-core/dmxdev.c index 36a2fe2..a3e5d6f 100644 --- a/dvb-core/dmxdev.c +++ b/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 @@ -369,23 +359,23 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) static void dvb_dmxdev_filter_timeout(struct timer_list *t) { - struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer); - - dmxdevfilter->buffer.error = -ETIMEDOUT; - spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; - spin_unlock_irq(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); + struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer); + + dmxdevfilter->buffer.error = -ETIMEDOUT; + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; + spin_unlock_irq(&dmxdevfilter->dev->lock); + wake_up(&dmxdevfilter->buffer.queue); } static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) { struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; - + del_timer(&dmxdevfilter->timer); if (para->timeout) { - dmxdevfilter->timer.expires = - jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; + dmxdevfilter->timer.expires = + jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; add_timer(&dmxdevfilter->timer); } } @@ -404,7 +394,7 @@ static void dvb_dmxdev_filter_timeout(unsigned long data) static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) { struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; - + del_timer(&dmxdevfilter->timer); if (para->timeout) { dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; @@ -415,6 +405,7 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) } } #endif + static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, struct dmx_section_filter *filter, @@ -475,14 +466,14 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed, - u32 *buffer_flags) + struct dmx_ts_feed *feed, + u32 *buffer_flags) { struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; #ifdef CONFIG_DVB_MMAP struct dvb_vb2_ctx *ctx; #endif - struct dvb_ringbuffer *buffer; int ret; spin_lock(&dmxdevfilter->dev->lock); @@ -849,6 +840,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; @@ -1485,7 +1481,7 @@ 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; @@ -1508,21 +1504,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/dvb-core/dvb_ca_en50221.c b/dvb-core/dvb_ca_en50221.c index ed59c5a..208c9ef 100644 --- a/dvb-core/dvb_ca_en50221.c +++ b/dvb-core/dvb_ca_en50221.c @@ -1,4 +1,4 @@ - // SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces * @@ -164,7 +164,7 @@ 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); diff --git a/dvb-core/dvb_demux.c b/dvb-core/dvb_demux.c index 44c5fd2..dd29a59 100644 --- a/dvb-core/dvb_demux.c +++ b/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 * & 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) "dvb_demux: " fmt @@ -256,7 +246,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; @@ -285,7 +275,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) @@ -489,8 +479,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", - pid, demux->cnt_storage[pid], - buf[3] & 0xf); + pid, demux->cnt_storage[pid], + buf[3] & 0xf); demux->cnt_storage[pid] = buf[3] & 0xf; } } diff --git a/dvb-core/dvb_frontend.c b/dvb-core/dvb_frontend.c index 01193b3..bee785a 100644 --- a/dvb-core/dvb_frontend.c +++ b/dvb-core/dvb_frontend.c @@ -141,7 +141,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); @@ -924,6 +924,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: @@ -949,6 +950,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: @@ -980,6 +982,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: @@ -1047,6 +1050,10 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) c->input = NO_INPUT; switch (c->delivery_system) { + case SYS_DSS: + c->modulation = QPSK; + c->rolloff = ROLLOFF_20; + break; case SYS_DVBS: case SYS_DVBS2: case SYS_TURBO: @@ -1839,6 +1846,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: @@ -2312,6 +2320,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: @@ -2582,8 +2593,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; } @@ -2591,9 +2601,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; } @@ -2601,9 +2610,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; } @@ -2767,7 +2775,6 @@ typedef unsigned int __poll_t; #define EPOLLOUT POLLOUT #endif - static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) { struct dvb_device *dvbdev = file->private_data; @@ -2796,7 +2803,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) @@ -2974,7 +2991,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; @@ -2990,7 +3009,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) @@ -3024,6 +3045,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, .name = fe->ops.info.name, #endif }; + int ret; dev_dbg(dvb->device, "%s:\n", __func__); @@ -3053,8 +3075,14 @@ int dvb_register_frontend(struct dvb_adapter *dvb, fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; - dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, - fe, DVB_DEVICE_FRONTEND, 0); + 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; + } dev_info(fe->dvb->device, "DVB: registering adapter %i frontend %i (%s)...\n", diff --git a/dvb-core/dvb_net.c b/dvb-core/dvb_net.c index 05cc5c1..0dd739e 100644 --- a/dvb-core/dvb_net.c +++ b/dvb-core/dvb_net.c @@ -60,6 +60,9 @@ #include #include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) +#include +#endif static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) { @@ -661,8 +664,8 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, h->ts_remain, h->ts_remain > 2 ? *(unsigned short *)h->from_where : 0); - - #ifdef DVB_ULE_DEBUG + +#ifdef DVB_ULE_DEBUG hexdump(iov[0].iov_base, iov[0].iov_len); hexdump(iov[1].iov_base, iov[1].iov_len); hexdump(iov[2].iov_base, iov[2].iov_len); @@ -678,8 +681,8 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, hexdump(ule_where - TS_SZ, TS_SZ); } ule_dump = 1; - #endif - +#endif + h->dev->stats.rx_errors++; h->dev->stats.rx_crc_errors++; dev_kfree_skb(h->priv->ule_skb); @@ -1062,7 +1065,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; - const 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); @@ -1483,14 +1486,21 @@ static int dvb_net_do_ioctl(struct file *file, struct net_device *netdev; struct dvb_net_priv *priv_data; struct dvb_net_if *dvbnetif = parg; + int if_num = dvbnetif->if_num; - if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || - !dvbnet->state[dvbnetif->if_num]) { + if (if_num >= DVB_NET_DEVICES_MAX) { + ret = -EINVAL; + goto ioctl_error; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) + if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX); +#endif + if (!dvbnet->state[if_num]) { ret = -EINVAL; goto ioctl_error; } - netdev = dvbnet->device[dvbnetif->if_num]; + netdev = dvbnet->device[if_num]; priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; @@ -1543,14 +1553,21 @@ static int dvb_net_do_ioctl(struct file *file, struct net_device *netdev; struct dvb_net_priv *priv_data; struct __dvb_net_if_old *dvbnetif = parg; + int if_num = dvbnetif->if_num; - if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || - !dvbnet->state[dvbnetif->if_num]) { + if (if_num >= DVB_NET_DEVICES_MAX) { + ret = -EINVAL; + goto ioctl_error; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) + if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX); +#endif + if (!dvbnet->state[if_num]) { ret = -EINVAL; goto ioctl_error; } - netdev = dvbnet->device[dvbnetif->if_num]; + netdev = dvbnet->device[if_num]; priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; diff --git a/dvb-core/dvb_ringbuffer.c b/dvb-core/dvb_ringbuffer.c index 60830ef..ac3721e 100644 --- a/dvb-core/dvb_ringbuffer.c +++ b/dvb-core/dvb_ringbuffer.c @@ -63,7 +63,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) * this pairs with smp_store_release() in dvb_ringbuffer_write(), * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() * - * for memory barriers also see Documentation/core-api/circular-buffers.txt + * for memory barriers also see Documentation/core-api/circular-buffers.rst */ return (rbuf->pread == smp_load_acquire(&rbuf->pwrite)); #endif @@ -75,7 +75,7 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf) { ssize_t free; - /* ACCESS_ONCE() to load read pointer on writer side + /* READ_ONCE() to load read pointer on writer side * this pairs with smp_store_release() in dvb_ringbuffer_read(), * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(), * or dvb_ringbuffer_reset() @@ -171,7 +171,7 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si #else /* smp_store_release() for read pointer update to ensure * that buf is not overwritten until read is complete, - * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free() + * this pairs with READ_ONCE() in dvb_ringbuffer_free() */ smp_store_release(&rbuf->pread, 0); #endif @@ -203,7 +203,7 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) #else /* smp_store_release() for read pointer update to ensure * that buf is not overwritten until read is complete, - * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free() + * this pairs with READ_ONCE() in dvb_ringbuffer_free() */ smp_store_release(&rbuf->pread, 0); #endif @@ -391,7 +391,7 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; } - consumed = idx - rbuf->pread; + consumed = (idx - rbuf->pread); if (consumed < 0) consumed += rbuf->size; diff --git a/dvb-core/dvb_vb2.c b/dvb-core/dvb_vb2.c index 959d110..909df82 100644 --- a/dvb-core/dvb_vb2.c +++ b/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 @@ -358,6 +354,12 @@ 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) { + struct vb2_queue *q = &ctx->vb_q; + + if (b->index >= q->num_buffers) { + dprintk(1, "[%s] buffer index out of range\n", ctx->name); + return -EINVAL; + } vb2_core_querybuf(&ctx->vb_q, b->index, b); dprintk(3, "[%s] index=%d\n", ctx->name, b->index); return 0; @@ -382,8 +384,13 @@ 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; int ret; + if (b->index >= q->num_buffers) { + dprintk(1, "[%s] buffer index out of range\n", ctx->name); + return -EINVAL; + } ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL); if (ret) { dprintk(1, "[%s] index=%d errno=%d\n", ctx->name, diff --git a/dvb-core/dvbdev.c b/dvb-core/dvbdev.c index e26fee3..ad1cd41 100644 --- a/dvb-core/dvbdev.c +++ b/dvb-core/dvbdev.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * dvbdev.c * * 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) "dvbdev: " fmt @@ -118,7 +108,7 @@ 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); @@ -182,6 +172,9 @@ int dvb_generic_release(struct inode *inode, struct file *file) } dvbdev->users++; + + dvb_device_put(dvbdev); + return 0; } EXPORT_SYMBOL(dvb_generic_release); @@ -264,7 +257,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev) static int dvb_create_tsout_entity(struct dvb_device *dvbdev, const char *name, int npads) { - int i, ret = 0; + int i; dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads), GFP_KERNEL); @@ -281,6 +274,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) @@ -353,6 +347,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, GFP_KERNEL); if (!dvbdev->pads) { kfree(dvbdev->entity); + dvbdev->entity = NULL; return -ENOMEM; } } @@ -499,6 +494,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } memcpy(dvbdev, template, sizeof(struct dvb_device)); + kref_init(&dvbdev->ref); dvbdev->type = type; dvbdev->id = id; dvbdev->adapter = adap; @@ -529,7 +525,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, #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); @@ -574,6 +570,7 @@ 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); @@ -585,21 +582,34 @@ void dvb_remove_device(struct dvb_device *dvbdev) 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); } -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); @@ -1041,9 +1051,13 @@ EXPORT_SYMBOL_GPL(dvb_module_release); #endif #endif +#if (KERNEL_VERSION(6, 2, 0) > LINUX_VERSION_CODE) static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) +#else +static int dvb_uevent(const struct device *dev, struct kobj_uevent_env *env) +#endif { - 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]); @@ -1051,9 +1065,13 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +#if (KERNEL_VERSION(6, 2, 0) > LINUX_VERSION_CODE) static char *dvb_devnode(struct device *dev, umode_t *mode) +#else +static char *dvb_devnode(const struct device *dev, umode_t *mode) +#endif { - 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); diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index a9ddc50..9ddfe4b 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -280,7 +280,28 @@ enum fe_spectral_inversion { * @FEC_3_5: Forward Error Correction Code 3/5 * @FEC_9_10: Forward Error Correction Code 9/10 * @FEC_2_5: Forward Error Correction Code 2/5 - * + * @FEC_1_3: Forward Error Correction Code 1/3 + * @FEC_1_4: Forward Error Correction Code 1/4 + * @FEC_5_9: Forward Error Correction Code 5/9 + * @FEC_7_9: Forward Error Correction Code 7/9 + * @FEC_8_15: Forward Error Correction Code 8/15 + * @FEC_11_15: Forward Error Correction Code 11/15 + * @FEC_13_18: Forward Error Correction Code 13/18 + * @FEC_9_20: Forward Error Correction Code 9/20 + * @FEC_11_20: Forward Error Correction Code 11/20 + * @FEC_23_36: Forward Error Correction Code 23/36 + * @FEC_25_36: Forward Error Correction Code 25/36 + * @FEC_13_45: Forward Error Correction Code 13/45 + * @FEC_26_45: Forward Error Correction Code 26/45 + * @FEC_28_45: Forward Error Correction Code 28/45 + * @FEC_32_45: Forward Error Correction Code 32/45 + * @FEC_77_90: Forward Error Correction Code 77/90 + * @FEC_11_45: Forward Error Correction Code 11/45 + * @FEC_4_15: Forward Error Correction Code 4/15 + * @FEC_14_45: Forward Error Correction Code 14/45 + * @FEC_7_15: Forward Error Correction Code 7/15 + * @FEC_29_45: Forward Error Correction Code 29/45 + * @FEC_31_45: Forward Error Correction Code 31/45 * Please note that not all FEC types are supported by a given standard. */ enum fe_code_rate { @@ -297,8 +318,28 @@ enum fe_code_rate { FEC_3_5, FEC_9_10, FEC_2_5, - FEC_1_4, FEC_1_3, + FEC_1_4, + FEC_5_9, + FEC_7_9, + FEC_8_15, + FEC_11_15, + FEC_13_18, + FEC_9_20, + FEC_11_20, + FEC_23_36, + FEC_25_36, + FEC_13_45, + FEC_26_45, + FEC_28_45, + FEC_32_45, + FEC_77_90, + FEC_11_45, + FEC_4_15, + FEC_14_45, + FEC_7_15, + FEC_29_45, + FEC_31_45, }; /** @@ -317,6 +358,16 @@ enum fe_code_rate { * @APSK_32: 32-APSK modulation * @DQPSK: DQPSK modulation * @QAM_4_NR: 4-QAM-NR modulation + * @QAM_1024: 1024-QAM modulation + * @QAM_4096: 4096-QAM modulation + * @APSK_8_L: 8APSK-L modulation + * @APSK_16_L: 16APSK-L modulation + * @APSK_32_L: 32APSK-L modulation + * @APSK_64: 64APSK modulation + * @APSK_64_L: 64APSK-L modulation + * @APSK_128: 128APSK modulation + * @APSK_256: 256APSK modulation + * @APSK_256_L: 256APSK-L modulation * * Please note that not all modulations are supported by a given standard. * @@ -336,9 +387,16 @@ enum fe_modulation { APSK_32, DQPSK, QAM_4_NR, + QAM_1024, + QAM_4096, + APSK_8_L, + APSK_16_L, + APSK_32_L, APSK_64, + APSK_64_L, APSK_128, APSK_256, + APSK_256_L, }; /** @@ -393,6 +451,7 @@ enum fe_transmit_mode { * @GUARD_INTERVAL_PN420: PN length 420 (1/4) * @GUARD_INTERVAL_PN595: PN length 595 (1/6) * @GUARD_INTERVAL_PN945: PN length 945 (1/9) + * @GUARD_INTERVAL_1_64: Guard interval 1/64 * * Please note that not all guard intervals are supported by a given standard. */ @@ -408,6 +467,7 @@ enum fe_guard_interval { GUARD_INTERVAL_PN420, GUARD_INTERVAL_PN595, GUARD_INTERVAL_PN945, + GUARD_INTERVAL_1_64, }; /** @@ -561,6 +621,9 @@ enum fe_pilot { * @ROLLOFF_20: Roloff factor: α=20% * @ROLLOFF_25: Roloff factor: α=25% * @ROLLOFF_AUTO: Auto-detect the roloff factor. + * @ROLLOFF_15: Rolloff factor: α=15% + * @ROLLOFF_10: Rolloff factor: α=10% + * @ROLLOFF_5: Rolloff factor: α=5% * * .. note: * @@ -587,6 +650,8 @@ enum fe_rolloff { * Cable TV: DVB-C following ITU-T J.83 Annex B spec (ClearQAM) * @SYS_DVBC_ANNEX_C: * Cable TV: DVB-C following ITU-T J.83 Annex C spec + * @SYS_DVBC2: + * Cable TV: DVB-C2 * @SYS_ISDBC: * Cable TV: ISDB-C (no drivers yet) * @SYS_DVBT: @@ -604,7 +669,7 @@ enum fe_rolloff { * @SYS_DVBS: * Satellite TV: DVB-S * @SYS_DVBS2: - * Satellite TV: DVB-S2 + * Satellite TV: DVB-S2 and DVB-S2X * @SYS_TURBO: * Satellite TV: DVB-S Turbo * @SYS_ISDBS: @@ -714,7 +779,7 @@ enum atscmh_rs_frame_mode { }; /** - * enum atscmh_rs_code_mode + * enum atscmh_rs_code_mode - ATSC-M/H Reed Solomon modes * @ATSCMH_RSCODE_211_187: Reed Solomon code (211,187). * @ATSCMH_RSCODE_223_187: Reed Solomon code (223,187). * @ATSCMH_RSCODE_235_187: Reed Solomon code (235,187). @@ -755,8 +820,8 @@ enum fecap_scale_params { * struct dtv_stats - Used for reading a DTV status property * * @scale: - * Filled with enum fecap_scale_params - the scale in usage - * for that parameter + * Filled with enum fecap_scale_params - the scale in usage + * for that parameter * * @svalue: * integer value of the measure, for %FE_SCALE_DECIBEL, diff --git a/include/linux/media/dvb_frontend.h b/include/linux/media/dvb_frontend.h index 2132da2..3b28e8c 100644 --- a/include/linux/media/dvb_frontend.h +++ b/include/linux/media/dvb_frontend.h @@ -369,6 +369,10 @@ struct dvb_frontend_internal_info { * allocated by the driver. * @init: callback function used to initialize the tuner device. * @sleep: callback function used to put the tuner to sleep. + * @suspend: callback function used to inform that the Kernel will + * suspend. + * @resume: callback function used to inform that the Kernel is + * resuming from suspend. * @write: callback function used by some demod legacy drivers to * allow other drivers to write data into their registers. * Should not be used on new drivers. @@ -438,7 +442,6 @@ struct dvb_frontend_internal_info { * @analog_ops: pointer to &struct analog_demod_ops */ struct dvb_frontend_ops { - struct dvb_frontend_internal_info info; u8 delsys[MAX_DELSYS]; @@ -449,6 +452,8 @@ struct dvb_frontend_ops { int (*init)(struct dvb_frontend* fe); int (*sleep)(struct dvb_frontend* fe); + int (*suspend)(struct dvb_frontend *fe); + int (*resume)(struct dvb_frontend *fe); int (*write)(struct dvb_frontend* fe, const u8 buf[], int len); @@ -765,7 +770,8 @@ void dvb_frontend_detach(struct dvb_frontend *fe); * &dvb_frontend_ops.tuner_ops.suspend\(\) is available, it calls it. Otherwise, * it will call &dvb_frontend_ops.tuner_ops.sleep\(\), if available. * - * It will also call &dvb_frontend_ops.sleep\(\) to put the demod to suspend. + * It will also call &dvb_frontend_ops.suspend\(\) to put the demod to suspend, + * if available. Otherwise it will call &dvb_frontend_ops.sleep\(\). * * The drivers should also call dvb_frontend_suspend\(\) as part of their * handler for the &device_driver.suspend\(\). @@ -779,7 +785,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe); * * This function resumes the usual operation of the tuner after resume. * - * In order to resume the frontend, it calls the demod &dvb_frontend_ops.init\(\). + * In order to resume the frontend, it calls the demod + * &dvb_frontend_ops.resume\(\) if available. Otherwise it calls demod + * &dvb_frontend_ops.init\(\). * * If &dvb_frontend_ops.tuner_ops.resume\(\) is available, It, it calls it. * Otherwise,t will call &dvb_frontend_ops.tuner_ops.init\(\), if available. diff --git a/include/linux/media/dvb_ringbuffer.h b/include/linux/media/dvb_ringbuffer.h index 8ed6bcc..029c8b6 100644 --- a/include/linux/media/dvb_ringbuffer.h +++ b/include/linux/media/dvb_ringbuffer.h @@ -214,7 +214,7 @@ extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, * @buf: Buffer to write. * @len: Length of buffer (currently limited to 65535 bytes max). * - * Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. + * Return: Number of bytes written, or -EFAULT, -ENOMEM, -EINVAL. */ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len); diff --git a/include/linux/media/dvbdev.h b/include/linux/media/dvbdev.h index 26770cd..5765792 100644 --- a/include/linux/media/dvbdev.h +++ b/include/linux/media/dvbdev.h @@ -35,7 +35,7 @@ #endif #endif - #define DVB_MAX_ADAPTERS 64 +#define DVB_MAX_ADAPTERS 64 #define DVB_UNSET (-1) @@ -96,7 +96,11 @@ struct dvb_frontend; * @device: pointer to struct device * @module: pointer to struct module * @mfe_shared: indicates mutually exclusive frontends. - * Use of this flag is currently deprecated. + * 1 = legacy exclusion behavior: blocking any open() call + * 2 = enhanced exclusion behavior, emulating the standard + * behavior of busy frontends: allowing read-only sharing + * and otherwise returning immediately with -EBUSY when any + * of the frontends is already opened with write access. * @mfe_dvbdev: Frontend device in use, in the case of MFE * @mfe_lock: Lock to prevent using the other frontends when MFE is * used. @@ -135,6 +139,7 @@ struct dvb_adapter { * struct dvb_device - represents a DVB device node * * @list_head: List head with all DVB devices + * @ref: reference counter * @fops: pointer to struct file_operations * @adapter: pointer to the adapter that holds this device node * @type: type of the device, as defined by &enum dvb_device_type. @@ -165,6 +170,7 @@ struct dvb_adapter { */ struct dvb_device { struct list_head list_head; + struct kref ref; const struct file_operations *fops; struct dvb_adapter *adapter; enum dvb_device_type type; @@ -196,6 +202,20 @@ struct dvb_device { void *priv; }; +/** + * dvb_device_get - Increase dvb_device reference + * + * @dvbdev: pointer to struct dvb_device + */ +struct dvb_device *dvb_device_get(struct dvb_device *dvbdev); + +/** + * dvb_device_put - Decrease dvb_device reference + * + * @dvbdev: pointer to struct dvb_device + */ +void dvb_device_put(struct dvb_device *dvbdev); + /** * dvb_register_adapter - Registers a new DVB adapter * @@ -240,29 +260,16 @@ int dvb_register_device(struct dvb_adapter *adap, /** * dvb_remove_device - Remove a registered DVB device * - * This does not free memory. To do that, call dvb_free_device(). + * This does not free memory. dvb_free_device() will do that when + * reference counter is empty * * @dvbdev: pointer to struct dvb_device */ void dvb_remove_device(struct dvb_device *dvbdev); -/** - * dvb_free_device - Free memory occupied by a DVB device. - * - * Call dvb_unregister_device() before calling this function. - * - * @dvbdev: pointer to struct dvb_device - */ -void dvb_free_device(struct dvb_device *dvbdev); - /** * dvb_unregister_device - Unregisters a DVB device * - * This is a combination of dvb_remove_device() and dvb_free_device(). - * Using this function is usually a mistake, and is often an indicator - * for a use-after-free bug (when a userspace process keeps a file - * handle to a detached device). - * * @dvbdev: pointer to struct dvb_device */ void dvb_unregister_device(struct dvb_device *dvbdev);