SASC
DVBSoftCAM

dvb_loopback.c File Reference

#include <linux/version.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/dvb/ca.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/version.h>
#include <linux/vmalloc.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include "dvbdev.h"
#include "dvbdevwrap.h"
#include "dvblb_internal.h"

Go to the source code of this file.

Defines

#define DVBLOOPBACK_VERSION   "0.0.1"
#define N_BUFFS   2
#define info(format, arg...)   printk(KERN_INFO __FILE__ ": " format "\n" "", ## arg)
#define dprintk   if (dvblb_debug) printk
#define dprintk2   if (dvblb_debug > 1) printk
#define dprintk3   if (dvblb_debug > 2) printk

Functions

 module_param (dvblb_debug, int, S_IRUGO|S_IWUSR)
 module_param (num_adapters, int, S_IRUGO)
static void * rvmalloc (unsigned long size)
static void rvfree (void *mem, unsigned long size)
static int dvblb_usercopy (struct file *file, unsigned int cmd, unsigned long arg, int(*func)(struct file *file, unsigned int cmd, void *arg))
static int get_new_filemap (struct dvblb_devinfo *lbdev, int id)
static int find_filemap (struct dvblb_devinfo *lbdev, struct dvb_device **fm)
int inuse_filemap (struct dvblb_devinfo *lbdev)
static int dvblb_fake_ioctl (struct dvblb_devinfo *lbdev, struct dvb_device **f, unsigned long int cmd, void *arg)
static int dvblb_open (struct inode *inode, struct file *f)
static int dvblb_release (struct inode *inode, struct file *f)
static ssize_t dvblb_write (struct file *f, const char *buf, size_t count, loff_t *offset)
static ssize_t dvblb_read (struct file *f, char *buf, size_t count, loff_t *offset)
static int dvblb_looped_ioctl (struct file *f, unsigned int cmd, void *parg)
static long dvblb_ioctl (struct file *f, unsigned int cmd, unsigned long arg)
static int dvblb_mmap (struct file *f, struct vm_area_struct *vma)
static unsigned int dvblb_poll (struct file *f, struct poll_table_struct *wait)
static int create_lb_dev (struct dvblb *dvblb, int dev_idx, int type)
static int destroy_lb_dev (struct dvblb *dvblb, int dev_idx)
static int destroy_lb_adapter (struct dvblb *dvblb)
 MODULE_AUTHOR ("Alan Nisota")
 MODULE_DESCRIPTION ("DVB loopback device.")
 MODULE_LICENSE ("GPL")
 MODULE_VERSION (DVBLOOPBACK_VERSION)
static int __init dvblb_init (void)
static void __exit cleanup_dvblb_module (void)
 module_init (dvblb_init)
 module_exit (cleanup_dvblb_module)

Variables

static int dvblb_debug = 0
static int num_adapters = 1
static struct dvblb * dvblb_global
static struct file_operations dvbdev_looped_fops
static struct dvb_device dvbdev_looped
static struct file_operations dvbdev_userspace_fops
static struct dvb_device dvbdev_userspace
static struct platform_device * dvblb_basedev

Define Documentation

#define dprintk   if (dvblb_debug) printk
#define dprintk2   if (dvblb_debug > 1) printk

Definition at line 72 of file dvb_loopback.c.

Referenced by dvblb_fake_ioctl(), and dvblb_ioctl().

#define dprintk3   if (dvblb_debug > 2) printk

Definition at line 73 of file dvb_loopback.c.

Referenced by dvblb_poll(), dvblb_read(), and dvblb_write().

#define DVBLOOPBACK_VERSION   "0.0.1"

Definition at line 44 of file dvb_loopback.c.

Referenced by dvblb_init().

#define info (   format,
  arg... 
)    printk(KERN_INFO __FILE__ ": " format "\n" "", ## arg)
#define N_BUFFS   2

Definition at line 67 of file dvb_loopback.c.

Referenced by destroy_lb_dev(), dvblb_mmap(), and dvblb_release().


Function Documentation

static void __exit cleanup_dvblb_module ( void  ) [static]

Definition at line 1267 of file dvb_loopback.c.

References destroy_lb_adapter(), dvblb_uninit_procfs(), i, info, dvblb::init, and num_adapters.

{
        int i;
        info("Unregistering ca loopback devices");
        for(i = 0; i < num_adapters; i++) {
                if(0 == dvblb_global[i].init)
                        break;
                destroy_lb_adapter(&dvblb_global[i]);
        }
        platform_device_unregister(dvblb_basedev);
        kfree(dvblb_global);
        dvblb_uninit_procfs();
}
static int create_lb_dev ( struct dvblb *  dvblb,
int  dev_idx,
int  type 
) [static]

Definition at line 1047 of file dvb_loopback.c.

References dvblb::adapter, dvblb_devinfo::buffer, dvblb_devinfo::buflen, dvblb::devinfo, dvb_register_device(), dvb_unregister_device(), dvblb_init_procfs_device(), DVBLB_MAXFD, dvblb_devinfo::filemap, dvblb_devinfo::forward_dev, dvblb_devinfo::forwardmap, i, info, dvblb::init, dvblb_devinfo::ioctl_already_read, dvblb_devinfo::ioctlcmd, dvblb_devinfo::ioctllen, dvblb_devinfo::ioctlretdata, dvblb_devinfo::lb_dev, dvblb_devinfo::lock_buffer, dvblb_devinfo::lock_fake_ioctl, dvblb_devinfo::lock_ioctl, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::pid, dvblb_devinfo::poll_waiting, dvblb_devinfo::user_dev, dvblb_devinfo::wait_ioctl, dvblb_devinfo::wait_poll, and dvblb_devinfo::wait_virt_poll.

Referenced by dvblb_init().

{
        int ret;
        struct dvblb_devinfo *lbdev = &dvblb->devinfo[dev_idx];

// create loopback device (will be frontend0)
        ret = dvb_register_device(&dvblb->adapter, &lbdev->lb_dev,
                            &dvbdev_looped, lbdev, type);
        if (ret != 0) {
                info("error registering device adapter%d",
                     dvblb->adapter.num);
                return ret;
        }
// create userspace device (will be frontend1)
        ret = dvb_register_device(&dvblb->adapter, &lbdev->user_dev,
                            &dvbdev_userspace, lbdev, type);
        if (ret != 0) {
                info("error registering device adapter%d",
                     dvblb->adapter.num);
                dvb_unregister_device(lbdev->lb_dev);
                return ret;
        }
// initialize all data
        //lbdev->ioctldata=kmalloc(1024, GFP_KERNEL);
        //if(lbdev->ioctldata == NULL)
        //{
        //      dvb_unregister_device(lbdev->lb_dev);
        //      dvb_unregister_device(lbdev->user_dev);
        //      return -ENOMEM;
        //}
        lbdev->parent = dvblb;
        lbdev->ioctlretdata=kmalloc(5*1024, GFP_KERNEL);
        lbdev->pid = -1;
        lbdev->buffer = NULL;
        lbdev->buflen = 0;
        lbdev->ioctlcmd = ULONG_MAX;
        lbdev->ioctllen = 0;
        lbdev->ioctl_already_read = 1;
        lbdev->forward_dev = NULL;
        memset(lbdev->filemap, 0, sizeof(lbdev->filemap));
        memset(lbdev->forwardmap, 0, sizeof(lbdev->forwardmap));

        lbdev->poll_waiting = 0;
        dvblb_init_procfs_device(dvblb, lbdev);

        {
                int i;
                for(i = 0; i < DVBLB_MAXFD; i++)
                        init_waitqueue_head(&lbdev->wait_poll[i]);
        }
        init_waitqueue_head(&lbdev->wait_virt_poll);
        init_waitqueue_head(&lbdev->wait_ioctl);
        mutex_init(&lbdev->lock_fake_ioctl);
        mutex_init(&lbdev->lock_ioctl);
        mutex_init(&lbdev->lock_buffer);
        dvblb->init |= (1 << dev_idx);
        return 0;
}
static int destroy_lb_dev ( struct dvblb *  dvblb,
int  dev_idx 
) [static]

Definition at line 1106 of file dvb_loopback.c.

References dvblb_devinfo::buffer, dvblb_devinfo::buflen, dvblb::devinfo, dvb_unregister_device(), dvblb_remove_procfs(), dvblb::init, dvblb_devinfo::ioctlretdata, dvblb_devinfo::lb_dev, N_BUFFS, dvblb::procdir, dvblb_devinfo::procfile, rvfree(), and dvblb_devinfo::user_dev.

Referenced by destroy_lb_adapter().

{
        if (0 == (dvblb->init & (1 << dev_idx)))
                return 0;
        dvb_unregister_device(dvblb->devinfo[dev_idx].lb_dev);
        dvb_unregister_device(dvblb->devinfo[dev_idx].user_dev);
        if (dvblb->devinfo[dev_idx].buffer)
                rvfree(dvblb->devinfo[dev_idx].buffer,
                       dvblb->devinfo[dev_idx].buflen*N_BUFFS);
        //kfree(lbdev->ioctldata);
        kfree(dvblb->devinfo[dev_idx].ioctlretdata);
        dvblb_remove_procfs(dvblb->devinfo[dev_idx].procfile, dvblb->procdir);
        dvblb->init &= ~(1 << dev_idx);
        return 0;
}
static int dvblb_fake_ioctl ( struct dvblb_devinfo *  lbdev,
struct dvb_device **  f,
unsigned long int  cmd,
void *  arg 
) [static]

Definition at line 260 of file dvb_loopback.c.

References dvblb::adapter, cmd, dprintk, dprintk2, DVBLB_CMD_CLOSE, DVBLB_MAX_CMDS, dvblb_devinfo::ioctl_already_read, dvblb_devinfo::ioctlcmd, dvblb_devinfo::ioctldata, dvblb_devinfo::ioctlfd, dvblb_devinfo::ioctllen, dvblb_devinfo::ioctlretdata, dvblb_devinfo::ioctlretval, dvblb_devinfo::lock_fake_ioctl, dvblb_devinfo::lock_ioctl, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::wait_ioctl, and dvblb_devinfo::wait_virt_poll.

Referenced by dvblb_looped_ioctl(), dvblb_open(), dvblb_poll(), dvblb_read(), and dvblb_release().

{
        int ret = 0;
#if DVB_API_VERSION >=5
        struct dtv_properties *tvps = NULL;
        long unsigned int _ioctllen;
#endif
        dprintk2("dvblb_fake_ioctl (%d) : %lu\n", lbdev->parent->adapter.num,
                 0xFF & cmd);
        if (mutex_lock_interruptible(&lbdev->lock_fake_ioctl))
                return -ERESTARTSYS;
        if (mutex_lock_interruptible(&lbdev->lock_ioctl)) {
                mutex_unlock(&lbdev->lock_fake_ioctl);
                return -ERESTARTSYS;
        }
        //printk("Sleep up on cmd: %u\n", cmd);
        lbdev->ioctlcmd = cmd;
        lbdev->ioctl_already_read = 0;
        if (cmd < DVBLB_MAX_CMDS) {
                // Read data command
                lbdev->ioctllen = sizeof(struct dvblb_custommsg);
        } else {
                // Regular ioctl
                lbdev->ioctllen = _IOC_SIZE(cmd);
        }

        lbdev->ioctlfd = f;
        lbdev->ioctldata = arg;
        //kill_proc(lbdev->pid, SIGIO, 1);

        mutex_unlock(&lbdev->lock_ioctl);
        wake_up_interruptible(&lbdev->wait_virt_poll);
        while(1) {
                ret = wait_event_interruptible_timeout(lbdev->wait_ioctl,
                         lbdev->ioctlcmd == ULONG_MAX, HZ);
                dprintk2("fake-ioctl wait (%lu) returned: %d/%lu\n", cmd,
                         ret, lbdev->ioctlcmd);
                if(ret >= 0 && lbdev->ioctlcmd == ULONG_MAX)
                        break;
                if(cmd == DVBLB_CMD_CLOSE) {
                        dprintk("Received a signal."
                                "  Resending DVBLB_CLOSE message\n");
                        wait_event_timeout(lbdev->wait_ioctl,
                                   lbdev->ioctlcmd == ULONG_MAX, HZ);
                        break;
                }
                if(ret < 0 || lbdev->filemap[0] == NULL) {
                        /* userspace driver has closed it would be nice if we
                           could do something about it here */
                        printk("dvblb_fake_ioctl interrupted: %lu\n",
                               lbdev->ioctlcmd);
                        mutex_unlock(&lbdev->lock_fake_ioctl);
                        return -1;
                }
                dprintk("dvbloopback: timeout waiting for userspace\n");
        }

        if (mutex_lock_interruptible(&lbdev->lock_ioctl)) {
                mutex_unlock(&lbdev->lock_fake_ioctl);
                return -ERESTARTSYS;
        }
        //printk("Woke up on cmd: %u\n", cmd);
        if (lbdev->ioctlcmd != ULONG_MAX) {
                mutex_unlock(&lbdev->lock_ioctl);
                mutex_unlock(&lbdev->lock_fake_ioctl);
                printk("dvblb_fake_ioctl failed: %lu\n",lbdev->ioctlcmd);
                return -1;
        }

        if (cmd < DVBLB_MAX_CMDS || ! (cmd & IOC_IN)){
#if DVB_API_VERSION >=5
                if ((cmd == FE_GET_PROPERTY)) {
                    tvps = (struct dtv_properties __user *)(lbdev->ioctlretdata + sizeof(int));
                    _ioctllen = lbdev->ioctllen + (tvps->num * sizeof(struct dtv_property));
                    memcpy(arg, lbdev->ioctlretdata + sizeof(int), _ioctllen);
                    tvps = (struct dtv_properties __user *)arg;
                    tvps->props = (struct dtv_property __user *)(arg + lbdev->ioctllen);
                }
                else
#endif
                    memcpy(arg, lbdev->ioctlretdata + sizeof(int), lbdev->ioctllen);
        }

        ret = lbdev->ioctlretval;
        mutex_unlock(&lbdev->lock_ioctl);
        mutex_unlock(&lbdev->lock_fake_ioctl);
        return ret;
}
static int __init dvblb_init ( void  ) [static]

Definition at line 1149 of file dvb_loopback.c.

References dvblb::adapter, dvblb::adapter_ll, create_lb_dev(), destroy_lb_adapter(), DVB_DEVICE_AUDIO, DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_FRONTEND, DVB_DEVICE_OSD, DVB_DEVICE_VIDEO, DVBLB_AUDIO, DVBLB_DEMUX, DVBLB_DVR, DVBLB_FRONTEND, dvblb_init_procfs(), dvblb_init_procfs_adapter(), DVBLB_MAX_ADAPTERS, DVBLB_OSD, DVBLB_STATUS_ADAPTER, DVBLB_VIDEO, DVBLOOPBACK_VERSION, i, info, dvblb::init, dvblb::link, dvb_adapter::list_head, list_head::next, NULL, num_adapters, and wrap_dvb_reg_adapter.

{
        int i,ret, failed;
        i=0;
        failed=0;

        dvblb_init_procfs();

        info("frontend loopback driver v"DVBLOOPBACK_VERSION);
        if (num_adapters < 1 || num_adapters > DVBLB_MAX_ADAPTERS) {
                printk("dvbloopback: param num_adapters=%d. Must be between"
                       " 1 and %d\n", num_adapters, DVBLB_MAX_ADAPTERS);
                return -EFAULT;
        }
        printk("dvbloopback: registering %d adapters\n", num_adapters);

        dvblb_global = kmalloc(sizeof(struct dvblb) * num_adapters, GFP_KERNEL);
        if (dvblb_global == NULL)
                return -ENOMEM;
        for(i=0; i < num_adapters; i++)
                dvblb_global[i].init = 0;
 
        dvblb_basedev = platform_device_alloc("dvbloopback", -1);
        if (!dvblb_basedev) {
                kfree(dvblb_global);
                return -ENOMEM;
        }
        ret = platform_device_add(dvblb_basedev);
        if (ret) {
                platform_device_put(dvblb_basedev);
                kfree(dvblb_global);
                return ret;
        }
        for(i=0; i < num_adapters; i++) {
                struct dvblb *this_adptr = &dvblb_global[i];
                // register new adapter (happens in main driver)
                if (wrap_dvb_reg_adapter(&this_adptr->adapter,
                                         "DVB-LOOPBACK", NULL) < 0) {
                        failed = 1;
                        break;
                }
                this_adptr->init |= DVBLB_STATUS_ADAPTER;

                // NOTE: we use the next line to fetch the start-node for the 
                // the adapter linked-list.  However it relies on us grabbing it
                // before another device is added (i.e. this adapter must be the
                // last on the list.
                if (0 == i) {
                        this_adptr->adapter_ll =
                                        this_adptr->adapter.list_head.next;
                } else {
                        this_adptr->adapter_ll = dvblb_global[0].adapter_ll;
                }
                this_adptr->link = -1;
                dvblb_init_procfs_adapter(this_adptr);

                ret = create_lb_dev(this_adptr, DVBLB_FRONTEND,
                                    DVB_DEVICE_FRONTEND);
                if (ret != 0) {
                        info("Failed to add loopback for adapter");
                        failed = 1;
                        break;
                }

                ret = create_lb_dev(this_adptr, DVBLB_DEMUX,
                            DVB_DEVICE_DEMUX);
                if (ret != 0) {
                        info("Failed to add loopback for adapter");
                        failed = 1;
                        break;
                }

                ret = create_lb_dev(this_adptr, DVBLB_DVR,
                                    DVB_DEVICE_DVR);
                if (ret != 0) {
                        info("Failed to add loopback for adapter");
                        failed = 1;
                        break;
                }

                ret = create_lb_dev(this_adptr, DVBLB_VIDEO,
                                    DVB_DEVICE_VIDEO);
                if (ret != 0) {
                        info("Failed to add loopback for adapter");
                        failed = 1;
                        break;
                }

                ret = create_lb_dev(this_adptr, DVBLB_AUDIO,
                                    DVB_DEVICE_AUDIO);
                if (ret != 0) {
                        info("Failed to add loopback for adapter");
                        failed = 1;
                        break;
                }

                ret = create_lb_dev(this_adptr, DVBLB_OSD,
                                    DVB_DEVICE_OSD);
                if (ret != 0) {
                        info("Failed to add loopback for adapter");
                        failed = 1;
                        break;
                }
        }

        if (failed) {
                for(i = 0; i < num_adapters; i++) {
                        if(0 == dvblb_global[i].init)
                                break;
                        destroy_lb_adapter(&dvblb_global[i]);
                }
                platform_device_unregister(dvblb_basedev);
                kfree(dvblb_global);
                return -EFAULT;
        }
        return 0;
}
static long dvblb_ioctl ( struct file *  f,
unsigned int  cmd,
unsigned long  arg 
) [static]

Definition at line 712 of file dvb_loopback.c.

References dvblb::adapter, dvblb_pollmsg::count, dnames, dprintk, dprintk2, DVBLB_CMD_ASYNC, dvblb_forward_ioctl(), DVBLB_MAX_CMDS, DVBLB_MAXFD, dvblb_usercopy(), dvblb_pollmsg::file, dvblb_devinfo::filemap, find_filemap(), dvblb_devinfo::forward_dev, i, dvb_device::id, dvblb_devinfo::ioctlcmd, dvblb_devinfo::ioctlretdata, dvblb_devinfo::ioctlretval, dvb_device::kernel_ioctl, dvblb_devinfo::lock_ioctl, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::poll_waiting, dvb_device::priv, dvb_device::type, dvblb_devinfo::wait_ioctl, and dvblb_devinfo::wait_poll.

{
        void * parg = (void *)arg;
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;
#if DVB_API_VERSION >=5
        struct dtv_properties *tvps;
#endif
        int size;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during ioctl\n");
                return -EFAULT;
        }
        if(dvbdev->id == 0) {
                /* This is the looped device */
                if (lbdev->forward_dev)
                        return dvblb_forward_ioctl(lbdev, f, cmd, arg);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
                return dvblb_usercopy (f, cmd, arg,
                                       dvbdev->kernel_ioctl);
#else
                return dvblb_usercopy (inode, f, cmd, arg,
                                       dvbdev->kernel_ioctl);
#endif
        }
        /* This is the userspace control device */
        dprintk2("dvblb_ioctl %d%s%d fd:%d cmd:%x\n",lbdev->parent->adapter.num,
                dnames[dvbdev->type],
                dvbdev->id, find_filemap(lbdev, filemap), cmd);
        if (cmd == DVBLB_CMD_ASYNC) {
                /* async command return */
                int pos, i;
                struct dvblb_pollmsg pollmsg;
                if (copy_from_user(&pollmsg, parg,
                                   sizeof(struct dvblb_pollmsg))) {
                        printk("Failed to read pollmsg from ioctl\n");
                        return -EFAULT;
                }
                if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                        return -ERESTARTSYS;
                if (pollmsg.count == 0) {
                        /* Send wakeup to all waiting polls */
                        /*
                        printk("Waking all fds on %s\n", dnames[dvbdev->type]);
                        */
                        lbdev->poll_waiting = 0;
                        for (i = 0; i < DVBLB_MAXFD; i++)
                                if(lbdev->filemap[i] != 0)
                                        wake_up_interruptible(
                                                        &lbdev->wait_poll[i]);
                } 
                for (i = 0; i < pollmsg.count; i++) {
                        pos = find_filemap(lbdev, pollmsg.file[i]);
                        if (pos >= 0) {
                                /*
                                printk("Sending wakeup command to %p, pos:%d\n",
                                       lbdev->filemap[pos], pos);
                                */
                                lbdev->poll_waiting &= ~(1<<pos);
                                wake_up_interruptible(&lbdev->wait_poll[pos]);
                        }
                }
                mutex_unlock(&lbdev->lock_ioctl);
                return 0;
        }
        if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                return -ERESTARTSYS;
        if (cmd != lbdev->ioctlcmd) {
                // Incorrect response
                printk("dvbloopback: Got wrong response (%u != %lu)\n", cmd,
                       lbdev->ioctlcmd);
                mutex_unlock(&lbdev->lock_ioctl);
                return 0;
        }
        if (cmd < DVBLB_MAX_CMDS)
                size = sizeof(int) + sizeof(struct dvblb_custommsg);
        else if (cmd & IOC_IN)
                size = sizeof(int);
        else
                size = sizeof(int) + _IOC_SIZE(cmd);

        if (copy_from_user(lbdev->ioctlretdata, parg, size)) {
                mutex_unlock(&lbdev->lock_ioctl);
                return -EFAULT;
        }
#if DVB_API_VERSION >=5
        if (cmd == FE_GET_PROPERTY)
        {    
            tvps = (struct dtv_properties __user *)(lbdev->ioctlretdata + sizeof(int));    
            if (copy_from_user(lbdev->ioctlretdata + size, tvps->props,
                         tvps->num * sizeof(struct dtv_property))) 
            {
                mutex_unlock(&lbdev->lock_ioctl);
                return -EFAULT;
            }
            tvps = (struct dtv_properties __user *)(lbdev->ioctlretdata + sizeof(int));
            tvps->props = (struct dtv_property __user *)(lbdev->ioctlretdata + size);
            dprintk("%s() copy_from_user: cmd %u\n", __func__, tvps->props[0].cmd);
        }
#endif

        lbdev->ioctlretval = *(int *)lbdev->ioctlretdata;
        lbdev->ioctlcmd = ULONG_MAX;
        mutex_unlock(&lbdev->lock_ioctl);
        wake_up(&lbdev->wait_ioctl);
        return 0;
}
static int dvblb_looped_ioctl ( struct file *  f,
unsigned int  cmd,
void *  parg 
) [static]

Definition at line 678 of file dvb_loopback.c.

References dvblb::adapter, dnames, dprintk, dvblb_fake_ioctl(), find_filemap(), dvb_device::id, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvb_device::priv, and dvb_device::type.

{
        int ret;
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during ioctl\n");
                return -EFAULT;
        }
        dprintk("dvblb_ioctl %d%s%d fd:%d\n", lbdev->parent->adapter.num,
                dnames[dvbdev->type],
                dvbdev->id, find_filemap(lbdev, filemap));
        ret = dvblb_fake_ioctl(lbdev, filemap, cmd, parg);
        return ret;
}
static int dvblb_mmap ( struct file *  f,
struct vm_area_struct *  vma 
) [static]

Definition at line 838 of file dvb_loopback.c.

References dvblb::adapter, dvblb_devinfo::buffer, dvblb_devinfo::buflen, dnames, dprintk, dvblb_forward_mmap(), dvblb_devinfo::filemap, find_filemap(), dvblb_devinfo::forward_dev, dvb_device::id, dvblb_devinfo::lock_buffer, N_BUFFS, NULL, dvb_adapter::num, PAGE_SIZE, dvblb_devinfo::parent, dvb_device::priv, rvfree(), rvmalloc(), start(), and dvb_device::type.

{
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;
        unsigned long start = (unsigned long)vma->vm_start;
        long size = vma->vm_end - vma->vm_start;
        unsigned long page, pos;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during mmap\n");
                return -EFAULT;
        }
        dprintk("dvblb_mmap %d%s%d fd:%d\n", lbdev->parent->adapter.num,
                dnames[dvbdev->type],
                dvbdev->id, find_filemap(lbdev, filemap));
        if(dvbdev->id == 0) {
                /* This is the looped device */
                if (lbdev->forward_dev)
                        return dvblb_forward_mmap(lbdev, f, vma);

                return -EINVAL;
        }
        /* This is the userspace control device */
        if (!size)
                return -EINVAL;
        if (mutex_lock_interruptible(&lbdev->lock_buffer))
                return -ERESTARTSYS;
        if (lbdev->buffer)
                rvfree(lbdev->buffer, lbdev->buflen*N_BUFFS);
        lbdev->buflen=size;
        lbdev->buffer=rvmalloc(lbdev->buflen*N_BUFFS);

        if (lbdev->buffer == NULL) {
                mutex_unlock(&lbdev->lock_buffer);
                return -EINVAL;
        }

        if (size > (((N_BUFFS * lbdev->buflen) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
                mutex_unlock(&lbdev->lock_buffer);
                return -EINVAL;
        }

        pos = (unsigned long)lbdev->buffer;
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE,
                                 PAGE_SHARED)) {
                        mutex_unlock(&lbdev->lock_buffer);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
                pos += PAGE_SIZE;
                size -= PAGE_SIZE;
        }
        mutex_unlock(&lbdev->lock_buffer);

        return 0;
}
static int dvblb_open ( struct inode *  inode,
struct file *  f 
) [static]

Definition at line 350 of file dvb_loopback.c.

References dvblb::adapter, dvblb_devinfo::dbgfilemap, dnames, dprintk, dvb_generic_open(), DVBLB_CMD_OPEN, dvblb_fake_ioctl(), dvblb_forward_open(), DVBLB_OPEN, dvblb_devinfo::filemap, dvblb_devinfo::forward_dev, get_new_filemap(), dvb_device::id, dvblb_devinfo::ioctlcmd, dvblb_devinfo::ioctllen, dvblb_devinfo::lock_ioctl, dvblb_custommsg::mode, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::pid, dvblb_devinfo::poll_waiting, dvb_device::priv, dvblb_custommsg::type, dvb_device::type, and dvblb_custommsg::u.

{
        struct dvb_device *dvbdev;
        struct dvblb_devinfo *lbdev;
        int ret, map;

        dvbdev  = (struct dvb_device *) f->private_data;
        if (dvbdev == NULL) {
                printk("Failed to open device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during open\n");
                return -EFAULT;
        }
        dprintk("dvblb_open %d%s%d\n", lbdev->parent->adapter.num,
                dnames[dvbdev->type], dvbdev->id);

        if(dvbdev->id == 0) {
                /* This is the looped device */
                struct dvblb_custommsg ci;

                /*must update private_data so we can map fds properly */
                if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                        return -ERESTARTSYS;
                map = get_new_filemap(lbdev, 0);
                if (map < 0) {
                        printk("dvblb_open %s: Failed to set filemap\n",
                               dnames[dvbdev->type]);
                        mutex_unlock(&lbdev->lock_ioctl);
                        return -EBUSY;
                }
                try_module_get(THIS_MODULE);
                lbdev->dbgfilemap[map] = f;
                f->private_data = &lbdev->filemap[map];
                lbdev->poll_waiting = 0;
                mutex_unlock(&lbdev->lock_ioctl);
                dprintk("dvblb_open %s: fd: %d\n", dnames[dvbdev->type], map);
                if (lbdev->forward_dev) {
                        ret = dvblb_forward_open(lbdev, inode, f);
                        if(ret < 0) {
                                module_put(THIS_MODULE);
                                lbdev->filemap[map] = NULL;
                        }
                        return ret;
                }

                if (lbdev->pid == -1) {
                        module_put(THIS_MODULE);
                        lbdev->filemap[map] = NULL;
                        return -EFAULT;
                }
                ci.type = DVBLB_OPEN;
                ci.u.mode = f->f_flags;
                ret = dvblb_fake_ioctl(lbdev, &lbdev->filemap[map],
                                       DVBLB_CMD_OPEN, &ci);
                if(ret < 0) {
                        module_put(THIS_MODULE);
                        lbdev->filemap[map] = NULL;
                }

                return ret;
        }
        /* This is the userspace control device */
        if(lbdev->forward_dev)
                return -EFAULT;
        ret = dvb_generic_open(inode, f);
        if (ret >= 0) {
                lbdev->pid = current->pid;
                lbdev->ioctlcmd = ULONG_MAX;
                lbdev->ioctllen = 0;
                mutex_lock(&lbdev->lock_ioctl);
                memset(lbdev->filemap, 0, sizeof(lbdev->filemap));
                map = get_new_filemap(lbdev, 1);
                if (map < 0) {
                        printk("dvblb_open %s: Failed to set filemap\n",
                               dnames[dvbdev->type]);
                        mutex_unlock(&lbdev->lock_ioctl);
                        return -EBUSY;
                }
                try_module_get(THIS_MODULE);
                f->private_data = &lbdev->filemap[map];
                lbdev->dbgfilemap[map] = f;
                lbdev->poll_waiting = 0;
                mutex_unlock(&lbdev->lock_ioctl);
                dprintk("dvblb_open %s: fd: %d\n", dnames[dvbdev->type], map);
        }
        return ret;
}
static unsigned int dvblb_poll ( struct file *  f,
struct poll_table_struct *  wait 
) [static]

Definition at line 908 of file dvb_loopback.c.

References dvblb::adapter, dnames, dprintk3, DVBLB_CMD_POLL, dvblb_fake_ioctl(), dvblb_forward_poll(), DVBLB_POLL, find_filemap(), dvblb_devinfo::forward_dev, dvb_device::id, dvblb_devinfo::ioctl_already_read, dvblb_devinfo::ioctlcmd, dvblb_devinfo::lock_ioctl, dvblb_custommsg::mode, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::pid, dvblb_devinfo::poll_waiting, dvb_device::priv, dvblb_custommsg::type, dvb_device::type, dvblb_custommsg::u, dvblb_devinfo::wait_poll, and dvblb_devinfo::wait_virt_poll.

{
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during poll\n");
                return -EFAULT;
        }
        dprintk3("dvblb_poll %d%s%d: fd:%d\n", lbdev->parent->adapter.num,
                 dnames[dvbdev->type],
                 dvbdev->id, find_filemap(lbdev, filemap));
        if(dvbdev->id == 0) {
                /* This is the looped device */
                struct dvblb_custommsg ci;
                int ret;
                int do_poll = 1;
                int pos;

                if (lbdev->forward_dev)
                        return dvblb_forward_poll(lbdev, f, wait);

                if (lbdev->pid == -1) {
                        printk("no pid found!\n");
                        return -EFAULT;
                }
                pos = find_filemap(lbdev, filemap);
                if (pos == -1) {
                        printk("dvblb_poll %s: Didn't find filemap!\n",
                               dnames[dvbdev->type]);
                        return -EFAULT;
                }
                poll_wait(f, &lbdev->wait_poll[pos], wait);

                if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                        return -ERESTARTSYS;
                if(lbdev->poll_waiting & (1 << pos))
                        do_poll = 0;
                else /* need to set it before the fake_ioctl to prevent race */
                        lbdev->poll_waiting |= (1 << pos);
                mutex_unlock(&lbdev->lock_ioctl);

                if(do_poll) {
                        ci.type = DVBLB_POLL;
                        ci.u.mode = (wait == NULL) ? 0 : 1;
                        ret = dvblb_fake_ioctl(lbdev, filemap, DVBLB_CMD_POLL,
                                               &ci);
                        if(ret != 0) {
                                if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                                        return -ERESTARTSYS;
                                lbdev->poll_waiting &= ~(1 << pos);
                                mutex_unlock(&lbdev->lock_ioctl);
                                if(ret < 0)
                                        return ret;
                        }
                        if (ci.u.mode & POLLIN)
                                ci.u.mode |= POLLRDNORM;
                } else {
                        ci.u.mode = 0;
                        /*
                        printk("skipping poll on %p (%d)\n", f, pos);
                        */
                }
        dprintk3("dvblb_poll %d%s%d: fd:%d returned: %d\n",
                 lbdev->parent->adapter.num,
                 dnames[dvbdev->type], dvbdev->id, pos, ci.u.mode);
                return(ci.u.mode);
        }

        poll_wait(f, &lbdev->wait_virt_poll, wait);
        if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                return -ERESTARTSYS;
        if (lbdev->ioctlcmd != ULONG_MAX && ! lbdev->ioctl_already_read) {
                mutex_unlock(&lbdev->lock_ioctl);
                return (POLLIN | POLLPRI | POLLRDNORM);
        }
        mutex_unlock(&lbdev->lock_ioctl);
        return 0;
}
static ssize_t dvblb_read ( struct file *  f,
char *  buf,
size_t  count,
loff_t *  offset 
) [static]

Definition at line 548 of file dvb_loopback.c.

References dvblb::adapter, dvblb_devinfo::buffer, dvblb_devinfo::buflen, cmd, count, dvblb_custommsg::count, dnames, dprintk3, DVBLB_CMD_READ, dvblb_fake_ioctl(), dvblb_forward_read(), DVBLB_READ, find_filemap(), dvblb_devinfo::forward_dev, dvb_device::id, dvblb_devinfo::ioctl_already_read, dvblb_devinfo::ioctlcmd, dvblb_devinfo::ioctldata, dvblb_devinfo::ioctlfd, dvblb_devinfo::ioctllen, dvblb_devinfo::lock_buffer, dvblb_devinfo::lock_ioctl, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::pid, dvb_device::priv, dvblb_custommsg::type, dvb_device::type, and dvblb_custommsg::u.

{
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;
#if DVB_API_VERSION >=5
        struct dtv_properties *tvps = NULL;
#endif
        unsigned long int _count = 0;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to find device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during read\n");
                return -EFAULT;
        }
        dprintk3("dvblb_read %d%s%d fd:%d\n", lbdev->parent->adapter.num,
                dnames[dvbdev->type],
                dvbdev->id, find_filemap(lbdev, filemap));
        if(dvbdev->id == 0) {
                /* This is the looped device */
                struct dvblb_custommsg ci;

                if (lbdev->forward_dev)
                        return dvblb_forward_read(lbdev, f, buf, count, offset);

                ci.type = DVBLB_READ;
                ci.u.count = count;
                if (lbdev->pid == -1)
                        return -EFAULT;
                if (mutex_lock_interruptible(&lbdev->lock_buffer))
                        return -ERESTARTSYS;
                if(dvblb_fake_ioctl(lbdev, filemap, DVBLB_CMD_READ, &ci) < 0 ||
                   ! lbdev->buffer) {
                        mutex_unlock(&lbdev->lock_buffer);
                        return 0;
                }
                if (ci.u.count > lbdev->buflen)
                        ci.u.count = lbdev->buflen;
                if (copy_to_user(buf, lbdev->buffer, ci.u.count)) {
                        mutex_unlock(&lbdev->lock_buffer);
                        return -EFAULT;
                }
                mutex_unlock(&lbdev->lock_buffer);
                dprintk3("Read %ld bytes\n", (long)ci.u.count);
                return ci.u.count;
        } else {
                /* This is the userspace control device */
                /* We pass ioctls to the userspace driver this way */
                unsigned long int cmd, base_size, size;
                base_size = sizeof(cmd) + sizeof(lbdev->ioctlfd);
                if (mutex_lock_interruptible(&lbdev->lock_ioctl))
                        return -ERESTARTSYS;

                cmd = lbdev->ioctlcmd;
                size = (lbdev->ioctllen > sizeof(int)) ? lbdev->ioctllen :
                                                         sizeof(int);
#if DVB_API_VERSION >=5
                if ((cmd == FE_GET_PROPERTY) || (cmd == FE_SET_PROPERTY)){
                    tvps = (struct dtv_properties __user *)(lbdev->ioctldata);
                    _count = size + base_size + (tvps->num * sizeof(struct dtv_property));
                }
                else
#endif
                    _count = base_size + size;
                    
                if (count < _count || lbdev->ioctlcmd == ULONG_MAX ||
                    lbdev->ioctl_already_read) {
                        mutex_unlock(&lbdev->lock_ioctl);
                        return -EFAULT;
                }
                if (cmd == ULONG_MAX)
                    count = base_size;
                else
                    count = _count;

                if (copy_to_user(buf, &cmd, sizeof(cmd))) {
                        mutex_unlock(&lbdev->lock_ioctl);
                        return -EFAULT;
                }

                if (copy_to_user(buf + sizeof(cmd), &lbdev->ioctlfd,
                                 sizeof(lbdev->ioctlfd))) {
                        mutex_unlock(&lbdev->lock_ioctl);
                        return -EFAULT;
                }

                if (lbdev->ioctllen == 0) {
                        if (copy_to_user(buf + base_size, &lbdev->ioctldata,
                                         size)) {
                                mutex_unlock(&lbdev->lock_ioctl);
                                return -EFAULT;
                        }
                        
                } else {
#if DVB_API_VERSION >=5
                        if ((cmd == FE_GET_PROPERTY) || (cmd == FE_SET_PROPERTY)) {    
                            if (copy_to_user(buf + base_size + size, tvps->props,
                                         tvps->num * sizeof(struct dtv_property))) {
                                mutex_unlock(&lbdev->lock_ioctl);
                                return -EFAULT;
                            }
                            tvps->props = (struct dtv_property __user *)(buf + base_size + size);
                        }
#endif
                        if (copy_to_user(buf + base_size, lbdev->ioctldata,
                                         size)) {
                                mutex_unlock(&lbdev->lock_ioctl);
                                return -EFAULT;
                        }
                }
                lbdev->ioctl_already_read = 1;
                mutex_unlock(&lbdev->lock_ioctl);
                return count;
        }
}
static int dvblb_release ( struct inode *  inode,
struct file *  f 
) [static]

Definition at line 441 of file dvb_loopback.c.

References dvblb::adapter, dvblb_devinfo::buffer, dvblb_devinfo::buflen, dnames, dprintk, dvb_generic_release(), DVBLB_CLOSE, DVBLB_CMD_CLOSE, dvblb_fake_ioctl(), dvblb_forward_release(), find_filemap(), dvblb_devinfo::forward_dev, dvb_device::id, dvblb_devinfo::lock_buffer, dvblb_devinfo::lock_ioctl, N_BUFFS, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvblb_devinfo::pid, dvblb_devinfo::poll_waiting, dvb_device::priv, rvfree(), dvblb_custommsg::type, and dvb_device::type.

{
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;
        int ret;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during close\n");
                return -EFAULT;
        }
        dprintk("dvblb_release %d%s%d fd:%d\n", lbdev->parent->adapter.num,
                dnames[dvbdev->type],
                dvbdev->id, find_filemap(lbdev, filemap));

        if(dvbdev->id == 0) {
                /* This is the looped device */
                struct dvblb_custommsg ci;

                if (lbdev->forward_dev) {
                        ret = dvblb_forward_release(lbdev, f);
                        *filemap = NULL;
                        goto out;
                }

                if (lbdev->pid == -1) {
                        ret = -EFAULT;
                        goto out;
                }
                ci.type = DVBLB_CLOSE;
                ret = dvblb_fake_ioctl(lbdev, filemap, DVBLB_CMD_CLOSE, &ci);
                if (mutex_lock_interruptible(&lbdev->lock_ioctl)) {
                        ret = -ERESTARTSYS;
                        goto out;
                }
                lbdev->poll_waiting = 0;
                *filemap = NULL;
                mutex_unlock(&lbdev->lock_ioctl);
                goto out;
        }
        /* This is the userspace control device */
        *filemap = NULL;
        f->private_data = dvbdev;
        ret = dvb_generic_release(inode, f);
        if (ret < 0) {
                goto out;
        }
        lbdev->pid = -1;
        if (mutex_lock_interruptible(&lbdev->lock_buffer)) {
                ret = -ERESTARTSYS;
                goto out;
        }
        if (lbdev->buffer) {
                rvfree(lbdev->buffer, lbdev->buflen*N_BUFFS);
                lbdev->buffer = NULL;
        }
        mutex_unlock(&lbdev->lock_buffer);
        ret = 0;
        goto out;

out:
        module_put(THIS_MODULE);
        return ret;
}
static int dvblb_usercopy ( struct file *  file,
unsigned int  cmd,
unsigned long  arg,
int(*)(struct file *file, unsigned int cmd, void *arg)  func 
) [static]

Definition at line 122 of file dvb_loopback.c.

References NULL.

Referenced by dvblb_ioctl().

{
        char    sbuf[128];
        void    *mbuf = NULL;
        void    *parg = NULL;
        int     err  = -EINVAL;
#if DVB_API_VERSION >=5
        struct  dtv_properties *tvps = NULL;
        struct  dtv_property *tvp = NULL;
#endif

        /*  Copy arguments into temp kernel buffer  */
        switch (_IOC_DIR(cmd)) {
        case _IOC_NONE:
                /*
                 * For this command, the pointer is actually an integer
                 * argument.
                 */
                parg = (void *) arg;
                break;
        case _IOC_READ: /* some v4l ioctls are marked wrong ... */
        case _IOC_WRITE:
        case (_IOC_WRITE | _IOC_READ):
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
                        parg = sbuf;
                } else {
                        /* too big to allocate from stack */
                        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
                        if (NULL == mbuf)
                                return -ENOMEM;
                        parg = mbuf;
                }

                err = -EFAULT;
                if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
                        goto out;
#if DVB_API_VERSION >=5
                if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) {
                    tvps = (struct dtv_properties __user *)arg;
                    tvp = (struct dtv_property *) kmalloc(tvps->num *
                        sizeof(struct dtv_property), GFP_KERNEL);
                    if (!tvp){
                        err = -ENOMEM;
                        goto out;
                    }
                    if (copy_from_user(tvp, tvps->props, 
                        (tvps->num) * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                    }
                    tvps = (struct dtv_properties __user *)parg;
                    tvps->props = tvp;
                    tvp = NULL;
                }
#endif
                break;
        }

        /* call driver */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
        if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
#else
        if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
#endif
                err = -EINVAL;

        if (err < 0)
                goto out;

        /*  Copy results into user buffer  */
        switch (_IOC_DIR(cmd))
        {
        case _IOC_READ:
        case (_IOC_WRITE | _IOC_READ):
#if DVB_API_VERSION >=5
                if ((cmd == FE_GET_PROPERTY) || (cmd == FE_SET_PROPERTY)) 
                {
                    tvps = (struct dtv_properties __user *)arg;
                    tvp = tvps->props;
                    tvps = (struct dtv_properties __user *)parg;
                    if (copy_to_user(tvp, tvps->props, tvps->num * 
                            sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                    }
                    tvps->props = tvp;
                }
#endif
                if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
                        err = -EFAULT;
                break;
        }

out:
        kfree(mbuf);
        return err;
}
static ssize_t dvblb_write ( struct file *  f,
const char *  buf,
size_t  count,
loff_t *  offset 
) [static]

Definition at line 516 of file dvb_loopback.c.

References dvblb::adapter, dnames, dprintk3, dvblb_forward_write(), find_filemap(), dvblb_devinfo::forward_dev, dvb_device::id, NULL, dvb_adapter::num, dvblb_devinfo::parent, dvb_device::priv, and dvb_device::type.

{
        struct dvb_device *dvbdev, **filemap;
        struct dvblb_devinfo *lbdev;

        filemap  = (struct dvb_device **) f->private_data;
        if(filemap == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        dvbdev = *filemap;
        if (dvbdev == NULL) {
                printk("Failed to locate device\n");
                return -EFAULT;
        }
        lbdev = (struct dvblb_devinfo *)dvbdev->priv;
        if (lbdev == NULL) {
                printk("Failed to find private data during close\n");
                return -EFAULT;
        }
        dprintk3("dvblb_write %d%s%d fd:%d\n", lbdev->parent->adapter.num,
                dnames[dvbdev->type],
                dvbdev->id, find_filemap(lbdev, filemap));

        if (lbdev->forward_dev)
                return dvblb_forward_write(lbdev, f, buf, count, offset);

        printk("Write not supported on loopback device\n");
        return -EFAULT;
}
static int find_filemap ( struct dvblb_devinfo *  lbdev,
struct dvb_device **  fm 
) [static]

Definition at line 244 of file dvb_loopback.c.

References DVBLB_MAXFD, dvblb_devinfo::filemap, and i.

Referenced by dvblb_ioctl(), dvblb_looped_ioctl(), dvblb_mmap(), dvblb_poll(), dvblb_read(), dvblb_release(), and dvblb_write().

                                                                             {
        int i;
        for(i = 0; i < DVBLB_MAXFD; i++)
                if(&lbdev->filemap[i] == fm)
                        return i;
        return -1;
}
static int get_new_filemap ( struct dvblb_devinfo *  lbdev,
int  id 
) [static]

Definition at line 229 of file dvb_loopback.c.

References DVBLB_MAXFD, dvblb_devinfo::filemap, i, dvblb_devinfo::lb_dev, NULL, and dvblb_devinfo::user_dev.

Referenced by dvblb_open().

                                                                {
        int i;
        for(i = 0; i < DVBLB_MAXFD; i++)
        {
                if(lbdev->filemap[i] == NULL) {
                        if(id)
                                lbdev->filemap[i] = lbdev->user_dev;
                        else
                                lbdev->filemap[i] = lbdev->lb_dev;
                        return i;
                }
        }
        return -1;
}
int inuse_filemap ( struct dvblb_devinfo *  lbdev)

Definition at line 252 of file dvb_loopback.c.

References count, DVBLB_MAXFD, dvblb_devinfo::filemap, i, and NULL.

Referenced by dvblb_procfs_adapter_write(), and dvblb_procfs_write().

                                               {
        int i, count = 0;
        for(i = 0; i < DVBLB_MAXFD; i++)
                if(lbdev->filemap[i] != NULL)
                        count++;
        return count;
}
MODULE_AUTHOR ( "Alan Nisota"  )
MODULE_DESCRIPTION ( "DVB loopback device."  )
module_exit ( cleanup_dvblb_module  )
module_init ( dvblb_init  )
MODULE_LICENSE ( "GPL"  )
module_param ( num_adapters  ,
int  ,
S_IRUGO   
)
module_param ( dvblb_debug  ,
int  ,
S_IRUGO|  S_IWUSR 
)
MODULE_VERSION ( DVBLOOPBACK_VERSION  )
static void rvfree ( void *  mem,
unsigned long  size 
) [static]

Definition at line 102 of file dvb_loopback.c.

References PAGE_SIZE.

Referenced by destroy_lb_dev(), dvblb_mmap(), and dvblb_release().

{
        unsigned long adr;

        if (!mem)
                return;

        adr = (unsigned long) mem;
        while ((long) size > 0) {
                ClearPageReserved(vmalloc_to_page((void *)adr));
                adr += PAGE_SIZE;
                size -= PAGE_SIZE;
        }
        vfree(mem);
}
static void* rvmalloc ( unsigned long  size) [static]

Definition at line 82 of file dvb_loopback.c.

References NULL, and PAGE_SIZE.

Referenced by dvblb_mmap().

{
        void *mem;
        unsigned long adr;

        size = PAGE_ALIGN(size);
        mem = vmalloc_32(size);
        if (!mem)
                return NULL;
        memset(mem, 0, size); /* Clear the ram out, no junk to the user */
        adr = (unsigned long) mem;
        while (size > 0) {
                SetPageReserved(vmalloc_to_page((void *)adr));
                adr += PAGE_SIZE;
                size -= PAGE_SIZE;
        }

        return mem;
}

Variable Documentation

struct dvb_device dvbdev_looped [static]
Initial value:
 {
        .priv = NULL,
        .users = DVBLB_MAXFD,
        .readers = 1,
        .writers = 1,
        .fops = &dvbdev_looped_fops,
        .kernel_ioctl  = dvblb_looped_ioctl,
}

Definition at line 1014 of file dvb_loopback.c.

struct file_operations dvbdev_looped_fops [static]
Initial value:
 {
        .owner          = THIS_MODULE,
        .open           = dvblb_open,
        .release        = dvblb_release,
        .read           = dvblb_read,
        .write          = dvblb_write,
        .poll           = dvblb_poll,
        .mmap           = dvblb_mmap,

        .unlocked_ioctl = dvblb_ioctl,



}

Definition at line 999 of file dvb_loopback.c.

struct dvb_device dvbdev_userspace [static]
Initial value:
 {
        .priv = NULL,
        .users = 1,
        .readers = 1,
        .writers = 1,
        .fops = &dvbdev_userspace_fops,
        .kernel_ioctl  = dvblb_looped_ioctl,
}

Definition at line 1038 of file dvb_loopback.c.

struct file_operations dvbdev_userspace_fops [static]
Initial value:
 {
        .owner          = THIS_MODULE,
        .open           = dvblb_open,
        .release        = dvblb_release,
        .read           = dvblb_read,
        .write          = dvblb_write,
        .poll           = dvblb_poll,
        .mmap           = dvblb_mmap,

        .unlocked_ioctl = dvblb_ioctl,



}

Definition at line 1023 of file dvb_loopback.c.

struct platform_device* dvblb_basedev [static]

Definition at line 1147 of file dvb_loopback.c.

int dvblb_debug = 0 [static]

Definition at line 75 of file dvb_loopback.c.

struct dvblb* dvblb_global [static]

Definition at line 80 of file dvb_loopback.c.

int num_adapters = 1 [static]

Definition at line 76 of file dvb_loopback.c.

Referenced by cleanup_dvblb_module(), and dvblb_init().

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines