staticint dvb_create_media_entity(struct dvb_device *dvbdev, int type, int demux_sink_pads)
{ int i, ret, npads;
switch (type) { case DVB_DEVICE_FRONTEND:
npads = 2; break; case DVB_DEVICE_DVR:
ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
demux_sink_pads); return ret; case DVB_DEVICE_DEMUX:
npads = 1 + demux_sink_pads;
ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
demux_sink_pads); if (ret < 0) return ret; break; case DVB_DEVICE_CA:
npads = 2; break; case DVB_DEVICE_NET: /* * We should be creating entities for the MPE/ULE * decapsulation hardware (or software implementation). * * However, the number of for the MPE/ULE decaps may not be * fixed. As we don't have yet dynamic support for PADs at * the Media Controller, let's not create the decap * entities yet.
*/ return 0; default: return 0;
}
dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); if (!dvbdev->entity) return -ENOMEM;
dvbdev->entity->name = dvbdev->name;
if (npads) {
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
GFP_KERNEL); if (!dvbdev->pads) {
kfree(dvbdev->entity);
dvbdev->entity = NULL; return -ENOMEM;
}
}
switch (type) { case DVB_DEVICE_FRONTEND:
dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_DEMUX:
dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; for (i = 1; i < npads; i++)
dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_CA:
dvbdev->entity->function = MEDIA_ENT_F_DTV_CA;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; default: /* Should never happen, as the first switch prevents it */
kfree(dvbdev->entity);
kfree(dvbdev->pads);
dvbdev->entity = NULL;
dvbdev->pads = NULL; return 0;
}
if (npads) {
ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads); if (ret) return ret;
}
ret = media_device_register_entity(dvbdev->adapter->mdev,
dvbdev->entity); if (ret) return ret;
pr_info("%s: media entity '%s' registered.\n",
__func__, dvbdev->entity->name);
return 0;
} #endif
staticint dvb_register_media_device(struct dvb_device *dvbdev, int type, int minor, unsignedint demux_sink_pads)
{ #ifdefined(CONFIG_MEDIA_CONTROLLER_DVB) struct media_link *link;
u32 intf_type; int ret;
if (!dvbdev->adapter->mdev) return 0;
ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads); if (ret) return ret;
switch (type) { case DVB_DEVICE_FRONTEND:
intf_type = MEDIA_INTF_T_DVB_FE; break; case DVB_DEVICE_DEMUX:
intf_type = MEDIA_INTF_T_DVB_DEMUX; break; case DVB_DEVICE_DVR:
intf_type = MEDIA_INTF_T_DVB_DVR; break; case DVB_DEVICE_CA:
intf_type = MEDIA_INTF_T_DVB_CA; break; case DVB_DEVICE_NET:
intf_type = MEDIA_INTF_T_DVB_NET; break; default: return 0;
}
/* * Create the "obvious" link, e. g. the ones that represent * a direct association between an interface and an entity. * Other links should be created elsewhere, like: * DVB FE intf -> tuner * DVB demux intf -> dvr
*/
if (!dvbdev->entity) return 0;
link = media_create_intf_link(dvbdev->entity,
&dvbdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM; #endif return 0;
}
/* * When a device of the same type is probe()d more than once, * the first allocated fops are used. This prevents memory leaks * that can occur when the same device is probe()d repeatedly.
*/
list_for_each_entry(node, &dvbdevfops_list, list_head) { if (node->fops->owner == adap->module &&
node->type == type && node->template == template) {
dvbdevfops = node->fops; break;
}
}
if (!dvbdevfops) {
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); if (!dvbdevfops) {
kfree(dvbdev);
*pdvbdev = NULL;
mutex_unlock(&dvbdev_register_lock); return -ENOMEM;
}
media_device_for_each_entity(entity, mdev) { switch (entity->function) { case MEDIA_ENT_F_TUNER:
tuner = entity;
ntuner++; break; case MEDIA_ENT_F_DTV_DEMOD:
demod = entity;
ndemod++; break; case MEDIA_ENT_F_TS_DEMUX:
demux = entity; break; case MEDIA_ENT_F_DTV_CA:
ca = entity; break;
}
}
/* * Prepare to signalize to media_create_pad_links() that multiple * entities of the same type exists and a 1:n or n:1 links need to be * created. * NOTE: if both tuner and demod have multiple instances, it is up * to the caller driver to create such links.
*/ if (ntuner > 1)
tuner = NULL; if (ndemod > 1)
demod = NULL;
if (create_rf_connector) {
conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) return -ENOMEM;
adap->conn = conn;
adap->conn_pads = kzalloc(sizeof(*adap->conn_pads), GFP_KERNEL); if (!adap->conn_pads) return -ENOMEM;
ret = media_entity_pads_init(conn, 1, adap->conn_pads); if (ret) return ret;
ret = media_device_register_entity(mdev, conn); if (ret) return ret;
if (!ntuner) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0,
MEDIA_LNK_FL_ENABLED, false);
} else {
pad_sink = media_get_pad_index(tuner, MEDIA_PAD_FL_SINK,
PAD_SIGNAL_ANALOG); if (pad_sink < 0) return -EINVAL;
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_TUNER,
tuner, pad_sink,
MEDIA_LNK_FL_ENABLED, false);
} if (ret) return ret;
}
if (ntuner && ndemod) { /* NOTE: first found tuner source pad presumed correct */
pad_source = media_get_pad_index(tuner, MEDIA_PAD_FL_SOURCE,
PAD_SIGNAL_ANALOG); if (pad_source < 0) return -EINVAL;
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
tuner, pad_source,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED, false); if (ret) return ret;
}
if (ndemod && demux) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_DTV_DEMOD,
demod, 1,
MEDIA_ENT_F_TS_DEMUX,
demux, 0, MEDIA_LNK_FL_ENABLED, false); if (ret) return ret;
} if (demux && ca) {
ret = media_create_pad_link(demux, 1, ca,
0, MEDIA_LNK_FL_ENABLED); if (ret) return ret;
}
/* Create demux links for each ringbuffer/pad */ if (demux) {
media_device_for_each_entity(entity, mdev) { if (entity->function == MEDIA_ENT_F_IO_DTV) { if (!strncmp(entity->name, DVR_TSOUT,
strlen(DVR_TSOUT))) {
ret = media_create_pad_link(demux,
++dvr_pad,
entity, 0, 0); if (ret) return ret;
} if (!strncmp(entity->name, DEMUX_TSOUT,
strlen(DEMUX_TSOUT))) {
ret = media_create_pad_link(demux,
++demux_pad,
entity, 0, 0); if (ret) return ret;
}
}
}
}
/* Create interface links for FE->tuner, DVR->demux and CA->ca */
media_device_for_each_intf(intf, mdev) { if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
link = media_create_intf_link(ca, intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM;
}
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
link = media_create_intf_link(tuner, intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM;
} #if 0 /* * Indirect link - let's not create yet, as we don't know how * to handle indirect links, nor if this will * actually be needed.
*/ if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
link = media_create_intf_link(demux, intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM;
} #endif if (intf->type == MEDIA_INTF_T_DVB_DVR) {
ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT); if (ret) return ret;
} if (intf->type == MEDIA_INTF_T_DVB_DEMUX) {
ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT); if (ret) return ret;
}
} return 0;
}
EXPORT_SYMBOL_GPL(dvb_create_media_graph); #endif
staticint 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, constchar *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;
}
/* * 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 dependency * 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 file *file, unsignedint cmd, unsignedlong arg, int (*func)(struct file *file, unsignedint 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 (!mbuf) return -ENOMEM;
parg = mbuf;
}
staticint __init init_dvbdev(void)
{ int retval;
dev_t dev = MKDEV(DVB_MAJOR, 0);
retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB"); if (retval != 0) {
pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR); return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS); if (retval != 0) {
pr_err("dvb-core: unable register character device\n"); goto error;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.