mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 04:06:26 +00:00
media fixes for v6.4-rc3
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmRl3pAACgkQCF8+vY7k 4RUbcxAAheVgBw4kH0zY8vI8DUF9tZ/vPO6Nssp0CUVkchlgM2R0mPpKs/egGZfW XJV+HFr3DvwOsSuAoEGtQbYixGJpsZLnRGDl4nc8mTyiR6JHkrKPcyWSqGxtVI/7 LO436/PdMbgG76fSvJ0YkawYkO2FioMECDGI93Gf27dsV5GXWdk8KPueBqPS+cQo fO5zKAPSp1K+ejrLR92vU5j4d2OFHzx1+ESGt3MDGplu/1szTs+J2qvZThgiF130 TXYMLo7vjfgRlmyCWh9WH6u7bGbLd7I6ZI5z2W/ypgCBErDJW5Qy1PkyDB9LC6PO MG2tGorpmeQXB0t1D46GbJ1EzSzy3Bep5yo9sSf2/s+aEZ+W+F0XEAqGKdklnhHY ftjIWbwjIDvkKIVFaWfYed1lhFOUn4owSHk8VmyeB04TUSpJxD7nyPmfi7ZxmDh6 HzR2NYh4ka8SN2gZu1w6ZL8Hg8xPOyBVh/ZF/1TYgzJP5836NLRqjdUE0biCGyJa /Fxo1t6uQNa4wdQ3F1P2MisLW1vaW/uNEgpMTlxNGODRnxEf1VFiYnzvYFkI6dB6 zW/4/xhX2282JSlFiQo1+RIHWMXz4JtzgkiVbdJAHMF2wLj9/VX+YvUu/UEEUNs9 Q/dg00Q+w5aa9Dk6ziRNaVTG7lSuHGy+0WsfFtV8EJgFwWzdfZ8= =Z//n -----END PGP SIGNATURE----- Merge tag 'media/v6.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media fixes from Mauro Carvalho Chehab: "Several fixes for the dvb core and drivers: - fix UAF and null pointer de-reference in DVB core - fix kernel runtime warning for blocking operation in wait_event*() in dvb core - fix write size bug in DVB conditional access core - fix dvb demux continuity counter debug check logic - randconfig build fixes in pvrusb2 and mn88443x - fix memory leak in ttusb-dec - fix netup_unidvb probe-time error check logic - improve error handling in dw2102 if it can't retrieve DVB MAC address" * tag 'media/v6.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221 media: dvb-core: Fix kernel WARNING for blocking operation in wait_event*() media: dvb-core: Fix use-after-free due to race at dvb_register_device() media: dvb-core: Fix use-after-free due on race condition at dvb_net media: dvb-core: Fix use-after-free on race condition at dvb_frontend media: mn88443x: fix !CONFIG_OF error by drop of_match_ptr from ID table media: ttusb-dec: fix memory leak in ttusb_dec_exit_dvb() media: dvb_ca_en50221: fix a size write bug media: netup_unidvb: fix irq init by register it at the end of probe media: dvb-usb: dw2102: fix uninit-value in su3000_read_mac_address media: dvb-usb: digitv: fix null-ptr-deref in digitv_i2c_xfer() media: dvb-usb-v2: rtl28xxu: fix null-ptr-deref in rtl28xxu_i2c_xfer media: dvb-usb-v2: ce6230: fix null-ptr-deref in ce6230_i2c_master_xfer() media: dvb-usb-v2: ec168: fix null-ptr-deref in ec168_i2c_xfer() media: dvb-usb: az6027: fix three null-ptr-deref in az6027_i2c_xfer() media: netup_unidvb: fix use-after-free at del_timer() media: dvb_demux: fix a bug for the continuity counter media: pvrusb2: fix DVB_CORE dependency
This commit is contained in:
commit
b802651bb6
@ -151,6 +151,12 @@ 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)
|
||||
@ -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 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
|
||||
* @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 writen 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);
|
||||
|
||||
|
@ -115,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;
|
||||
@ -300,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 */
|
||||
@ -336,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 */
|
||||
|
@ -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;
|
||||
}
|
||||
@ -809,15 +817,26 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
mutex_lock(&fe->remove_mutex);
|
||||
|
||||
if (fe->exit != DVB_FE_DEVICE_REMOVED)
|
||||
fe->exit = DVB_FE_NORMAL_EXIT;
|
||||
mb();
|
||||
|
||||
if (!fepriv->thread)
|
||||
if (!fepriv->thread) {
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
kthread_stop(fepriv->thread);
|
||||
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
|
||||
if (fepriv->dvbdev->users < -1) {
|
||||
wait_event(fepriv->dvbdev->wait_queue,
|
||||
fepriv->dvbdev->users == -1);
|
||||
}
|
||||
|
||||
sema_init(&fepriv->sem, 1);
|
||||
fepriv->state = FESTATE_IDLE;
|
||||
|
||||
@ -2761,9 +2780,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
struct dvb_adapter *adapter = fe->dvb;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&fe->remove_mutex);
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
if (fe->exit == DVB_FE_DEVICE_REMOVED)
|
||||
return -ENODEV;
|
||||
if (fe->exit == DVB_FE_DEVICE_REMOVED) {
|
||||
ret = -ENODEV;
|
||||
goto err_remove_mutex;
|
||||
}
|
||||
|
||||
if (adapter->mfe_shared == 2) {
|
||||
mutex_lock(&adapter->mfe_lock);
|
||||
@ -2771,7 +2794,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
if (adapter->mfe_dvbdev &&
|
||||
!adapter->mfe_dvbdev->writers) {
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto err_remove_mutex;
|
||||
}
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
@ -2794,8 +2818,10 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
while (mferetry-- && (mfedev->users != -1 ||
|
||||
mfepriv->thread)) {
|
||||
if (msleep_interruptible(500)) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
if (signal_pending(current)) {
|
||||
ret = -EINTR;
|
||||
goto err_remove_mutex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2807,7 +2833,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
if (mfedev->users != -1 ||
|
||||
mfepriv->thread) {
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto err_remove_mutex;
|
||||
}
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
@ -2866,6 +2893,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
return ret;
|
||||
|
||||
err3:
|
||||
@ -2887,6 +2916,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
err0:
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
|
||||
err_remove_mutex:
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2897,6 +2929,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&fe->remove_mutex);
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
|
||||
@ -2918,10 +2952,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
|
||||
}
|
||||
mutex_unlock(&fe->dvb->mdev_lock);
|
||||
#endif
|
||||
if (fe->exit != DVB_FE_NO_EXIT)
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
if (fe->ops.ts_bus_ctrl)
|
||||
fe->ops.ts_bus_ctrl(fe, 0);
|
||||
|
||||
if (fe->exit != DVB_FE_NO_EXIT) {
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
wake_up(&dvbdev->wait_queue);
|
||||
} else {
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
}
|
||||
|
||||
} else {
|
||||
mutex_unlock(&fe->remove_mutex);
|
||||
}
|
||||
|
||||
dvb_frontend_put(fe);
|
||||
@ -3022,6 +3064,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
|
||||
fepriv = fe->frontend_priv;
|
||||
|
||||
kref_init(&fe->refcount);
|
||||
mutex_init(&fe->remove_mutex);
|
||||
|
||||
/*
|
||||
* After initialization, there need to be two references: one
|
||||
|
@ -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++)
|
||||
|
@ -27,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);
|
||||
@ -453,14 +454,15 @@ 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){
|
||||
if ((id = dvbdev_get_free_id (adap, type)) < 0) {
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
*pdvbdev = NULL;
|
||||
pr_err("%s: couldn't find free device id\n", __func__);
|
||||
@ -468,18 +470,45 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
}
|
||||
|
||||
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
|
||||
|
||||
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 == NULL) {
|
||||
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
|
||||
if (!dvbdevfops) {
|
||||
kfree(dvbdev);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
new_node = kzalloc(sizeof(struct dvbdevfops_node), GFP_KERNEL);
|
||||
if (!new_node) {
|
||||
kfree(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
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));
|
||||
@ -490,20 +519,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
dvbdev->priv = priv;
|
||||
dvbdev->fops = dvbdevfops;
|
||||
init_waitqueue_head (&dvbdev->wait_queue);
|
||||
|
||||
dvbdevfops->owner = adap->module;
|
||||
|
||||
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)
|
||||
break;
|
||||
|
||||
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(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
up_write(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
@ -512,41 +541,47 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
#else
|
||||
minor = nums2minor(adap->num, type, id);
|
||||
#endif
|
||||
|
||||
dvbdev->minor = minor;
|
||||
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__);
|
||||
|
||||
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);
|
||||
kfree(dvbdev);
|
||||
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));
|
||||
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);
|
||||
kfree(dvbdev);
|
||||
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);
|
||||
@ -575,7 +610,6 @@ static void dvb_free_device(struct kref *ref)
|
||||
{
|
||||
struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
|
||||
|
||||
kfree (dvbdev->fops);
|
||||
kfree (dvbdev);
|
||||
}
|
||||
|
||||
@ -1081,9 +1115,17 @@ static int __init init_dvbdev(void)
|
||||
|
||||
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);
|
||||
|
@ -798,7 +798,7 @@ MODULE_DEVICE_TABLE(i2c, mn88443x_i2c_id);
|
||||
static struct i2c_driver mn88443x_driver = {
|
||||
.driver = {
|
||||
.name = "mn88443x",
|
||||
.of_match_table = of_match_ptr(mn88443x_of_match),
|
||||
.of_match_table = mn88443x_of_match,
|
||||
},
|
||||
.probe_new = mn88443x_probe,
|
||||
.remove = mn88443x_remove,
|
||||
|
@ -697,7 +697,7 @@ static void netup_unidvb_dma_fini(struct netup_unidvb_dev *ndev, int num)
|
||||
netup_unidvb_dma_enable(dma, 0);
|
||||
msleep(50);
|
||||
cancel_work_sync(&dma->work);
|
||||
del_timer(&dma->timeout);
|
||||
del_timer_sync(&dma->timeout);
|
||||
}
|
||||
|
||||
static int netup_unidvb_dma_setup(struct netup_unidvb_dev *ndev)
|
||||
@ -887,12 +887,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
|
||||
ndev->lmmio0, (u32)pci_resource_len(pci_dev, 0),
|
||||
ndev->lmmio1, (u32)pci_resource_len(pci_dev, 1),
|
||||
pci_dev->irq);
|
||||
if (request_irq(pci_dev->irq, netup_unidvb_isr, IRQF_SHARED,
|
||||
"netup_unidvb", pci_dev) < 0) {
|
||||
dev_err(&pci_dev->dev,
|
||||
"%s(): can't get IRQ %d\n", __func__, pci_dev->irq);
|
||||
goto irq_request_err;
|
||||
}
|
||||
|
||||
ndev->dma_size = 2 * 188 *
|
||||
NETUP_DMA_BLOCKS_COUNT * NETUP_DMA_PACKETS_COUNT;
|
||||
ndev->dma_virt = dma_alloc_coherent(&pci_dev->dev,
|
||||
@ -933,6 +928,14 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
|
||||
dev_err(&pci_dev->dev, "netup_unidvb: DMA setup failed\n");
|
||||
goto dma_setup_err;
|
||||
}
|
||||
|
||||
if (request_irq(pci_dev->irq, netup_unidvb_isr, IRQF_SHARED,
|
||||
"netup_unidvb", pci_dev) < 0) {
|
||||
dev_err(&pci_dev->dev,
|
||||
"%s(): can't get IRQ %d\n", __func__, pci_dev->irq);
|
||||
goto dma_setup_err;
|
||||
}
|
||||
|
||||
dev_info(&pci_dev->dev,
|
||||
"netup_unidvb: device has been initialized\n");
|
||||
return 0;
|
||||
@ -951,8 +954,6 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
|
||||
dma_free_coherent(&pci_dev->dev, ndev->dma_size,
|
||||
ndev->dma_virt, ndev->dma_phys);
|
||||
dma_alloc_err:
|
||||
free_irq(pci_dev->irq, pci_dev);
|
||||
irq_request_err:
|
||||
iounmap(ndev->lmmio1);
|
||||
pci_bar1_error:
|
||||
iounmap(ndev->lmmio0);
|
||||
|
@ -101,6 +101,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (msg[i].addr ==
|
||||
ce6230_zl10353_config.demod_address) {
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
req.cmd = DEMOD_READ;
|
||||
req.value = msg[i].addr >> 1;
|
||||
req.index = msg[i].buf[0];
|
||||
@ -117,6 +121,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
} else {
|
||||
if (msg[i].addr ==
|
||||
ce6230_zl10353_config.demod_address) {
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
req.cmd = DEMOD_WRITE;
|
||||
req.value = msg[i].addr >> 1;
|
||||
req.index = msg[i].buf[0];
|
||||
|
@ -115,6 +115,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
while (i < num) {
|
||||
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (msg[i].addr == ec168_ec100_config.demod_address) {
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
req.cmd = READ_DEMOD;
|
||||
req.value = 0;
|
||||
req.index = 0xff00 + msg[i].buf[0]; /* reg */
|
||||
@ -131,6 +135,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
}
|
||||
} else {
|
||||
if (msg[i].addr == ec168_ec100_config.demod_address) {
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
req.cmd = WRITE_DEMOD;
|
||||
req.value = msg[i].buf[1]; /* val */
|
||||
req.index = 0xff00 + msg[i].buf[0]; /* reg */
|
||||
@ -139,6 +147,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 1;
|
||||
} else {
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
req.cmd = WRITE_I2C;
|
||||
req.value = msg[i].buf[0]; /* val */
|
||||
req.index = 0x0100 + msg[i].addr; /* I2C addr */
|
||||
|
@ -176,6 +176,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
} else if (msg[0].addr == 0x10) {
|
||||
if (msg[0].len < 1 || msg[1].len < 1) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
}
|
||||
/* method 1 - integrated demod */
|
||||
if (msg[0].buf[0] == 0x00) {
|
||||
/* return demod page from driver cache */
|
||||
@ -189,6 +193,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
ret = rtl28xxu_ctrl_msg(d, &req);
|
||||
}
|
||||
} else if (msg[0].len < 2) {
|
||||
if (msg[0].len < 1) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
}
|
||||
/* method 2 - old I2C */
|
||||
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
|
||||
req.index = CMD_I2C_RD;
|
||||
@ -217,8 +225,16 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
} else if (msg[0].addr == 0x10) {
|
||||
if (msg[0].len < 1) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
}
|
||||
/* method 1 - integrated demod */
|
||||
if (msg[0].buf[0] == 0x00) {
|
||||
if (msg[0].len < 2) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
}
|
||||
/* save demod page for later demod access */
|
||||
dev->page = msg[0].buf[1];
|
||||
ret = 0;
|
||||
@ -231,6 +247,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
ret = rtl28xxu_ctrl_msg(d, &req);
|
||||
}
|
||||
} else if ((msg[0].len < 23) && (!dev->new_i2c_write)) {
|
||||
if (msg[0].len < 1) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_mutex_unlock;
|
||||
}
|
||||
/* method 2 - old I2C */
|
||||
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
|
||||
req.index = CMD_I2C_WR;
|
||||
|
@ -988,6 +988,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
|
||||
/* write/read request */
|
||||
if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
|
||||
req = 0xB9;
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
|
||||
value = msg[i].addr + (msg[i].len << 8);
|
||||
length = msg[i + 1].len + 6;
|
||||
@ -1001,6 +1005,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
|
||||
|
||||
/* demod 16bit addr */
|
||||
req = 0xBD;
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
|
||||
value = msg[i].addr + (2 << 8);
|
||||
length = msg[i].len - 2;
|
||||
@ -1026,6 +1034,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
|
||||
} else {
|
||||
|
||||
req = 0xBD;
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
index = msg[i].buf[0] & 0x00FF;
|
||||
value = msg[i].addr + (1 << 8);
|
||||
length = msg[i].len - 1;
|
||||
|
@ -63,6 +63,10 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
|
||||
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (msg[i].len < 1) {
|
||||
i = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
|
||||
|
@ -946,7 +946,7 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
||||
for (i = 0; i < 6; i++) {
|
||||
obuf[1] = 0xf0 + i;
|
||||
if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
|
||||
break;
|
||||
return -1;
|
||||
else
|
||||
mac[i] = ibuf[0];
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ config VIDEO_PVRUSB2_DVB
|
||||
bool "pvrusb2 ATSC/DVB support"
|
||||
default y
|
||||
depends on VIDEO_PVRUSB2 && DVB_CORE
|
||||
depends on VIDEO_PVRUSB2=m || DVB_CORE=y
|
||||
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
|
||||
|
@ -1544,8 +1544,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
|
||||
dvb_dmx_release(&dec->demux);
|
||||
if (dec->fe) {
|
||||
dvb_unregister_frontend(dec->fe);
|
||||
if (dec->fe->ops.release)
|
||||
dec->fe->ops.release(dec->fe);
|
||||
dvb_frontend_detach(dec->fe);
|
||||
}
|
||||
dvb_unregister_adapter(&dec->adapter);
|
||||
}
|
||||
|
@ -686,7 +686,10 @@ struct dtv_frontend_properties {
|
||||
* @id: Frontend ID
|
||||
* @exit: Used to inform the DVB core that the frontend
|
||||
* thread should exit (usually, means that the hardware
|
||||
* got disconnected.
|
||||
* got disconnected).
|
||||
* @remove_mutex: mutex that avoids a race condition between a callback
|
||||
* called when the hardware is disconnected and the
|
||||
* file_operations of dvb_frontend.
|
||||
*/
|
||||
|
||||
struct dvb_frontend {
|
||||
@ -704,6 +707,7 @@ struct dvb_frontend {
|
||||
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
|
||||
int id;
|
||||
unsigned int exit;
|
||||
struct mutex remove_mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -39,6 +39,9 @@ struct net_device;
|
||||
* @exit: flag to indicate when the device is being removed.
|
||||
* @demux: pointer to &struct dmx_demux.
|
||||
* @ioctl_mutex: protect access to this struct.
|
||||
* @remove_mutex: mutex that avoids a race condition between a callback
|
||||
* called when the hardware is disconnected and the
|
||||
* file_operations of dvb_net.
|
||||
*
|
||||
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
|
||||
* devices.
|
||||
@ -51,6 +54,7 @@ struct dvb_net {
|
||||
unsigned int exit:1;
|
||||
struct dmx_demux *demux;
|
||||
struct mutex ioctl_mutex;
|
||||
struct mutex remove_mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -193,6 +193,21 @@ struct dvb_device {
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvbdevfops_node - fops nodes registered in dvbdevfops_list
|
||||
*
|
||||
* @fops: Dynamically allocated fops for ->owner registration
|
||||
* @type: type of dvb_device
|
||||
* @template: dvb_device used for registration
|
||||
* @list_head: list_head for dvbdevfops_list
|
||||
*/
|
||||
struct dvbdevfops_node {
|
||||
struct file_operations *fops;
|
||||
enum dvb_device_type type;
|
||||
const struct dvb_device *template;
|
||||
struct list_head list_head;
|
||||
};
|
||||
|
||||
/**
|
||||
* dvb_device_get - Increase dvb_device reference
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user