/* * Helper to find the next divisor that results in modulo being zero. * This is required to guarantee valid decimation unit counts.
*/ staticunsignedint
div_round_integer(unsignedint x, unsignedint y)
{ for (;; y++) { if (x % y == 0) return x / y;
}
}
staticvoid stk1160_set_std(struct stk1160 *dev)
{ int i;
/* TODO: Each line of frame has some junk at the end */ /* Frame start */
{STK116_CFSPO, 0x0000},
{STK116_CFSPO+1, 0x0000},
{STK116_CFSPO+2, 0x0001},
{STK116_CFSPO+3, 0x0000},
if (dev->norm & V4L2_STD_525_60) {
stk1160_dbg("registers to NTSC like standard\n"); for (i = 0; std525[i].reg != 0xffff; i++)
stk1160_write_reg(dev, std525[i].reg, std525[i].val);
} else {
stk1160_dbg("registers to PAL like standard\n"); for (i = 0; std625[i].reg != 0xffff; i++)
stk1160_write_reg(dev, std625[i].reg, std625[i].val);
}
if (ctrl) { /* * Since the format is UYVY, the device must skip or send * a number of rows/columns multiple of four. This way, the * colour format is preserved. The STK1160_DEC_UNIT_SIZE bit * does exactly this.
*/
val |= STK1160_DEC_UNIT_SIZE;
val |= ctrl->col_en ? STK1160_H_DEC_EN : 0;
val |= ctrl->row_en ? STK1160_V_DEC_EN : 0;
val |= ctrl->col_mode ==
STK1160_DECIMATE_MORE_THAN_HALF ?
STK1160_H_DEC_MODE : 0;
val |= ctrl->row_mode ==
STK1160_DECIMATE_MORE_THAN_HALF ?
STK1160_V_DEC_MODE : 0;
/* Horizontal count units */
stk1160_write_reg(dev, STK1160_DMCTRL_H_UNITS, ctrl->col_n); /* Vertical count units */
stk1160_write_reg(dev, STK1160_DMCTRL_V_UNITS, ctrl->row_n);
stk1160_dbg("decimate 0x%x, column units %d, row units %d\n",
val, ctrl->col_n, ctrl->row_n);
}
/* Decimation control */
stk1160_write_reg(dev, STK1160_DMCTRL, val);
}
/* * Set a new alternate setting. * Returns true is dev->max_pkt_size has changed, false otherwise.
*/ staticbool stk1160_set_alternate(struct stk1160 *dev)
{ int i, prev_alt = dev->alt; unsignedint min_pkt_size; bool new_pkt_size;
/* * If we don't set right alternate, * then we will get a green screen with junk.
*/
min_pkt_size = STK1160_MIN_PKT_SIZE;
for (i = 0; i < dev->num_alt; i++) { /* stop when the selected alt setting offers enough bandwidth */ if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
dev->alt = i; break; /* * otherwise make sure that we end up with the maximum bandwidth * because the min_pkt_size equation might be wrong...
*/
} elseif (dev->alt_max_pkt_size[i] >
dev->alt_max_pkt_size[dev->alt])
dev->alt = i;
}
stk1160_dbg("setting alternate %d\n", dev->alt);
if (dev->alt != prev_alt) {
stk1160_dbg("minimum isoc packet size: %u (alt=%d)\n",
min_pkt_size, dev->alt);
stk1160_dbg("setting alt %d with wMaxPacketSize=%u\n",
dev->alt, dev->alt_max_pkt_size[dev->alt]);
usb_set_interface(dev->udev, 0, dev->alt);
}
staticint stk1160_start_streaming(struct stk1160 *dev)
{ bool new_pkt_size; int rc = 0; int i;
/* Check device presence */ if (!dev->udev) return -ENODEV;
if (mutex_lock_interruptible(&dev->v4l_lock)) return -ERESTARTSYS; /* * For some reason it is mandatory to set alternate *first* * and only *then* initialize isoc urbs. * Someone please explain me why ;)
*/
new_pkt_size = stk1160_set_alternate(dev);
/* * We (re)allocate isoc urbs if: * there is no allocated isoc urbs, OR * a new dev->max_pkt_size is detected
*/ if (!dev->isoc_ctl.num_bufs || new_pkt_size) {
rc = stk1160_alloc_isoc(dev); if (rc < 0) goto out_stop_hw;
}
/* submit urbs and enables IRQ */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
rc = usb_submit_urb(dev->isoc_ctl.urb_ctl[i].urb, GFP_KERNEL); if (rc) {
stk1160_err("cannot submit urb[%d] (%d)\n", i, rc); goto out_uninit;
}
}
/* Must be called with v4l_lock hold */ staticvoid stk1160_stop_hw(struct stk1160 *dev)
{ /* If the device is not physically present, there is nothing to do */ if (!dev->udev) return;
staticint stk1160_stop_streaming(struct stk1160 *dev)
{ if (mutex_lock_interruptible(&dev->v4l_lock)) return -ERESTARTSYS;
/* * Once URBs are cancelled, the URB complete handler * won't be running. This is required to safely release the * current buffer (dev->isoc_ctl.buf).
*/
stk1160_cancel_isoc(dev);
/* * It is possible to keep buffers around using a module parameter. * This is intended to avoid memory fragmentation.
*/ if (!keep_buffers)
stk1160_free_isoc(dev);
/* * Here we can change the number of buffers being requested. * So, we set a minimum and a maximum like this:
*/
*nbuffers = clamp_t(unsignedint, *nbuffers,
STK1160_MIN_VIDEO_BUFFERS, STK1160_MAX_VIDEO_BUFFERS);
if (*nplanes) return sizes[0] < size ? -EINVAL : 0;
/* This means a packed colorformat */
*nplanes = 1;
sizes[0] = size;
stk1160_dbg("%s: buffer count %d, each %ld bytes\n",
__func__, *nbuffers, size);
spin_lock_irqsave(&dev->buf_lock, flags); if (!dev->udev) { /* * If the device is disconnected return the buffer to userspace * directly. The next QBUF call will fail with -ENODEV.
*/
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
} else {
/* * If buffer length is less from expected then we return * the buffer to userspace directly.
*/ if (buf->length < dev->width * dev->height * 2)
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); else
list_add_tail(&buf->list, &dev->avail_bufs);
/* Must be called with both v4l_lock and vb_queue_lock hold */ void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state)
{ struct stk1160_buffer *buf; unsignedlong flags;
/* Release all active buffers */
spin_lock_irqsave(&dev->buf_lock, flags); while (!list_empty(&dev->avail_bufs)) {
buf = list_first_entry(&dev->avail_bufs, struct stk1160_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf, vb2_state);
stk1160_dbg("buffer [%p/%d] aborted\n",
buf, buf->vb.vb2_buf.index);
}
/* It's important to release the current buffer */ if (dev->isoc_ctl.buf) {
buf = dev->isoc_ctl.buf;
dev->isoc_ctl.buf = NULL;
/* initialize video dma queue */
INIT_LIST_HEAD(&dev->avail_bufs);
return 0;
}
int stk1160_video_register(struct stk1160 *dev)
{ int rc;
/* Initialize video_device with a template structure */
dev->vdev = v4l_template;
dev->vdev.queue = &dev->vb_vidq;
/* * Provide mutexes for v4l2 core and for videobuf2 queue. * It will be used to protect *only* v4l2 ioctls.
*/
dev->vdev.lock = &dev->v4l_lock;
/* This will be used to set video_device parent */
dev->vdev.v4l2_dev = &dev->v4l2_dev;
dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
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.