summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/dvb-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb/dvb-core')
-rw-r--r--linux/drivers/media/dvb/dvb-core/Kconfig14
-rw-r--r--linux/drivers/media/dvb/dvb-core/dmxdev.c56
-rw-r--r--linux/drivers/media/dvb/dvb-core/dmxdev.h2
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c20
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_net.c53
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_net.h1
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.c26
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.h1
8 files changed, 157 insertions, 16 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/Kconfig b/linux/drivers/media/dvb/dvb-core/Kconfig
index 1990eda10..e3e6839f8 100644
--- a/linux/drivers/media/dvb/dvb-core/Kconfig
+++ b/linux/drivers/media/dvb/dvb-core/Kconfig
@@ -1,12 +1,22 @@
config DVB_CORE
- tristate "DVB Core Support"
- depends on DVB
+ tristate "DVB for Linux"
+ depends on NET && INET
select CRC32
help
+ Support Digital Video Broadcasting hardware. Enable this if you
+ own a DVB adapter and want to use it or if you compile Linux for
+ a digital SetTopBox.
+
DVB core utility functions for device handling, software fallbacks etc.
Say Y when you have a DVB card and want to use it. Say Y if your want
to build your drivers outside the kernel, but need the DVB core. All
in-kernel drivers will select this automatically if needed.
+
+ API specs and user tools are available from <http://www.linuxtv.org/>.
+
+ Please report problems regarding this driver to the LinuxDVB
+ mailing list.
+
If unsure say N.
config DVB_CORE_ATTACH
diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c
index a5c0e1a3e..275df65fd 100644
--- a/linux/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c
@@ -132,6 +132,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
mutex_unlock(&dmxdev->mutex);
@@ -171,6 +176,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front);
}
+ dvbdev->users++;
mutex_unlock(&dmxdev->mutex);
return 0;
}
@@ -198,7 +204,16 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
vfree(mem);
}
}
- mutex_unlock(&dmxdev->mutex);
+ /* TODO */
+ dvbdev->users--;
+ if(dvbdev->users==-1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
return 0;
}
@@ -215,6 +230,11 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
return -EINVAL;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
ret = dmxdev->demux->write(dmxdev->demux, buf, count);
mutex_unlock(&dmxdev->mutex);
return ret;
@@ -227,6 +247,11 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
//mutex_lock(&dmxdev->mutex);
ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
file->f_flags & O_NONBLOCK,
@@ -665,6 +690,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
dmxdevfilter->feed.ts = NULL;
init_timer(&dmxdevfilter->timer);
+ dvbdev->users++;
+
mutex_unlock(&dmxdev->mutex);
return 0;
}
@@ -943,7 +970,21 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
- return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+ int ret;
+
+ ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+ mutex_lock(&dmxdev->mutex);
+ dmxdev->dvbdev->users--;
+ if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dmxdev->dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
+ return ret;
}
static struct file_operations dvb_demux_fops = {
@@ -1027,6 +1068,7 @@ static struct file_operations dvb_dvr_fops = {
static struct dvb_device dvbdev_dvr = {
.priv = NULL,
.readers = 1,
+ .users = 1,
.fops = &dvb_dvr_fops
};
@@ -1064,6 +1106,16 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
+ dmxdev->exit=1;
+ if (dmxdev->dvbdev->users > 1) {
+ wait_event(dmxdev->dvbdev->wait_queue,
+ dmxdev->dvbdev->users==1);
+ }
+ if (dmxdev->dvr_dvbdev->users > 1) {
+ wait_event(dmxdev->dvr_dvbdev->wait_queue,
+ dmxdev->dvr_dvbdev->users==1);
+ }
+
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);
diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.h b/linux/drivers/media/dvb/dvb-core/dmxdev.h
index 080abd9a9..bb416e6c2 100644
--- a/linux/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/linux/drivers/media/dvb/dvb-core/dmxdev.h
@@ -98,6 +98,8 @@ struct dmxdev {
int filternum;
int capabilities;
+
+ unsigned int exit:1;
#define DMXDEV_CAP_DUPLEX 1
struct dmx_frontend *dvr_orig_fe;
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index 60c8b0da2..2cad44fb2 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -611,6 +611,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
return;
kthread_stop(fepriv->thread);
+
init_MUTEX (&fepriv->sem);
fepriv->state = FESTATE_IDLE;
@@ -1028,6 +1029,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ int ret;
dprintk ("%s\n", __FUNCTION__);
@@ -1037,7 +1039,14 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl (fe, 0);
- return dvb_generic_release (inode, file);
+ ret = dvb_generic_release (inode, file);
+
+ if (dvbdev->users==-1 && fepriv->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ wake_up(&dvbdev->wait_queue);
+ }
+ return ret;
}
static struct file_operations dvb_frontend_fops = {
@@ -1097,8 +1106,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
dprintk ("%s\n", __FUNCTION__);
mutex_lock(&frontend_mutex);
- dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
+ mutex_unlock(&frontend_mutex);
+
+ if (fepriv->dvbdev->users < -1)
+ wait_event(fepriv->dvbdev->wait_queue,
+ fepriv->dvbdev->users==-1);
+
+ mutex_lock(&frontend_mutex);
+ dvb_unregister_device (fepriv->dvbdev);
/* fe is invalid now */
kfree(fepriv);
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c
index 3e94e6cf9..408c3b638 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c
@@ -183,7 +183,11 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
struct ethhdr *eth;
unsigned char *rawp;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
skb->mac.raw=skb->data;
+#else
+ skb_reset_mac_header(skb);
+#endif
skb_pull(skb,dev->hard_header_len);
eth = eth_hdr(skb);
@@ -609,6 +613,9 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Check CRC32, we've got it in our skb already. */
unsigned short ulen = htons(priv->ule_sndu_len);
unsigned short utype = htons(priv->ule_sndu_type);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ const u8 *tail;
+#endif
struct kvec iov[3] = {
{ &ulen, sizeof ulen },
{ &utype, sizeof utype },
@@ -622,10 +629,18 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
ule_crc = iov_crc32(ule_crc, iov, 3);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 |
*((u8 *)priv->ule_skb->tail - 3) << 16 |
*((u8 *)priv->ule_skb->tail - 2) << 8 |
*((u8 *)priv->ule_skb->tail - 1);
+#else
+ tail = skb_tail_pointer(priv->ule_skb);
+ expected_crc = *(tail - 4) << 24 |
+ *(tail - 3) << 16 |
+ *(tail - 2) << 8 |
+ *(tail - 1);
+#endif
if (ule_crc != expected_crc) {
printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
@@ -704,7 +719,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
else
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN);
+#else
+ skb_copy_from_linear_data(priv->ule_skb,
+ dest_addr,
+ ETH_ALEN);
+#endif
skb_pull(priv->ule_skb, ETH_ALEN);
}
}
@@ -1476,11 +1497,36 @@ static int dvb_net_ioctl(struct inode *inode, struct file *file,
return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl);
}
+static int dvb_net_close(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_net *dvbnet = dvbdev->priv;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ dvbdev->readers++;
+ } else {
+ dvbdev->writers++;
+ }
+
+ dvbdev->users++;
+
+ if(dvbdev->users == 1 && dvbnet->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ wake_up(&dvbdev->wait_queue);
+ }
+ return 0;
+}
+
+
static struct file_operations dvb_net_fops = {
.owner = THIS_MODULE,
.ioctl = dvb_net_ioctl,
.open = dvb_generic_open,
- .release = dvb_generic_release,
+ .release = dvb_net_close,
};
static struct dvb_device dvbdev_net = {
@@ -1495,6 +1541,11 @@ void dvb_net_release (struct dvb_net *dvbnet)
{
int i;
+ dvbnet->exit = 1;
+ if (dvbnet->dvbdev->users < 1)
+ wait_event(dvbnet->dvbdev->wait_queue,
+ dvbnet->dvbdev->users==1);
+
dvb_unregister_device(dvbnet->dvbdev);
for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.h b/linux/drivers/media/dvb/dvb-core/dvb_net.h
index f14e4ca38..3a3126cae 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_net.h
+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.h
@@ -36,6 +36,7 @@ struct dvb_net {
struct dvb_device *dvbdev;
struct net_device *device[DVB_NET_DEVICES_MAX];
int state[DVB_NET_DEVICES_MAX];
+ unsigned int exit:1;
struct dmx_demux *demux;
};
diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c
index 9c8e9c3f4..aee6db950 100644
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c
@@ -211,7 +211,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
{
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
-
+ struct class_device *clsdev;
int id;
mutex_lock(&dvbdev_register_lock);
@@ -219,7 +219,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
- printk ("%s: could get find free device id...\n", __FUNCTION__);
+ printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
return -ENFILE;
}
@@ -244,6 +244,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->adapter = adap;
dvbdev->priv = priv;
dvbdev->fops = dvbdevfops;
+ init_waitqueue_head (&dvbdev->wait_queue);
memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
dvbdev->fops->owner = adap->module;
@@ -252,10 +253,17 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
- class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
+ clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR,
+ nums2minor(adap->num, type, id)),
+ adap->device, "dvb%d.%s%d", adap->num,
+ dnames[type], id);
+ if (IS_ERR(clsdev)) {
+ printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
+ __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+ return PTR_ERR(clsdev);
+ }
- dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+ dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
nums2minor(adap->num, type, id));
@@ -314,7 +322,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list);
- printk ("DVB: registering new adapter (%s).\n", name);
+ printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
adap->num = num;
adap->name = name;
@@ -410,13 +418,13 @@ static int __init init_dvbdev(void)
dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable register character device\n");
goto error;
}
@@ -441,7 +449,7 @@ static void __exit exit_dvbdev(void)
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
}
-module_init(init_dvbdev);
+subsys_initcall(init_dvbdev);
module_exit(exit_dvbdev);
MODULE_DESCRIPTION("DVB Core Driver");
diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h
index 26e4a9135..cb76869bd 100644
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h
@@ -70,6 +70,7 @@ struct dvb_device {
int writers;
int users;
+ wait_queue_head_t wait_queue;
/* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg);