提交 b802651b 编写于 作者: L Linus Torvalds

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
...@@ -151,6 +151,12 @@ struct dvb_ca_private { ...@@ -151,6 +151,12 @@ struct dvb_ca_private {
/* mutex serializing ioctls */ /* mutex serializing ioctls */
struct mutex ioctl_mutex; 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) 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); ...@@ -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, static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
u8 *ebuf, int ecount); u8 *ebuf, int ecount);
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, 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. * findstr - Safely find needle in haystack.
...@@ -370,7 +376,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) ...@@ -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); ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10);
if (ret) if (ret)
return 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) if (ret != 2)
return -EIO; return -EIO;
ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); 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, ...@@ -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 * @buf: The data in this buffer is treated as a complete link-level packet to
* be written. * be written.
* @bytes_write: Size of ebuf. * @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. * return: Number of bytes written, or < 0 on error.
*/ */
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, 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]; struct dvb_ca_slot *sl = &ca->slot_info[slot];
int status; int status;
...@@ -817,7 +825,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, ...@@ -817,7 +825,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
/* OK, set HC bit */ /* OK, set HC bit */
status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
IRQEN | CMDREG_HC); IRQEN | CMDREG_HC | size_write_flag);
if (status) if (status)
goto exit; goto exit;
...@@ -1508,7 +1516,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, ...@@ -1508,7 +1516,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
mutex_lock(&sl->slot_lock); mutex_lock(&sl->slot_lock);
status = dvb_ca_en50221_write_data(ca, slot, fragbuf, status = dvb_ca_en50221_write_data(ca, slot, fragbuf,
fraglen + 2); fraglen + 2, 0);
mutex_unlock(&sl->slot_lock); mutex_unlock(&sl->slot_lock);
if (status == (fraglen + 2)) { if (status == (fraglen + 2)) {
written = 1; written = 1;
...@@ -1709,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) ...@@ -1709,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dprintk("%s\n", __func__); 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; return -EIO;
}
err = dvb_generic_open(inode, file); err = dvb_generic_open(inode, file);
if (err < 0) { if (err < 0) {
module_put(ca->pub->owner); module_put(ca->pub->owner);
mutex_unlock(&ca->remove_mutex);
return err; return err;
} }
...@@ -1739,6 +1757,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) ...@@ -1739,6 +1757,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dvb_ca_private_get(ca); dvb_ca_private_get(ca);
mutex_unlock(&ca->remove_mutex);
return 0; return 0;
} }
...@@ -1758,6 +1777,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) ...@@ -1758,6 +1777,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dprintk("%s\n", __func__); dprintk("%s\n", __func__);
mutex_lock(&ca->remove_mutex);
/* mark the CA device as closed */ /* mark the CA device as closed */
ca->open = 0; ca->open = 0;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
...@@ -1768,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) ...@@ -1768,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dvb_ca_private_put(ca); 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; return err;
} }
...@@ -1891,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ...@@ -1891,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
} }
mutex_init(&ca->ioctl_mutex); mutex_init(&ca->ioctl_mutex);
mutex_init(&ca->remove_mutex);
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -EINTR; ret = -EINTR;
...@@ -1933,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) ...@@ -1933,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
dprintk("%s\n", __func__); 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 */ /* shutdown the thread if there was one */
kthread_stop(ca->thread); kthread_stop(ca->thread);
......
...@@ -115,12 +115,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, ...@@ -115,12 +115,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
cc = buf[3] & 0x0f; cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc; ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc;
if (!ccok) { if (!ccok) {
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("missed packet: %d instead of %d!\n", dprintk_sect_loss("missed packet: %d instead of %d!\n",
cc, (feed->cc + 1) & 0x0f); cc, (feed->cc + 1) & 0x0f);
} }
feed->cc = cc;
if (buf[1] & 0x40) // PUSI ? if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa; feed->peslen = 0xfffa;
...@@ -300,7 +300,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, ...@@ -300,7 +300,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
cc = buf[3] & 0x0f; cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc; ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc;
if (buf[3] & 0x20) { if (buf[3] & 0x20) {
/* adaption field present, check for discontinuity_indicator */ /* adaption field present, check for discontinuity_indicator */
...@@ -336,6 +335,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, ...@@ -336,6 +335,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
feed->pusi_seen = false; feed->pusi_seen = false;
dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_new(feed);
} }
feed->cc = cc;
if (buf[1] & 0x40) { if (buf[1] & 0x40) {
/* PUSI=1 (is set), section boundary is here */ /* PUSI=1 (is set), section boundary is here */
......
...@@ -293,14 +293,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, ...@@ -293,14 +293,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
} }
if (events->eventw == events->eventr) { if (events->eventw == events->eventr) {
int ret; struct wait_queue_entry wait;
int ret = 0;
if (flags & O_NONBLOCK) if (flags & O_NONBLOCK)
return -EWOULDBLOCK; return -EWOULDBLOCK;
ret = wait_event_interruptible(events->wait_queue, init_waitqueue_entry(&wait, current);
dvb_frontend_test_event(fepriv, events)); 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) if (ret < 0)
return ret; return ret;
} }
...@@ -809,15 +817,26 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) ...@@ -809,15 +817,26 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
mutex_lock(&fe->remove_mutex);
if (fe->exit != DVB_FE_DEVICE_REMOVED) if (fe->exit != DVB_FE_DEVICE_REMOVED)
fe->exit = DVB_FE_NORMAL_EXIT; fe->exit = DVB_FE_NORMAL_EXIT;
mb(); mb();
if (!fepriv->thread) if (!fepriv->thread) {
mutex_unlock(&fe->remove_mutex);
return; return;
}
kthread_stop(fepriv->thread); 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); sema_init(&fepriv->sem, 1);
fepriv->state = FESTATE_IDLE; fepriv->state = FESTATE_IDLE;
...@@ -2761,9 +2780,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -2761,9 +2780,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
struct dvb_adapter *adapter = fe->dvb; struct dvb_adapter *adapter = fe->dvb;
int ret; int ret;
mutex_lock(&fe->remove_mutex);
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (fe->exit == DVB_FE_DEVICE_REMOVED) if (fe->exit == DVB_FE_DEVICE_REMOVED) {
return -ENODEV; ret = -ENODEV;
goto err_remove_mutex;
}
if (adapter->mfe_shared == 2) { if (adapter->mfe_shared == 2) {
mutex_lock(&adapter->mfe_lock); mutex_lock(&adapter->mfe_lock);
...@@ -2771,7 +2794,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -2771,7 +2794,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (adapter->mfe_dvbdev && if (adapter->mfe_dvbdev &&
!adapter->mfe_dvbdev->writers) { !adapter->mfe_dvbdev->writers) {
mutex_unlock(&adapter->mfe_lock); mutex_unlock(&adapter->mfe_lock);
return -EBUSY; ret = -EBUSY;
goto err_remove_mutex;
} }
adapter->mfe_dvbdev = dvbdev; adapter->mfe_dvbdev = dvbdev;
} }
...@@ -2794,8 +2818,10 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -2794,8 +2818,10 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
while (mferetry-- && (mfedev->users != -1 || while (mferetry-- && (mfedev->users != -1 ||
mfepriv->thread)) { mfepriv->thread)) {
if (msleep_interruptible(500)) { if (msleep_interruptible(500)) {
if (signal_pending(current)) if (signal_pending(current)) {
return -EINTR; ret = -EINTR;
goto err_remove_mutex;
}
} }
} }
...@@ -2807,7 +2833,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -2807,7 +2833,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (mfedev->users != -1 || if (mfedev->users != -1 ||
mfepriv->thread) { mfepriv->thread) {
mutex_unlock(&adapter->mfe_lock); mutex_unlock(&adapter->mfe_lock);
return -EBUSY; ret = -EBUSY;
goto err_remove_mutex;
} }
adapter->mfe_dvbdev = dvbdev; adapter->mfe_dvbdev = dvbdev;
} }
...@@ -2866,6 +2893,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -2866,6 +2893,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (adapter->mfe_shared) if (adapter->mfe_shared)
mutex_unlock(&adapter->mfe_lock); mutex_unlock(&adapter->mfe_lock);
mutex_unlock(&fe->remove_mutex);
return ret; return ret;
err3: err3:
...@@ -2887,6 +2916,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -2887,6 +2916,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
err0: err0:
if (adapter->mfe_shared) if (adapter->mfe_shared)
mutex_unlock(&adapter->mfe_lock); mutex_unlock(&adapter->mfe_lock);
err_remove_mutex:
mutex_unlock(&fe->remove_mutex);
return ret; return ret;
} }
...@@ -2897,6 +2929,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) ...@@ -2897,6 +2929,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
int ret; int ret;
mutex_lock(&fe->remove_mutex);
dev_dbg(fe->dvb->device, "%s:\n", __func__); dev_dbg(fe->dvb->device, "%s:\n", __func__);
if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
...@@ -2918,10 +2952,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) ...@@ -2918,10 +2952,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
} }
mutex_unlock(&fe->dvb->mdev_lock); mutex_unlock(&fe->dvb->mdev_lock);
#endif #endif
if (fe->exit != DVB_FE_NO_EXIT)
wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl) if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0); 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); dvb_frontend_put(fe);
...@@ -3022,6 +3064,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, ...@@ -3022,6 +3064,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
fepriv = fe->frontend_priv; fepriv = fe->frontend_priv;
kref_init(&fe->refcount); kref_init(&fe->refcount);
mutex_init(&fe->remove_mutex);
/* /*
* After initialization, there need to be two references: one * After initialization, there need to be two references: one
......
...@@ -1564,15 +1564,43 @@ static long dvb_net_ioctl(struct file *file, ...@@ -1564,15 +1564,43 @@ static long dvb_net_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); 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) static int dvb_net_close(struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv; struct dvb_net *dvbnet = dvbdev->priv;
mutex_lock(&dvbnet->remove_mutex);
dvb_generic_release(inode, file); 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); wake_up(&dvbdev->wait_queue);
} else {
mutex_unlock(&dvbnet->remove_mutex);
}
return 0; return 0;
} }
...@@ -1580,7 +1608,7 @@ static int dvb_net_close(struct inode *inode, struct file *file) ...@@ -1580,7 +1608,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
static const struct file_operations dvb_net_fops = { static const struct file_operations dvb_net_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.unlocked_ioctl = dvb_net_ioctl, .unlocked_ioctl = dvb_net_ioctl,
.open = dvb_generic_open, .open = locked_dvb_net_open,
.release = dvb_net_close, .release = dvb_net_close,
.llseek = noop_llseek, .llseek = noop_llseek,
}; };
...@@ -1599,10 +1627,13 @@ void dvb_net_release (struct dvb_net *dvbnet) ...@@ -1599,10 +1627,13 @@ void dvb_net_release (struct dvb_net *dvbnet)
{ {
int i; int i;
mutex_lock(&dvbnet->remove_mutex);
dvbnet->exit = 1; dvbnet->exit = 1;
mutex_unlock(&dvbnet->remove_mutex);
if (dvbnet->dvbdev->users < 1) if (dvbnet->dvbdev->users < 1)
wait_event(dvbnet->dvbdev->wait_queue, wait_event(dvbnet->dvbdev->wait_queue,
dvbnet->dvbdev->users==1); dvbnet->dvbdev->users == 1);
dvb_unregister_device(dvbnet->dvbdev); dvb_unregister_device(dvbnet->dvbdev);
...@@ -1621,6 +1652,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, ...@@ -1621,6 +1652,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
int i; int i;
mutex_init(&dvbnet->ioctl_mutex); mutex_init(&dvbnet->ioctl_mutex);
mutex_init(&dvbnet->remove_mutex);
dvbnet->demux = dmx; dvbnet->demux = dmx;
for (i=0; i<DVB_NET_DEVICES_MAX; i++) for (i=0; i<DVB_NET_DEVICES_MAX; i++)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <media/tuner.h> #include <media/tuner.h>
static DEFINE_MUTEX(dvbdev_mutex); static DEFINE_MUTEX(dvbdev_mutex);
static LIST_HEAD(dvbdevfops_list);
static int dvbdev_debug; static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644); module_param(dvbdev_debug, int, 0644);
...@@ -453,14 +454,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -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) enum dvb_device_type type, int demux_sink_pads)
{ {
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct file_operations *dvbdevfops; struct file_operations *dvbdevfops = NULL;
struct dvbdevfops_node *node = NULL, *new_node = NULL;
struct device *clsdev; struct device *clsdev;
int minor; int minor;
int id, ret; int id, ret;
mutex_lock(&dvbdev_register_lock); 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); mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL; *pdvbdev = NULL;
pr_err("%s: couldn't find free device id\n", __func__); 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, ...@@ -468,18 +470,45 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
} }
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL); *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
if (!dvbdev){ if (!dvbdev){
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
return -ENOMEM; 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){ if (dvbdevfops == NULL) {
kfree (dvbdev); dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
mutex_unlock(&dvbdev_register_lock); if (!dvbdevfops) {
return -ENOMEM; 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)); memcpy(dvbdev, template, sizeof(struct dvb_device));
...@@ -490,20 +519,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -490,20 +519,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->priv = priv; dvbdev->priv = priv;
dvbdev->fops = dvbdevfops; dvbdev->fops = dvbdevfops;
init_waitqueue_head (&dvbdev->wait_queue); init_waitqueue_head (&dvbdev->wait_queue);
dvbdevfops->owner = adap->module; 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); down_write(&minor_rwsem);
#ifdef CONFIG_DVB_DYNAMIC_MINORS #ifdef CONFIG_DVB_DYNAMIC_MINORS
for (minor = 0; minor < MAX_DVB_MINORS; minor++) for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (dvb_minors[minor] == NULL) if (dvb_minors[minor] == NULL)
break; break;
if (minor == MAX_DVB_MINORS) { if (minor == MAX_DVB_MINORS) {
if (new_node) {
list_del (&new_node->list_head);
kfree(dvbdevfops);
kfree(new_node);
}
list_del (&dvbdev->list_head); list_del (&dvbdev->list_head);
kfree(dvbdevfops);
kfree(dvbdev); kfree(dvbdev);
up_write(&minor_rwsem); up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
...@@ -512,41 +541,47 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -512,41 +541,47 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
#else #else
minor = nums2minor(adap->num, type, id); minor = nums2minor(adap->num, type, id);
#endif #endif
dvbdev->minor = minor; dvbdev->minor = minor;
dvb_minors[minor] = dvb_device_get(dvbdev); dvb_minors[minor] = dvb_device_get(dvbdev);
up_write(&minor_rwsem); up_write(&minor_rwsem);
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads); ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
if (ret) { if (ret) {
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n", 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); dvb_media_device_free(dvbdev);
list_del (&dvbdev->list_head); list_del (&dvbdev->list_head);
kfree(dvbdevfops);
kfree(dvbdev); kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
return ret; return ret;
} }
mutex_unlock(&dvbdev_register_lock);
clsdev = device_create(dvb_class, adap->device, clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, minor), MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) { if (IS_ERR(clsdev)) {
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); __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); dvb_media_device_free(dvbdev);
list_del (&dvbdev->list_head); list_del (&dvbdev->list_head);
kfree(dvbdevfops);
kfree(dvbdev); kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return PTR_ERR(clsdev); return PTR_ERR(clsdev);
} }
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor); adap->num, dnames[type], id, minor, minor);
mutex_unlock(&dvbdev_register_lock);
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_register_device); EXPORT_SYMBOL(dvb_register_device);
...@@ -575,7 +610,6 @@ static void dvb_free_device(struct kref *ref) ...@@ -575,7 +610,6 @@ static void dvb_free_device(struct kref *ref)
{ {
struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref); struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
kfree (dvbdev->fops);
kfree (dvbdev); kfree (dvbdev);
} }
...@@ -1081,9 +1115,17 @@ static int __init init_dvbdev(void) ...@@ -1081,9 +1115,17 @@ static int __init init_dvbdev(void)
static void __exit exit_dvbdev(void) static void __exit exit_dvbdev(void)
{ {
struct dvbdevfops_node *node, *next;
class_destroy(dvb_class); class_destroy(dvb_class);
cdev_del(&dvb_device_cdev); cdev_del(&dvb_device_cdev);
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); 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); subsys_initcall(init_dvbdev);
......
...@@ -798,7 +798,7 @@ MODULE_DEVICE_TABLE(i2c, mn88443x_i2c_id); ...@@ -798,7 +798,7 @@ MODULE_DEVICE_TABLE(i2c, mn88443x_i2c_id);
static struct i2c_driver mn88443x_driver = { static struct i2c_driver mn88443x_driver = {
.driver = { .driver = {
.name = "mn88443x", .name = "mn88443x",
.of_match_table = of_match_ptr(mn88443x_of_match), .of_match_table = mn88443x_of_match,
}, },
.probe_new = mn88443x_probe, .probe_new = mn88443x_probe,
.remove = mn88443x_remove, .remove = mn88443x_remove,
......
...@@ -697,7 +697,7 @@ static void netup_unidvb_dma_fini(struct netup_unidvb_dev *ndev, int num) ...@@ -697,7 +697,7 @@ static void netup_unidvb_dma_fini(struct netup_unidvb_dev *ndev, int num)
netup_unidvb_dma_enable(dma, 0); netup_unidvb_dma_enable(dma, 0);
msleep(50); msleep(50);
cancel_work_sync(&dma->work); 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) 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, ...@@ -887,12 +887,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
ndev->lmmio0, (u32)pci_resource_len(pci_dev, 0), ndev->lmmio0, (u32)pci_resource_len(pci_dev, 0),
ndev->lmmio1, (u32)pci_resource_len(pci_dev, 1), ndev->lmmio1, (u32)pci_resource_len(pci_dev, 1),
pci_dev->irq); 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 * ndev->dma_size = 2 * 188 *
NETUP_DMA_BLOCKS_COUNT * NETUP_DMA_PACKETS_COUNT; NETUP_DMA_BLOCKS_COUNT * NETUP_DMA_PACKETS_COUNT;
ndev->dma_virt = dma_alloc_coherent(&pci_dev->dev, ndev->dma_virt = dma_alloc_coherent(&pci_dev->dev,
...@@ -933,6 +928,14 @@ static int netup_unidvb_initdev(struct pci_dev *pci_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"); dev_err(&pci_dev->dev, "netup_unidvb: DMA setup failed\n");
goto dma_setup_err; 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, dev_info(&pci_dev->dev,
"netup_unidvb: device has been initialized\n"); "netup_unidvb: device has been initialized\n");
return 0; return 0;
...@@ -951,8 +954,6 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, ...@@ -951,8 +954,6 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
dma_free_coherent(&pci_dev->dev, ndev->dma_size, dma_free_coherent(&pci_dev->dev, ndev->dma_size,
ndev->dma_virt, ndev->dma_phys); ndev->dma_virt, ndev->dma_phys);
dma_alloc_err: dma_alloc_err:
free_irq(pci_dev->irq, pci_dev);
irq_request_err:
iounmap(ndev->lmmio1); iounmap(ndev->lmmio1);
pci_bar1_error: pci_bar1_error:
iounmap(ndev->lmmio0); iounmap(ndev->lmmio0);
......
...@@ -101,6 +101,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, ...@@ -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 (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
if (msg[i].addr == if (msg[i].addr ==
ce6230_zl10353_config.demod_address) { ce6230_zl10353_config.demod_address) {
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
req.cmd = DEMOD_READ; req.cmd = DEMOD_READ;
req.value = msg[i].addr >> 1; req.value = msg[i].addr >> 1;
req.index = msg[i].buf[0]; req.index = msg[i].buf[0];
...@@ -117,6 +121,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, ...@@ -117,6 +121,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
} else { } else {
if (msg[i].addr == if (msg[i].addr ==
ce6230_zl10353_config.demod_address) { ce6230_zl10353_config.demod_address) {
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
req.cmd = DEMOD_WRITE; req.cmd = DEMOD_WRITE;
req.value = msg[i].addr >> 1; req.value = msg[i].addr >> 1;
req.index = msg[i].buf[0]; req.index = msg[i].buf[0];
......
...@@ -115,6 +115,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ...@@ -115,6 +115,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
while (i < num) { while (i < num) {
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
if (msg[i].addr == ec168_ec100_config.demod_address) { if (msg[i].addr == ec168_ec100_config.demod_address) {
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
req.cmd = READ_DEMOD; req.cmd = READ_DEMOD;
req.value = 0; req.value = 0;
req.index = 0xff00 + msg[i].buf[0]; /* reg */ 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[], ...@@ -131,6 +135,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
} }
} else { } else {
if (msg[i].addr == ec168_ec100_config.demod_address) { if (msg[i].addr == ec168_ec100_config.demod_address) {
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
req.cmd = WRITE_DEMOD; req.cmd = WRITE_DEMOD;
req.value = msg[i].buf[1]; /* val */ req.value = msg[i].buf[1]; /* val */
req.index = 0xff00 + msg[i].buf[0]; /* reg */ 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[], ...@@ -139,6 +147,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = ec168_ctrl_msg(d, &req); ret = ec168_ctrl_msg(d, &req);
i += 1; i += 1;
} else { } else {
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
req.cmd = WRITE_I2C; req.cmd = WRITE_I2C;
req.value = msg[i].buf[0]; /* val */ req.value = msg[i].buf[0]; /* val */
req.index = 0x0100 + msg[i].addr; /* I2C addr */ 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[], ...@@ -176,6 +176,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto err_mutex_unlock; goto err_mutex_unlock;
} else if (msg[0].addr == 0x10) { } 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 */ /* method 1 - integrated demod */
if (msg[0].buf[0] == 0x00) { if (msg[0].buf[0] == 0x00) {
/* return demod page from driver cache */ /* return demod page from driver cache */
...@@ -189,6 +193,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ...@@ -189,6 +193,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = rtl28xxu_ctrl_msg(d, &req); ret = rtl28xxu_ctrl_msg(d, &req);
} }
} else if (msg[0].len < 2) { } else if (msg[0].len < 2) {
if (msg[0].len < 1) {
ret = -EOPNOTSUPP;
goto err_mutex_unlock;
}
/* method 2 - old I2C */ /* method 2 - old I2C */
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
req.index = CMD_I2C_RD; req.index = CMD_I2C_RD;
...@@ -217,8 +225,16 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ...@@ -217,8 +225,16 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto err_mutex_unlock; goto err_mutex_unlock;
} else if (msg[0].addr == 0x10) { } else if (msg[0].addr == 0x10) {
if (msg[0].len < 1) {
ret = -EOPNOTSUPP;
goto err_mutex_unlock;
}
/* method 1 - integrated demod */ /* method 1 - integrated demod */
if (msg[0].buf[0] == 0x00) { if (msg[0].buf[0] == 0x00) {
if (msg[0].len < 2) {
ret = -EOPNOTSUPP;
goto err_mutex_unlock;
}
/* save demod page for later demod access */ /* save demod page for later demod access */
dev->page = msg[0].buf[1]; dev->page = msg[0].buf[1];
ret = 0; ret = 0;
...@@ -231,6 +247,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ...@@ -231,6 +247,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = rtl28xxu_ctrl_msg(d, &req); ret = rtl28xxu_ctrl_msg(d, &req);
} }
} else if ((msg[0].len < 23) && (!dev->new_i2c_write)) { } 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 */ /* method 2 - old I2C */
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
req.index = CMD_I2C_WR; req.index = CMD_I2C_WR;
......
...@@ -988,6 +988,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n ...@@ -988,6 +988,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
/* write/read request */ /* write/read request */
if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
req = 0xB9; req = 0xB9;
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
value = msg[i].addr + (msg[i].len << 8); value = msg[i].addr + (msg[i].len << 8);
length = msg[i + 1].len + 6; 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 ...@@ -1001,6 +1005,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
/* demod 16bit addr */ /* demod 16bit addr */
req = 0xBD; req = 0xBD;
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
value = msg[i].addr + (2 << 8); value = msg[i].addr + (2 << 8);
length = msg[i].len - 2; length = msg[i].len - 2;
...@@ -1026,6 +1034,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n ...@@ -1026,6 +1034,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n
} else { } else {
req = 0xBD; req = 0xBD;
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
index = msg[i].buf[0] & 0x00FF; index = msg[i].buf[0] & 0x00FF;
value = msg[i].addr + (1 << 8); value = msg[i].addr + (1 << 8);
length = msg[i].len - 1; length = msg[i].len - 1;
......
...@@ -63,6 +63,10 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num ...@@ -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."); warn("more than 2 i2c messages at a time is not handled yet. TODO.");
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (msg[i].len < 1) {
i = -EOPNOTSUPP;
break;
}
/* write/read request */ /* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { 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, 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]) ...@@ -946,7 +946,7 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
obuf[1] = 0xf0 + i; obuf[1] = 0xf0 + i;
if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
break; return -1;
else else
mac[i] = ibuf[0]; mac[i] = ibuf[0];
} }
......
...@@ -37,6 +37,7 @@ config VIDEO_PVRUSB2_DVB ...@@ -37,6 +37,7 @@ config VIDEO_PVRUSB2_DVB
bool "pvrusb2 ATSC/DVB support" bool "pvrusb2 ATSC/DVB support"
default y default y
depends on VIDEO_PVRUSB2 && DVB_CORE depends on VIDEO_PVRUSB2 && DVB_CORE
depends on VIDEO_PVRUSB2=m || DVB_CORE=y
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1411 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) ...@@ -1544,8 +1544,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dvb_dmx_release(&dec->demux); dvb_dmx_release(&dec->demux);
if (dec->fe) { if (dec->fe) {
dvb_unregister_frontend(dec->fe); dvb_unregister_frontend(dec->fe);
if (dec->fe->ops.release) dvb_frontend_detach(dec->fe);
dec->fe->ops.release(dec->fe);
} }
dvb_unregister_adapter(&dec->adapter); dvb_unregister_adapter(&dec->adapter);
} }
......
...@@ -686,7 +686,10 @@ struct dtv_frontend_properties { ...@@ -686,7 +686,10 @@ struct dtv_frontend_properties {
* @id: Frontend ID * @id: Frontend ID
* @exit: Used to inform the DVB core that the frontend * @exit: Used to inform the DVB core that the frontend
* thread should exit (usually, means that the hardware * 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 { struct dvb_frontend {
...@@ -704,6 +707,7 @@ struct dvb_frontend { ...@@ -704,6 +707,7 @@ struct dvb_frontend {
int (*callback)(void *adapter_priv, int component, int cmd, int arg); int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id; int id;
unsigned int exit; unsigned int exit;
struct mutex remove_mutex;
}; };
/** /**
......
...@@ -39,6 +39,9 @@ struct net_device; ...@@ -39,6 +39,9 @@ struct net_device;
* @exit: flag to indicate when the device is being removed. * @exit: flag to indicate when the device is being removed.
* @demux: pointer to &struct dmx_demux. * @demux: pointer to &struct dmx_demux.
* @ioctl_mutex: protect access to this struct. * @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 * Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
* devices. * devices.
...@@ -51,6 +54,7 @@ struct dvb_net { ...@@ -51,6 +54,7 @@ struct dvb_net {
unsigned int exit:1; unsigned int exit:1;
struct dmx_demux *demux; struct dmx_demux *demux;
struct mutex ioctl_mutex; struct mutex ioctl_mutex;
struct mutex remove_mutex;
}; };
/** /**
......
...@@ -193,6 +193,21 @@ struct dvb_device { ...@@ -193,6 +193,21 @@ struct dvb_device {
void *priv; 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 * dvb_device_get - Increase dvb_device reference
* *
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册