/* * This will find the tuner that is connected into the decoder. * Technically, this is not 100% correct, as the device may be * using an analog input instead of the tuner. However, as we can't * do DVB streaming while the DMA engine is being used for V4L2, * this should be enough for the actual needs.
*/
media_device_for_each_entity(entity, mdev) { if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
decoder = entity; break;
}
} if (!decoder) return 0;
list_for_each_entry(link, &decoder->links, list) { if (link->sink->entity == decoder) {
found_link = link; if (link->flags & MEDIA_LNK_FL_ENABLED)
active_links++; break;
}
}
ret = media_entity_setup_link(link, flags); if (ret) {
dev_err(dev->dev, "Couldn't change link %s->%s to %s. Error %d\n",
source->name, sink->name,
flags ? "enabled" : "disabled",
ret); return ret;
} else
dev_dbg(dev->dev, "link %s->%s was %s\n",
source->name, sink->name,
flags ? "ENABLED" : "disabled");
} #endif return 0;
}
/* ------------------------------------------------------------------ Video buffer and parser functions
------------------------------------------------------------------*/
/* * Announces that a buffer were filled and request the next
*/ staticinlinevoid buffer_filled(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, struct cx231xx_buffer *buf)
{ /* Advice that buffer was filled */
cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.vb2_buf.index);
buf->vb.sequence = dma_q->sequence++;
buf->vb.field = V4L2_FIELD_INTERLACED;
buf->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, dev->size);
if (dev->USE_ISO)
dev->video_mode.isoc_ctl.buf = NULL; else
dev->video_mode.bulk_ctl.buf = NULL;
staticinlinevoid print_err_status(struct cx231xx *dev, int packet, int status)
{ char *errmsg = "Unknown";
switch (status) { case -ENOENT:
errmsg = "unlinked synchronously"; break; case -ECONNRESET:
errmsg = "unlinked asynchronously"; break; case -ENOSR:
errmsg = "Buffer error (overrun)"; break; case -EPIPE:
errmsg = "Stalled (device not responding)"; break; case -EOVERFLOW:
errmsg = "Babble (bad cable?)"; break; case -EPROTO:
errmsg = "Bit-stuff error (bad cable?)"; break; case -EILSEQ:
errmsg = "CRC/Timeout (could be anything)"; break; case -ETIME:
errmsg = "Device does not respond"; break;
} if (packet < 0) {
cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
} else {
cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
packet, status, errmsg);
}
}
/* * generic routine to get the next available buffer
*/ staticinlinevoid get_next_buf(struct cx231xx_dmaqueue *dma_q, struct cx231xx_buffer **buf)
{ struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq); struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
char *outp;
if (list_empty(&dma_q->active)) {
cx231xx_isocdbg("No active queue to serve\n"); if (dev->USE_ISO)
dev->video_mode.isoc_ctl.buf = NULL; else
dev->video_mode.bulk_ctl.buf = NULL;
*buf = NULL; return;
}
/* Get the next buffer */
*buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list);
/* Cleans up buffer - Useful for testing for frame/URB loss */
outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
memset(outp, 0, dev->size);
if (dev->USE_ISO)
dev->video_mode.isoc_ctl.buf = *buf; else
dev->video_mode.bulk_ctl.buf = *buf;
return;
}
/* * Controls the isoc copy of each urb packet
*/ staticinlineint cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
{ struct cx231xx_dmaqueue *dma_q = urb->context; int i; unsignedchar *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
u8 sav_eav = 0;
if (!dev) return 0;
if (dev->state & DEV_DISCONNECTED) return 0;
if (urb->status < 0) {
print_err_status(dev, -1, urb->status); if (urb->status == -ENOENT) return 0;
}
for (i = 0; i < urb->number_of_packets; i++) { int status = urb->iso_frame_desc[i].status;
if (status < 0) {
print_err_status(dev, i, status); if (urb->iso_frame_desc[i].status != -EPROTO) continue;
}
if (urb->iso_frame_desc[i].actual_length <= 0) { /* cx231xx_isocdbg("packet %d is empty",i); - spammy */ continue;
} if (urb->iso_frame_desc[i].actual_length >
dev->video_mode.max_pkt_size) {
cx231xx_isocdbg("packet bigger than packet size"); continue;
}
/* get buffer pointer and length */
p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
buffer_size = urb->iso_frame_desc[i].actual_length;
bytes_parsed = 0;
if (dma_q->is_partial_line) { /* Handle the case of a partial line */
sav_eav = dma_q->last_sav;
} else { /* Check for a SAV/EAV overlapping
the buffer boundary */
sav_eav =
cx231xx_find_boundary_SAV_EAV(p_buffer,
dma_q->partial_buf,
&bytes_parsed);
}
sav_eav &= 0xF0; /* Get the first line if we have some portion of an SAV/EAV from
the last buffer or a partial line */ if (sav_eav) {
bytes_parsed += cx231xx_get_video_line(dev, dma_q,
sav_eav, /* SAV/EAV */
p_buffer + bytes_parsed, /* p_buffer */
buffer_size - bytes_parsed);/* buf size */
}
/* Now parse data that is completely in this buffer */ /* dma_q->is_partial_line = 0; */
while (bytes_parsed < buffer_size) {
u32 bytes_used = 0;
sav_eav = cx231xx_find_next_SAV_EAV(
p_buffer + bytes_parsed, /* p_buffer */
buffer_size - bytes_parsed, /* buf size */
&bytes_used);/* bytes used to get SAV/EAV */
/* Save the last four bytes of the buffer so we can check the
buffer boundary condition next time */
memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
bytes_parsed = 0;
if (urb->status < 0) {
print_err_status(dev, -1, urb->status); if (urb->status == -ENOENT) return 0;
}
if (1) {
/* get buffer pointer and length */
p_buffer = urb->transfer_buffer;
buffer_size = urb->actual_length;
bytes_parsed = 0;
if (dma_q->is_partial_line) { /* Handle the case of a partial line */
sav_eav = dma_q->last_sav;
} else { /* Check for a SAV/EAV overlapping
the buffer boundary */
sav_eav =
cx231xx_find_boundary_SAV_EAV(p_buffer,
dma_q->partial_buf,
&bytes_parsed);
}
sav_eav &= 0xF0; /* Get the first line if we have some portion of an SAV/EAV from
the last buffer or a partial line */ if (sav_eav) {
bytes_parsed += cx231xx_get_video_line(dev, dma_q,
sav_eav, /* SAV/EAV */
p_buffer + bytes_parsed, /* p_buffer */
buffer_size - bytes_parsed);/* buf size */
}
/* Now parse data that is completely in this buffer */ /* dma_q->is_partial_line = 0; */
while (bytes_parsed < buffer_size) {
u32 bytes_used = 0;
sav_eav = cx231xx_find_next_SAV_EAV(
p_buffer + bytes_parsed, /* p_buffer */
buffer_size - bytes_parsed, /* buf size */
&bytes_used);/* bytes used to get SAV/EAV */
/* Save the last four bytes of the buffer so we can check the
buffer boundary condition next time */
memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
bytes_parsed = 0;
/* * Don't search if the buffer size is less than 4. It causes a page * fault since buffer_size - 4 evaluates to a large number in that * case.
*/ if (buffer_size < 4) {
*p_bytes_used = buffer_size; return 0;
}
switch (sav_eav) { case SAV_ACTIVE_VIDEO_FIELD1: /* looking for skipped line which occurred in PAL 720x480 mode. In this case, there will be no active data contained
between the SAV and EAV */ if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
(p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
(p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
(p_buffer[3] == EAV_VBLANK_FIELD1) ||
(p_buffer[3] == EAV_VBLANK_FIELD2))) return bytes_copied;
current_field = 1; break;
case SAV_ACTIVE_VIDEO_FIELD2: /* looking for skipped line which occurred in PAL 720x480 mode. In this case, there will be no active data contained between
the SAV and EAV */ if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
(p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
(p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
(p_buffer[3] == EAV_VBLANK_FIELD1) ||
(p_buffer[3] == EAV_VBLANK_FIELD2))) return bytes_copied;
current_field = 2; break;
}
/* If we don't have a buffer, just return the number of bytes we would
have copied if we had a buffer. */ if (!buf) {
dma_q->bytes_left_in_line -= bytes_to_copy;
dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
? 0 : 1; return bytes_to_copy;
}
/* copy the data to video buffer */
cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
/* handle the switch from field 1 to field 2 */ if (dma_q->current_field == 1) { if (dma_q->lines_completed >= dma_q->lines_per_field)
dma_q->field1_done = 1; else
dma_q->field1_done = 0;
}
if (dev->USE_ISO)
buf = dev->video_mode.isoc_ctl.buf; else
buf = dev->video_mode.bulk_ctl.buf;
if (buf == NULL) { /* first try to get the buffer */
get_next_buf(dma_q, &buf);
fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (!fmt) {
cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
f->fmt.pix.pixelformat); return -EINVAL;
}
/* width must even because of the YUYV format
height must be even because of interlacing */
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
/* We need to reset basic properties in the decoder related to resolution (since a standard change effects things like the number
of lines in VACT, etc) */
format.format.code = MEDIA_BUS_FMT_FIXED;
format.format.width = dev->width;
format.format.height = dev->height;
call_all(dev, pad, set_fmt, NULL, &format);
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
switch (INPUT(i)->type) { case CX231XX_VMUX_COMPOSITE1:
ent->function = MEDIA_ENT_F_CONN_COMPOSITE; break; case CX231XX_VMUX_SVIDEO:
ent->function = MEDIA_ENT_F_CONN_SVIDEO; break; case CX231XX_VMUX_TELEVISION: case CX231XX_VMUX_CABLE: case CX231XX_VMUX_DVB: /* The DVB core will handle it */ if (dev->tuner_type == TUNER_ABSENT) continue;
fallthrough; default: /* just to shut up a gcc warning */
ent->function = MEDIA_ENT_F_CONN_RF; break;
}
ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]); if (ret < 0)
pr_err("failed to initialize input pad[%d]!\n", i);
ret = media_device_register_entity(dev->media_dev, ent); if (ret < 0)
pr_err("failed to register input entity %d!\n", i);
} #endif
}
/* If they are asking about the active input, read signal status */ if (n == dev->video_input) {
ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
GEN_STAT, 2, &gen_stat, 4); if (ret > 0) { if ((gen_stat & FLD_VPRES) == 0x00)
i->status |= V4L2_IN_ST_NO_SIGNAL; if ((gen_stat & FLD_HLOCK) == 0x00)
i->status |= V4L2_IN_ST_NO_H_LOCK;
}
}
if (i >= MAX_CX231XX_INPUT) return -EINVAL; if (0 == INPUT(i)->type) return -EINVAL;
video_mux(dev, i);
if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
INPUT(i)->type == CX231XX_VMUX_CABLE) { /* There's a tuner, so reset the standard and put it on the last known frequency (since it was probably powered down
until now */
call_all(dev, video, s_std, dev->norm);
}
switch (dev->model) { case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: case CX231XX_BOARD_HAUPPAUGE_935C: case CX231XX_BOARD_HAUPPAUGE_955Q: case CX231XX_BOARD_HAUPPAUGE_975: case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
cap->capabilities |= V4L2_CAP_TUNER; break; default: if (dev->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER; break;
} return 0;
}
/* * cx231xx_v4l2_open() * inits the device and starts isoc transfer
*/ staticint cx231xx_v4l2_open(struct file *filp)
{ struct video_device *vdev = video_devdata(filp); struct cx231xx *dev = video_drvdata(filp); int ret;
if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS;
ret = v4l2_fh_open(filp); if (ret) {
mutex_unlock(&dev->lock); return ret;
}
if (dev->users++ == 0) { /* Power up in Analog TV mode */ if (dev->board.external_av)
cx231xx_set_power_mode(dev,
POLARIS_AVMODE_ENXTERNAL_AV); else
cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
/* set video alternate setting */
cx231xx_set_video_alternate(dev);
/* Needed, since GPIO might have disabled power of
some i2c device */
cx231xx_config_i2c(dev);
/* device needs to be initialized before isoc transfer */
dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
}
if (vdev->vfl_type == VFL_TYPE_RADIO) {
cx231xx_videodbg("video_open: setting radio device\n");
/* cx231xx_start_radio(dev); */
call_all(dev, tuner, s_radio);
} if (vdev->vfl_type == VFL_TYPE_VBI) { /* Set the required alternate setting VBI interface works in
Bulk mode only */
cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
}
mutex_unlock(&dev->lock); return 0;
}
/* * cx231xx_realease_resources() * unregisters the v4l2,i2c and usb devices * called when the device gets disconnected or at module unload
*/ void cx231xx_release_analog_resources(struct cx231xx *dev)
{
/*FIXME: I2C IR should be disconnected */
if (video_is_registered(&dev->radio_dev))
video_unregister_device(&dev->radio_dev); if (video_is_registered(&dev->vbi_dev)) {
dev_info(dev->dev, "V4L2 device %s deregistered\n",
video_device_node_name(&dev->vbi_dev));
video_unregister_device(&dev->vbi_dev);
} if (video_is_registered(&dev->vdev)) {
dev_info(dev->dev, "V4L2 device %s deregistered\n",
video_device_node_name(&dev->vdev));
if (dev->board.has_417)
cx231xx_417_unregister(dev);
/* * cx231xx_close() * stops streaming and deallocates all resources allocated by the v4l2 * calls and ioctls
*/ staticint cx231xx_close(struct file *filp)
{ struct cx231xx *dev = video_drvdata(filp); struct video_device *vdev = video_devdata(filp);
_vb2_fop_release(filp, NULL);
if (--dev->users == 0) { /* Save some power by putting tuner to sleep */
call_all(dev, tuner, standby);
/* do this before setting alternate! */ if (dev->USE_ISO)
cx231xx_uninit_isoc(dev); else
cx231xx_uninit_bulk(dev);
cx231xx_set_mode(dev, CX231XX_SUSPEND);
}
/* * To workaround error number=-71 on EP0 for VideoGrabber, * need exclude following. * FIXME: It is probably safe to remove most of these, as we're * now avoiding the alternate setting for INDEX_VANC
*/ if (!dev->board.no_alt_vanc && vdev->vfl_type == VFL_TYPE_VBI) { /* do this before setting alternate! */
cx231xx_uninit_vbi_isoc(dev);
/* set alternate 0 */ if (!dev->vbi_or_sliced_cc_mode)
cx231xx_set_alt_setting(dev, INDEX_VANC, 0); else
cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
/* allocate and fill video video_device struct */
cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video"); #ifdefined(CONFIG_MEDIA_CONTROLLER)
dev->video_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad); if (ret < 0)
dev_err(dev->dev, "failed to initialize video media entity!\n"); #endif
dev->vdev.ctrl_handler = &dev->ctrl_handler;
switch (dev->model) { /* i2c device tuners */ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: case CX231XX_BOARD_HAUPPAUGE_935C: case CX231XX_BOARD_HAUPPAUGE_955Q: case CX231XX_BOARD_HAUPPAUGE_975: case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
dev->vdev.device_caps |= V4L2_CAP_TUNER; break; default: if (dev->tuner_type != TUNER_ABSENT)
dev->vdev.device_caps |= V4L2_CAP_TUNER; break;
}
/* register v4l2 video video_device */
ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO,
video_nr[dev->devno]); if (ret) {
dev_err(dev->dev, "unable to register video device (error=%i).\n",
ret); return ret;
}
dev_info(dev->dev, "Registered video device %s [v4l2]\n",
video_device_node_name(&dev->vdev));
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.