X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Fdvb-core%2Fdvbdev.c;h=b3a8cbbda62191e203ec257b7885f7ceb9f70ad6;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=686ffc229eec2caa9d1f440d8ce6f40ad7aa955d;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 686ffc229..b3a8cbbda 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -1,4 +1,4 @@ -/* +/* * dvbdev.c * * Copyright (C) 2000 Ralph Metzler @@ -25,29 +25,38 @@ #include #include #include +#include #include #include #include #include - +#include +#include +#include +#include #include "dvbdev.h" -#include "dvb_functions.h" -static int dvbdev_debug = 0; +static int dvbdev_debug; + +module_param(dvbdev_debug, int, 0644); +MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); + #define dprintk if (dvbdev_debug) printk static LIST_HEAD(dvb_adapter_list); -static DECLARE_MUTEX(dvbdev_register_lock); +static DEFINE_MUTEX(dvbdev_register_lock); - -static char *dnames[] = { - "video", "audio", "sec", "frontend", "demux", "dvr", "ca", +static const char * const dnames[] = { + "video", "audio", "sec", "frontend", "demux", "dvr", "ca", "net", "osd" }; +#define DVB_MAX_ADAPTERS 8 +#define DVB_MAX_IDS 4 +#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) +#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) -#define DVB_MAX_IDS 4 -#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) +static struct class *dvb_class; static struct dvb_device* dvbdev_find_device (int minor) { @@ -72,24 +81,24 @@ static struct dvb_device* dvbdev_find_device (int minor) static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; - + dvbdev = dvbdev_find_device (iminor(inode)); if (dvbdev && dvbdev->fops) { int err = 0; - struct file_operations *old_fops; + const struct file_operations *old_fops; file->private_data = dvbdev; old_fops = file->f_op; - file->f_op = fops_get(dvbdev->fops); - if(file->f_op->open) - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - return err; + file->f_op = fops_get(dvbdev->fops); + if(file->f_op->open) + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + return err; } return -ENODEV; } @@ -101,38 +110,43 @@ static struct file_operations dvb_device_fops = .open = dvb_device_open, }; +static struct cdev dvb_device_cdev = { + .kobj = {.name = "dvb", }, + .owner = THIS_MODULE, +}; int dvb_generic_open(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; - if (!dvbdev) - return -ENODEV; + if (!dvbdev) + return -ENODEV; if (!dvbdev->users) - return -EBUSY; + return -EBUSY; if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if (!dvbdev->readers) - return -EBUSY; + if (!dvbdev->readers) + return -EBUSY; dvbdev->readers--; } else { - if (!dvbdev->writers) - return -EBUSY; + if (!dvbdev->writers) + return -EBUSY; dvbdev->writers--; } dvbdev->users--; return 0; } +EXPORT_SYMBOL(dvb_generic_open); int dvb_generic_release(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; if (!dvbdev) - return -ENODEV; + return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY) { dvbdev->readers++; @@ -143,21 +157,23 @@ int dvb_generic_release(struct inode *inode, struct file *file) dvbdev->users++; return 0; } +EXPORT_SYMBOL(dvb_generic_release); int dvb_generic_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct dvb_device *dvbdev = file->private_data; - - if (!dvbdev) - return -ENODEV; + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; if (!dvbdev->kernel_ioctl) return -EINVAL; return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); } +EXPORT_SYMBOL(dvb_generic_ioctl); static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) @@ -180,17 +196,18 @@ skip: } -int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, +int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, int type) { struct dvb_device *dvbdev; + struct file_operations *dvbdevfops; + int id; - if (down_interruptible (&dvbdev_register_lock)) - return -ERESTARTSYS; + mutex_lock(&dvbdev_register_lock); if ((id = dvbdev_get_free_id (adap, type)) < 0) { - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; printk ("%s: could get find free device id...\n", __FUNCTION__); return -ENFILE; @@ -199,25 +216,34 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); if (!dvbdev) { - up(&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } + + dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + + if (!dvbdevfops) { + kfree (dvbdev); + mutex_unlock(&dvbdev_register_lock); return -ENOMEM; } - up (&dvbdev_register_lock); - memcpy(dvbdev, template, sizeof(struct dvb_device)); dvbdev->type = type; dvbdev->id = id; dvbdev->adapter = adap; dvbdev->priv = priv; + dvbdev->fops = dvbdevfops; + memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations)); dvbdev->fops->owner = adap->module; list_add_tail (&dvbdev->list_head, &adap->device_list); - devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - S_IFCHR | S_IRUSR | S_IWUSR, - "dvb/adapter%d/%s%d", adap->num, dnames[type], id); + 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); dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, nums2minor(adap->num, type, id), @@ -225,6 +251,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return 0; } +EXPORT_SYMBOL(dvb_register_device); void dvb_unregister_device(struct dvb_device *dvbdev) @@ -232,19 +259,21 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, - dnames[dvbdev->type], dvbdev->id); + class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, + dvbdev->type, dvbdev->id))); - list_del(&dvbdev->list_head); - kfree(dvbdev); - } + list_del (&dvbdev->list_head); + kfree (dvbdev->fops); + kfree (dvbdev); +} +EXPORT_SYMBOL(dvb_unregister_device); static int dvbdev_get_free_adapter_num (void) { int num = 0; - while (1) { + while (num < DVB_MAX_ADAPTERS) { struct list_head *entry; list_for_each (entry, &dvb_adapter_list) { struct dvb_adapter *adap; @@ -261,72 +290,145 @@ skip: } -int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module) +int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device) { - struct dvb_adapter *adap; int num; - if (down_interruptible (&dvbdev_register_lock)) - return -ERESTARTSYS; + mutex_lock(&dvbdev_register_lock); if ((num = dvbdev_get_free_adapter_num ()) < 0) { - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); return -ENFILE; } - if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) { - up(&dvbdev_register_lock); - return -ENOMEM; - } - memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); printk ("DVB: registering new adapter (%s).\n", name); - - devfs_mk_dir("dvb/adapter%d", num); adap->num = num; adap->name = name; adap->module = module; + adap->device = device; list_add_tail (&adap->list_head, &dvb_adapter_list); - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); return num; } +EXPORT_SYMBOL(dvb_register_adapter); int dvb_unregister_adapter(struct dvb_adapter *adap) { - if (down_interruptible (&dvbdev_register_lock)) - return -ERESTARTSYS; - devfs_remove("dvb/adapter%d", adap->num); + mutex_lock(&dvbdev_register_lock); list_del (&adap->list_head); - up (&dvbdev_register_lock); - kfree (adap); + mutex_unlock(&dvbdev_register_lock); return 0; } +EXPORT_SYMBOL(dvb_unregister_adapter); + +/* if the miracle happens and "generic_usercopy()" is included into + the kernel, then this can vanish. please don't make the mistake and + define this as video_usercopy(). this will introduce a dependecy + to the v4l "videodev.o" module, which is unnecessary for some + cards (ie. the budget dvb-cards don't need the v4l module...) */ +int dvb_usercopy(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg)) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + /* 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; + break; + } + + /* call driver */ + if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) + 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 (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } +out: + kfree(mbuf); + return err; +} static int __init init_dvbdev(void) { int retval; - devfs_mk_dir("dvb"); + dev_t dev = MKDEV(DVB_MAJOR, 0); - retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops); - if (retval) - printk("video_dev: unable to get major %d\n", DVB_MAJOR); + if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { + printk("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); + goto error; + } + + dvb_class = class_create(THIS_MODULE, "dvb"); + if (IS_ERR(dvb_class)) { + retval = PTR_ERR(dvb_class); + goto error; + } + return 0; + +error: + cdev_del(&dvb_device_cdev); + unregister_chrdev_region(dev, MAX_DVB_MINORS); return retval; } static void __exit exit_dvbdev(void) { - unregister_chrdev(DVB_MAJOR, "DVB"); - devfs_remove("dvb"); + class_destroy(dvb_class); + cdev_del(&dvb_device_cdev); + unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); } module_init(init_dvbdev); @@ -335,7 +437,3 @@ module_exit(exit_dvbdev); MODULE_DESCRIPTION("DVB Core Driver"); MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); MODULE_LICENSE("GPL"); - -MODULE_PARM(dvbdev_debug,"i"); -MODULE_PARM_DESC(dvbdev_debug, "enable verbose debug messages"); -