linux/drivers/media/dvb/dvb-core/dvbdev.c
<<
>>
Prefs
   1/*
   2 * dvbdev.c
   3 *
   4 * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
   5 *                  & Marcus Metzler <marcus@convergence.de>
   6 *                    for convergence integrated media GmbH
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU Lesser General Public License
  10 * as published by the Free Software Foundation; either version 2.1
  11 * of the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU Lesser General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21 *
  22 */
  23
  24#include <linux/types.h>
  25#include <linux/errno.h>
  26#include <linux/string.h>
  27#include <linux/module.h>
  28#include <linux/kernel.h>
  29#include <linux/init.h>
  30#include <linux/slab.h>
  31#include <linux/device.h>
  32#include <linux/fs.h>
  33#include <linux/cdev.h>
  34#include <linux/mutex.h>
  35#include <linux/smp_lock.h>
  36#include "dvbdev.h"
  37
  38static int dvbdev_debug;
  39
  40module_param(dvbdev_debug, int, 0644);
  41MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
  42
  43#define dprintk if (dvbdev_debug) printk
  44
  45static LIST_HEAD(dvb_adapter_list);
  46static DEFINE_MUTEX(dvbdev_register_lock);
  47
  48static const char * const dnames[] = {
  49        "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
  50        "net", "osd"
  51};
  52
  53#ifdef CONFIG_DVB_DYNAMIC_MINORS
  54#define MAX_DVB_MINORS          256
  55#define DVB_MAX_IDS             MAX_DVB_MINORS
  56#else
  57#define DVB_MAX_IDS             4
  58#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
  59#define MAX_DVB_MINORS          (DVB_MAX_ADAPTERS*64)
  60#endif
  61
  62static struct class *dvb_class;
  63
  64static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
  65static DECLARE_RWSEM(minor_rwsem);
  66
  67static int dvb_device_open(struct inode *inode, struct file *file)
  68{
  69        struct dvb_device *dvbdev;
  70
  71        lock_kernel();
  72        down_read(&minor_rwsem);
  73        dvbdev = dvb_minors[iminor(inode)];
  74
  75        if (dvbdev && dvbdev->fops) {
  76                int err = 0;
  77                const struct file_operations *old_fops;
  78
  79                file->private_data = dvbdev;
  80                old_fops = file->f_op;
  81                file->f_op = fops_get(dvbdev->fops);
  82                if (file->f_op == NULL) {
  83                        file->f_op = old_fops;
  84                        goto fail;
  85                }
  86                if(file->f_op->open)
  87                        err = file->f_op->open(inode,file);
  88                if (err) {
  89                        fops_put(file->f_op);
  90                        file->f_op = fops_get(old_fops);
  91                }
  92                fops_put(old_fops);
  93                up_read(&minor_rwsem);
  94                unlock_kernel();
  95                return err;
  96        }
  97fail:
  98        up_read(&minor_rwsem);
  99        unlock_kernel();
 100        return -ENODEV;
 101}
 102
 103
 104static const struct file_operations dvb_device_fops =
 105{
 106        .owner =        THIS_MODULE,
 107        .open =         dvb_device_open,
 108};
 109
 110static struct cdev dvb_device_cdev;
 111
 112int dvb_generic_open(struct inode *inode, struct file *file)
 113{
 114        struct dvb_device *dvbdev = file->private_data;
 115
 116        if (!dvbdev)
 117                return -ENODEV;
 118
 119        if (!dvbdev->users)
 120                return -EBUSY;
 121
 122        if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 123                if (!dvbdev->readers)
 124                        return -EBUSY;
 125                dvbdev->readers--;
 126        } else {
 127                if (!dvbdev->writers)
 128                        return -EBUSY;
 129                dvbdev->writers--;
 130        }
 131
 132        dvbdev->users--;
 133        return 0;
 134}
 135EXPORT_SYMBOL(dvb_generic_open);
 136
 137
 138int dvb_generic_release(struct inode *inode, struct file *file)
 139{
 140        struct dvb_device *dvbdev = file->private_data;
 141
 142        if (!dvbdev)
 143                return -ENODEV;
 144
 145        if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 146                dvbdev->readers++;
 147        } else {
 148                dvbdev->writers++;
 149        }
 150
 151        dvbdev->users++;
 152        return 0;
 153}
 154EXPORT_SYMBOL(dvb_generic_release);
 155
 156
 157long dvb_generic_ioctl(struct file *file,
 158                       unsigned int cmd, unsigned long arg)
 159{
 160        struct dvb_device *dvbdev = file->private_data;
 161        int ret;
 162
 163        if (!dvbdev)
 164                return -ENODEV;
 165
 166        if (!dvbdev->kernel_ioctl)
 167                return -EINVAL;
 168
 169        lock_kernel();
 170        ret = dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
 171        unlock_kernel();
 172
 173        return ret;
 174}
 175EXPORT_SYMBOL(dvb_generic_ioctl);
 176
 177
 178static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
 179{
 180        u32 id = 0;
 181
 182        while (id < DVB_MAX_IDS) {
 183                struct dvb_device *dev;
 184                list_for_each_entry(dev, &adap->device_list, list_head)
 185                        if (dev->type == type && dev->id == id)
 186                                goto skip;
 187                return id;
 188skip:
 189                id++;
 190        }
 191        return -ENFILE;
 192}
 193
 194
 195int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 196                        const struct dvb_device *template, void *priv, int type)
 197{
 198        struct dvb_device *dvbdev;
 199        struct file_operations *dvbdevfops;
 200        struct device *clsdev;
 201        int minor;
 202        int id;
 203
 204        mutex_lock(&dvbdev_register_lock);
 205
 206        if ((id = dvbdev_get_free_id (adap, type)) < 0){
 207                mutex_unlock(&dvbdev_register_lock);
 208                *pdvbdev = NULL;
 209                printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
 210                return -ENFILE;
 211        }
 212
 213        *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
 214
 215        if (!dvbdev){
 216                mutex_unlock(&dvbdev_register_lock);
 217                return -ENOMEM;
 218        }
 219
 220        dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
 221
 222        if (!dvbdevfops){
 223                kfree (dvbdev);
 224                mutex_unlock(&dvbdev_register_lock);
 225                return -ENOMEM;
 226        }
 227
 228        memcpy(dvbdev, template, sizeof(struct dvb_device));
 229        dvbdev->type = type;
 230        dvbdev->id = id;
 231        dvbdev->adapter = adap;
 232        dvbdev->priv = priv;
 233        dvbdev->fops = dvbdevfops;
 234        init_waitqueue_head (&dvbdev->wait_queue);
 235
 236        memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
 237        dvbdevfops->owner = adap->module;
 238
 239        list_add_tail (&dvbdev->list_head, &adap->device_list);
 240
 241        down_write(&minor_rwsem);
 242#ifdef CONFIG_DVB_DYNAMIC_MINORS
 243        for (minor = 0; minor < MAX_DVB_MINORS; minor++)
 244                if (dvb_minors[minor] == NULL)
 245                        break;
 246
 247        if (minor == MAX_DVB_MINORS) {
 248                kfree(dvbdevfops);
 249                kfree(dvbdev);
 250                mutex_unlock(&dvbdev_register_lock);
 251                return -EINVAL;
 252        }
 253#else
 254        minor = nums2minor(adap->num, type, id);
 255#endif
 256
 257        dvbdev->minor = minor;
 258        dvb_minors[minor] = dvbdev;
 259        up_write(&minor_rwsem);
 260
 261        mutex_unlock(&dvbdev_register_lock);
 262
 263        clsdev = device_create(dvb_class, adap->device,
 264                               MKDEV(DVB_MAJOR, minor),
 265                               dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
 266        if (IS_ERR(clsdev)) {
 267                printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
 268                       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
 269                return PTR_ERR(clsdev);
 270        }
 271
 272        dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 273                adap->num, dnames[type], id, minor, minor);
 274
 275        return 0;
 276}
 277EXPORT_SYMBOL(dvb_register_device);
 278
 279
 280void dvb_unregister_device(struct dvb_device *dvbdev)
 281{
 282        if (!dvbdev)
 283                return;
 284
 285        down_write(&minor_rwsem);
 286        dvb_minors[dvbdev->minor] = NULL;
 287        up_write(&minor_rwsem);
 288
 289        device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
 290
 291        list_del (&dvbdev->list_head);
 292        kfree (dvbdev->fops);
 293        kfree (dvbdev);
 294}
 295EXPORT_SYMBOL(dvb_unregister_device);
 296
 297static int dvbdev_check_free_adapter_num(int num)
 298{
 299        struct list_head *entry;
 300        list_for_each(entry, &dvb_adapter_list) {
 301                struct dvb_adapter *adap;
 302                adap = list_entry(entry, struct dvb_adapter, list_head);
 303                if (adap->num == num)
 304                        return 0;
 305        }
 306        return 1;
 307}
 308
 309static int dvbdev_get_free_adapter_num (void)
 310{
 311        int num = 0;
 312
 313        while (num < DVB_MAX_ADAPTERS) {
 314                if (dvbdev_check_free_adapter_num(num))
 315                        return num;
 316                num++;
 317        }
 318
 319        return -ENFILE;
 320}
 321
 322
 323int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
 324                         struct module *module, struct device *device,
 325                         short *adapter_nums)
 326{
 327        int i, num;
 328
 329        mutex_lock(&dvbdev_register_lock);
 330
 331        for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
 332                num = adapter_nums[i];
 333                if (num >= 0  &&  num < DVB_MAX_ADAPTERS) {
 334                /* use the one the driver asked for */
 335                        if (dvbdev_check_free_adapter_num(num))
 336                                break;
 337                } else {
 338                        num = dvbdev_get_free_adapter_num();
 339                        break;
 340                }
 341                num = -1;
 342        }
 343
 344        if (num < 0) {
 345                mutex_unlock(&dvbdev_register_lock);
 346                return -ENFILE;
 347        }
 348
 349        memset (adap, 0, sizeof(struct dvb_adapter));
 350        INIT_LIST_HEAD (&adap->device_list);
 351
 352        printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
 353
 354        adap->num = num;
 355        adap->name = name;
 356        adap->module = module;
 357        adap->device = device;
 358        adap->mfe_shared = 0;
 359        adap->mfe_dvbdev = NULL;
 360        mutex_init (&adap->mfe_lock);
 361
 362        list_add_tail (&adap->list_head, &dvb_adapter_list);
 363
 364        mutex_unlock(&dvbdev_register_lock);
 365
 366        return num;
 367}
 368EXPORT_SYMBOL(dvb_register_adapter);
 369
 370
 371int dvb_unregister_adapter(struct dvb_adapter *adap)
 372{
 373        mutex_lock(&dvbdev_register_lock);
 374        list_del (&adap->list_head);
 375        mutex_unlock(&dvbdev_register_lock);
 376        return 0;
 377}
 378EXPORT_SYMBOL(dvb_unregister_adapter);
 379
 380/* if the miracle happens and "generic_usercopy()" is included into
 381   the kernel, then this can vanish. please don't make the mistake and
 382   define this as video_usercopy(). this will introduce a dependecy
 383   to the v4l "videodev.o" module, which is unnecessary for some
 384   cards (ie. the budget dvb-cards don't need the v4l module...) */
 385int dvb_usercopy(struct file *file,
 386                     unsigned int cmd, unsigned long arg,
 387                     int (*func)(struct file *file,
 388                     unsigned int cmd, void *arg))
 389{
 390        char    sbuf[128];
 391        void    *mbuf = NULL;
 392        void    *parg = NULL;
 393        int     err  = -EINVAL;
 394
 395        /*  Copy arguments into temp kernel buffer  */
 396        switch (_IOC_DIR(cmd)) {
 397        case _IOC_NONE:
 398                /*
 399                 * For this command, the pointer is actually an integer
 400                 * argument.
 401                 */
 402                parg = (void *) arg;
 403                break;
 404        case _IOC_READ: /* some v4l ioctls are marked wrong ... */
 405        case _IOC_WRITE:
 406        case (_IOC_WRITE | _IOC_READ):
 407                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
 408                        parg = sbuf;
 409                } else {
 410                        /* too big to allocate from stack */
 411                        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
 412                        if (NULL == mbuf)
 413                                return -ENOMEM;
 414                        parg = mbuf;
 415                }
 416
 417                err = -EFAULT;
 418                if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
 419                        goto out;
 420                break;
 421        }
 422
 423        /* call driver */
 424        if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
 425                err = -EINVAL;
 426
 427        if (err < 0)
 428                goto out;
 429
 430        /*  Copy results into user buffer  */
 431        switch (_IOC_DIR(cmd))
 432        {
 433        case _IOC_READ:
 434        case (_IOC_WRITE | _IOC_READ):
 435                if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
 436                        err = -EFAULT;
 437                break;
 438        }
 439
 440out:
 441        kfree(mbuf);
 442        return err;
 443}
 444
 445static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
 446{
 447        struct dvb_device *dvbdev = dev_get_drvdata(dev);
 448
 449        add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
 450        add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
 451        add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
 452        return 0;
 453}
 454
 455static char *dvb_devnode(struct device *dev, mode_t *mode)
 456{
 457        struct dvb_device *dvbdev = dev_get_drvdata(dev);
 458
 459        return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
 460                dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
 461}
 462
 463
 464static int __init init_dvbdev(void)
 465{
 466        int retval;
 467        dev_t dev = MKDEV(DVB_MAJOR, 0);
 468
 469        if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
 470                printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
 471                return retval;
 472        }
 473
 474        cdev_init(&dvb_device_cdev, &dvb_device_fops);
 475        if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
 476                printk(KERN_ERR "dvb-core: unable register character device\n");
 477                goto error;
 478        }
 479
 480        dvb_class = class_create(THIS_MODULE, "dvb");
 481        if (IS_ERR(dvb_class)) {
 482                retval = PTR_ERR(dvb_class);
 483                goto error;
 484        }
 485        dvb_class->dev_uevent = dvb_uevent;
 486        dvb_class->devnode = dvb_devnode;
 487        return 0;
 488
 489error:
 490        cdev_del(&dvb_device_cdev);
 491        unregister_chrdev_region(dev, MAX_DVB_MINORS);
 492        return retval;
 493}
 494
 495
 496static void __exit exit_dvbdev(void)
 497{
 498        class_destroy(dvb_class);
 499        cdev_del(&dvb_device_cdev);
 500        unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
 501}
 502
 503subsys_initcall(init_dvbdev);
 504module_exit(exit_dvbdev);
 505
 506MODULE_DESCRIPTION("DVB Core Driver");
 507MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
 508MODULE_LICENSE("GPL");
 509
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.