/* * dvbdev.c * * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> * & Marcus Metzler <marcus@convergence.de> * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include <linux/types.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/device.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/mutex.h>#include "dvbdev.h" static DEFINE_MUTEX(dvbdev_mutex);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 DEFINE_MUTEX(dvbdev_register_lock); static const char * const dnames[] = { "video", "audio", "sec", "frontend", "demux", "dvr", "ca", "net", "osd"}; #ifdef CONFIG_DVB_DYNAMIC_MINORS#define MAX_DVB_MINORS 256#define DVB_MAX_IDS MAX_DVB_MINORS#else#define DVB_MAX_IDS 4#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)#endif static struct class *dvb_class; static struct dvb_device *dvb_minors[MAX_DVB_MINORS];static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file){ struct dvb_device *dvbdev; mutex_lock(&dvbdev_mutex); down_read(&minor_rwsem); dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; const struct file_operations *new_fops; new_fops = fops_get(dvbdev->fops); if (!new_fops) goto fail; file->private_data = dvbdev; replace_fops(file, new_fops); if (file->f_op->open) err = file->f_op->open(inode,file); up_read(&minor_rwsem); mutex_unlock(&dvbdev_mutex); return err; }fail: up_read(&minor_rwsem); mutex_unlock(&dvbdev_mutex); return -ENODEV;} static const struct file_operations dvb_device_fops ={ .owner = THIS_MODULE, .open = dvb_device_open, .llseek = noop_llseek,}; static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file){ struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; if (!dvbdev->users) return -EBUSY; if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (!dvbdev->readers) return -EBUSY; dvbdev->readers--; } else { 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; if (!dvbdev) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY) { dvbdev->readers++; } else { dvbdev->writers++; } dvbdev->users++; return 0;}EXPORT_SYMBOL(dvb_generic_release); long dvb_generic_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; if (!dvbdev->kernel_ioctl) return -EINVAL; return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);}EXPORT_SYMBOL(dvb_generic_ioctl); static int dvbdev_get_free_id (struct dvb_adapter *adap, int type){ u32 id = 0; while (id < DVB_MAX_IDS) { struct dvb_device *dev; list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; return id;skip: id++; } return -ENFILE;} static void dvb_register_media_device(struct dvb_device *dvbdev, int type, int minor){#if defined(CONFIG_MEDIA_CONTROLLER_DVB) int ret = 0, npads; if (!dvbdev->adapter->mdev) return; dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); if (!dvbdev->entity) return; dvbdev->entity->info.dev.major = DVB_MAJOR; dvbdev->entity->info.dev.minor = minor; dvbdev->entity->name = dvbdev->name; switch (type) { case DVB_DEVICE_CA: case DVB_DEVICE_DEMUX: case DVB_DEVICE_FRONTEND: npads = 2; break; case DVB_DEVICE_NET: npads = 0; break; default: npads = 1; } if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); if (!dvbdev->pads) { kfree(dvbdev->entity); return; } } switch (type) { case DVB_DEVICE_FRONTEND: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_DEMUX: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_DVR: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; break; case DVB_DEVICE_CA: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_NET: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET; break; default: kfree(dvbdev->entity); dvbdev->entity = NULL; return; } if (npads) ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0); if (!ret) ret = media_device_register_entity(dvbdev->adapter->mdev, dvbdev->entity); if (ret < 0) { printk(KERN_ERR "%s: media_device_register_entity failed for %s\n", __func__, dvbdev->entity->name); kfree(dvbdev->pads); kfree(dvbdev->entity); dvbdev->entity = NULL; return; } printk(KERN_DEBUG "%s: media device '%s' registered.\n", __func__, dvbdev->entity->name);#endif} 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; struct device *clsdev; int minor; int id; mutex_lock(&dvbdev_register_lock); if ((id = dvbdev_get_free_id (adap, type)) < 0){ mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; printk(KERN_ERR "%s: couldn't find free device id\n", __func__); return -ENFILE; } *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); if (!dvbdev){ 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; } memcpy(dvbdev, template, sizeof(struct dvb_device)); dvbdev->type = type; dvbdev->id = id; dvbdev->adapter = adap; dvbdev->priv = priv; dvbdev->fops = dvbdevfops; init_waitqueue_head (&dvbdev->wait_queue); memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); dvbdevfops->owner = adap->module; list_add_tail (&dvbdev->list_head, &adap->device_list); down_write(&minor_rwsem);#ifdef CONFIG_DVB_DYNAMIC_MINORS for (minor = 0; minor < MAX_DVB_MINORS; minor++) if (dvb_minors[minor] == NULL) break; if (minor == MAX_DVB_MINORS) { kfree(dvbdevfops); kfree(dvbdev); up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return -EINVAL; }#else minor = nums2minor(adap->num, type, id);#endif dvbdev->minor = minor; dvb_minors[minor] = dvbdev; up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); clsdev = device_create(dvb_class, adap->device, MKDEV(DVB_MAJOR, minor), dvbdev, "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", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); return PTR_ERR(clsdev); } dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); dvb_register_media_device(dvbdev, type, minor); return 0;}EXPORT_SYMBOL(dvb_register_device); void dvb_unregister_device(struct dvb_device *dvbdev){ if (!dvbdev) return; down_write(&minor_rwsem); dvb_minors[dvbdev->minor] = NULL; up_write(&minor_rwsem); device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); #if defined(CONFIG_MEDIA_CONTROLLER_DVB) if (dvbdev->entity) { media_device_unregister_entity(dvbdev->entity); kfree(dvbdev->entity); kfree(dvbdev->pads); }#endif list_del (&dvbdev->list_head); kfree (dvbdev->fops); kfree (dvbdev);}EXPORT_SYMBOL(dvb_unregister_device); #ifdef CONFIG_MEDIA_CONTROLLER_DVBvoid dvb_create_media_graph(struct dvb_adapter *adap){ struct media_device *mdev = adap->mdev; struct media_entity *entity, *tuner = NULL, *fe = NULL; struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL; if (!mdev) return; media_device_for_each_entity(entity, mdev) { switch (entity->type) { case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: tuner = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_FE: fe = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_DEMUX: demux = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_DVR: dvr = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_CA: ca = entity; break; } } if (tuner && fe) media_entity_create_link(tuner, 0, fe, 0, 0); if (fe && demux) media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED); if (demux && dvr) media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED); if (demux && ca) media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED);}EXPORT_SYMBOL_GPL(dvb_create_media_graph);#endif static int dvbdev_check_free_adapter_num(int num){ struct list_head *entry; list_for_each(entry, &dvb_adapter_list) { struct dvb_adapter *adap; adap = list_entry(entry, struct dvb_adapter, list_head); if (adap->num == num) return 0; } return 1;} static int dvbdev_get_free_adapter_num (void){ int num = 0; while (num < DVB_MAX_ADAPTERS) { if (dvbdev_check_free_adapter_num(num)) return num; num++; } return -ENFILE;} int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device, short *adapter_nums){ int i, num; mutex_lock(&dvbdev_register_lock); for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { num = adapter_nums[i]; if (num >= 0 && num < DVB_MAX_ADAPTERS) { /* use the one the driver asked for */ if (dvbdev_check_free_adapter_num(num)) break; } else { num = dvbdev_get_free_adapter_num(); break; } num = -1; } if (num < 0) { mutex_unlock(&dvbdev_register_lock); return -ENFILE; } memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); adap->num = num; adap->name = name; adap->module = module; adap->device = device; adap->mfe_shared = 0; adap->mfe_dvbdev = NULL; mutex_init (&adap->mfe_lock); list_add_tail (&adap->list_head, &dvb_adapter_list); mutex_unlock(&dvbdev_register_lock); return num;}EXPORT_SYMBOL(dvb_register_adapter);Lines 1–500 of 640. Load more
/* * dvbdev.c * * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> * & Marcus Metzler <marcus@convergence.de> * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include <linux/types.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/mutex.h> #include "dvbdev.h" static DEFINE_MUTEX(dvbdev_mutex); 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 DEFINE_MUTEX(dvbdev_register_lock); static const char * const dnames[] = { "video", "audio", "sec", "frontend", "demux", "dvr", "ca", "net", "osd" }; #ifdef CONFIG_DVB_DYNAMIC_MINORS #define MAX_DVB_MINORS 256 #define DVB_MAX_IDS MAX_DVB_MINORS #else #define DVB_MAX_IDS 4 #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) #endif static struct class *dvb_class; static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; mutex_lock(&dvbdev_mutex); down_read(&minor_rwsem); dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; const struct file_operations *new_fops; new_fops = fops_get(dvbdev->fops); if (!new_fops) goto fail; file->private_data = dvbdev; replace_fops(file, new_fops); if (file->f_op->open) err = file->f_op->open(inode,file); up_read(&minor_rwsem); mutex_unlock(&dvbdev_mutex); return err; } fail: up_read(&minor_rwsem); mutex_unlock(&dvbdev_mutex); return -ENODEV; } static const struct file_operations dvb_device_fops = { .owner = THIS_MODULE, .open = dvb_device_open, .llseek = noop_llseek, }; static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; if (!dvbdev->users) return -EBUSY; if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (!dvbdev->readers) return -EBUSY; dvbdev->readers--; } else { 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; if (!dvbdev) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY) { dvbdev->readers++; } else { dvbdev->writers++; } dvbdev->users++; return 0; } EXPORT_SYMBOL(dvb_generic_release); long dvb_generic_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; if (!dvbdev->kernel_ioctl) return -EINVAL; return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); } EXPORT_SYMBOL(dvb_generic_ioctl); static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) { u32 id = 0; while (id < DVB_MAX_IDS) { struct dvb_device *dev; list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; return id; skip: id++; } return -ENFILE; } static void dvb_register_media_device(struct dvb_device *dvbdev, int type, int minor) { #if defined(CONFIG_MEDIA_CONTROLLER_DVB) int ret = 0, npads; if (!dvbdev->adapter->mdev) return; dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); if (!dvbdev->entity) return; dvbdev->entity->info.dev.major = DVB_MAJOR; dvbdev->entity->info.dev.minor = minor; dvbdev->entity->name = dvbdev->name; switch (type) { case DVB_DEVICE_CA: case DVB_DEVICE_DEMUX: case DVB_DEVICE_FRONTEND: npads = 2; break; case DVB_DEVICE_NET: npads = 0; break; default: npads = 1; } if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); if (!dvbdev->pads) { kfree(dvbdev->entity); return; } } switch (type) { case DVB_DEVICE_FRONTEND: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_DEMUX: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_DVR: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; break; case DVB_DEVICE_CA: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_NET: dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET; break; default: kfree(dvbdev->entity); dvbdev->entity = NULL; return; } if (npads) ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0); if (!ret) ret = media_device_register_entity(dvbdev->adapter->mdev, dvbdev->entity); if (ret < 0) { printk(KERN_ERR "%s: media_device_register_entity failed for %s\n", __func__, dvbdev->entity->name); kfree(dvbdev->pads); kfree(dvbdev->entity); dvbdev->entity = NULL; return; } printk(KERN_DEBUG "%s: media device '%s' registered.\n", __func__, dvbdev->entity->name); #endif } 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; struct device *clsdev; int minor; int id; mutex_lock(&dvbdev_register_lock); if ((id = dvbdev_get_free_id (adap, type)) < 0){ mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; printk(KERN_ERR "%s: couldn't find free device id\n", __func__); return -ENFILE; } *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); if (!dvbdev){ 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; } memcpy(dvbdev, template, sizeof(struct dvb_device)); dvbdev->type = type; dvbdev->id = id; dvbdev->adapter = adap; dvbdev->priv = priv; dvbdev->fops = dvbdevfops; init_waitqueue_head (&dvbdev->wait_queue); memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); dvbdevfops->owner = adap->module; list_add_tail (&dvbdev->list_head, &adap->device_list); down_write(&minor_rwsem); #ifdef CONFIG_DVB_DYNAMIC_MINORS for (minor = 0; minor < MAX_DVB_MINORS; minor++) if (dvb_minors[minor] == NULL) break; if (minor == MAX_DVB_MINORS) { kfree(dvbdevfops); kfree(dvbdev); up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return -EINVAL; } #else minor = nums2minor(adap->num, type, id); #endif dvbdev->minor = minor; dvb_minors[minor] = dvbdev; up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); clsdev = device_create(dvb_class, adap->device, MKDEV(DVB_MAJOR, minor), dvbdev, "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", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); return PTR_ERR(clsdev); } dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); dvb_register_media_device(dvbdev, type, minor); return 0; } EXPORT_SYMBOL(dvb_register_device); void dvb_unregister_device(struct dvb_device *dvbdev) { if (!dvbdev) return; down_write(&minor_rwsem); dvb_minors[dvbdev->minor] = NULL; up_write(&minor_rwsem); device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); #if defined(CONFIG_MEDIA_CONTROLLER_DVB) if (dvbdev->entity) { media_device_unregister_entity(dvbdev->entity); kfree(dvbdev->entity); kfree(dvbdev->pads); } #endif list_del (&dvbdev->list_head); kfree (dvbdev->fops); kfree (dvbdev); } EXPORT_SYMBOL(dvb_unregister_device); #ifdef CONFIG_MEDIA_CONTROLLER_DVB void dvb_create_media_graph(struct dvb_adapter *adap) { struct media_device *mdev = adap->mdev; struct media_entity *entity, *tuner = NULL, *fe = NULL; struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL; if (!mdev) return; media_device_for_each_entity(entity, mdev) { switch (entity->type) { case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: tuner = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_FE: fe = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_DEMUX: demux = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_DVR: dvr = entity; break; case MEDIA_ENT_T_DEVNODE_DVB_CA: ca = entity; break; } } if (tuner && fe) media_entity_create_link(tuner, 0, fe, 0, 0); if (fe && demux) media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED); if (demux && dvr) media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED); if (demux && ca) media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED); } EXPORT_SYMBOL_GPL(dvb_create_media_graph); #endif static int dvbdev_check_free_adapter_num(int num) { struct list_head *entry; list_for_each(entry, &dvb_adapter_list) { struct dvb_adapter *adap; adap = list_entry(entry, struct dvb_adapter, list_head); if (adap->num == num) return 0; } return 1; } static int dvbdev_get_free_adapter_num (void) { int num = 0; while (num < DVB_MAX_ADAPTERS) { if (dvbdev_check_free_adapter_num(num)) return num; num++; } return -ENFILE; } int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device, short *adapter_nums) { int i, num; mutex_lock(&dvbdev_register_lock); for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { num = adapter_nums[i]; if (num >= 0 && num < DVB_MAX_ADAPTERS) { /* use the one the driver asked for */ if (dvbdev_check_free_adapter_num(num)) break; } else { num = dvbdev_get_free_adapter_num(); break; } num = -1; } if (num < 0) { mutex_unlock(&dvbdev_register_lock); return -ENFILE; } memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); adap->num = num; adap->name = name; adap->module = module; adap->device = device; adap->mfe_shared = 0; adap->mfe_dvbdev = NULL; mutex_init (&adap->mfe_lock); list_add_tail (&adap->list_head, &dvb_adapter_list); mutex_unlock(&dvbdev_register_lock); return num; } EXPORT_SYMBOL(dvb_register_adapter);