diff options
author | Thierry MERLE <thierry.merle@free.fr> | 2006-12-04 06:31:21 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-12-10 06:05:47 -0500 |
commit | 3084920b555b3ba73590430b2e03d9167db23e8e (patch) | |
tree | 005fcfefe5cb8edb6bf08c16ff35d1fb8aa268d0 /drivers/media | |
parent | 5f7fb877be14da92803f0b5b60955e071ebe2d58 (diff) |
V4L/DVB (4929): Read() implementation + format set/get simplifications
- implement read() entry point that works with linux list.h
- rework of VIDIOC_ENUM_FMT/VIDIOC_S_FMT/VIDIOC_G_FMT
- VIDIOC_STREAMON : allows streaming whereas there is no queued buffer
(xdtv does VIDIOC_STREAMON before VIDIOC_QBUFs)
Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/usbvision/usbvision-core.c | 323 |
1 files changed, 167 insertions, 156 deletions
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 5a61ed728b35..3833f3fbbdf0 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c | |||
@@ -409,7 +409,8 @@ | |||
409 | 409 | ||
410 | 410 | ||
411 | static int usbvision_nr = 0; // sequential number of usbvision device | 411 | static int usbvision_nr = 0; // sequential number of usbvision device |
412 | 412 | static unsigned long usbvision_timestamp = 0; // timestamp in jiffies of a hundred frame | |
413 | static unsigned long usbvision_counter = 0; // frame counter | ||
413 | 414 | ||
414 | static const int max_imgwidth = MAX_FRAME_WIDTH; | 415 | static const int max_imgwidth = MAX_FRAME_WIDTH; |
415 | static const int max_imgheight = MAX_FRAME_HEIGHT; | 416 | static const int max_imgheight = MAX_FRAME_HEIGHT; |
@@ -4278,6 +4279,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
4278 | list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); | 4279 | list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); |
4279 | spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); | 4280 | spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); |
4280 | 4281 | ||
4282 | PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index); | ||
4281 | return 0; | 4283 | return 0; |
4282 | } | 4284 | } |
4283 | case VIDIOC_DQBUF: | 4285 | case VIDIOC_DQBUF: |
@@ -4312,18 +4314,31 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
4312 | vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; | 4314 | vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; |
4313 | vb->index = f->index; | 4315 | vb->index = f->index; |
4314 | vb->sequence = f->sequence; | 4316 | vb->sequence = f->sequence; |
4317 | vb->timestamp = f->timestamp; | ||
4318 | vb->field = V4L2_FIELD_NONE; | ||
4319 | vb->bytesused = f->scanlength; | ||
4315 | 4320 | ||
4321 | if(debug & DBG_IOCTL) { // do not spend computing time for debug stuff if not needed ! | ||
4322 | if(usbvision_counter == 100) { | ||
4323 | PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF delta=%d",(unsigned)(jiffies-usbvision_timestamp)); | ||
4324 | usbvision_counter = 0; | ||
4325 | usbvision_timestamp = jiffies; | ||
4326 | } | ||
4327 | else { | ||
4328 | usbvision_counter++; | ||
4329 | } | ||
4330 | PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame #%d",vb->index); | ||
4331 | } | ||
4316 | return 0; | 4332 | return 0; |
4317 | } | 4333 | } |
4318 | case VIDIOC_STREAMON: | 4334 | case VIDIOC_STREAMON: |
4319 | { | 4335 | { |
4320 | int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; | 4336 | int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; |
4321 | 4337 | ||
4322 | if (list_empty(&usbvision->inqueue)) | ||
4323 | return -EINVAL; | ||
4324 | |||
4325 | usbvision->streaming = Stream_On; | 4338 | usbvision->streaming = Stream_On; |
4326 | 4339 | ||
4340 | if(debug & DBG_IOCTL) usbvision_timestamp = jiffies; | ||
4341 | |||
4327 | call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); | 4342 | call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); |
4328 | 4343 | ||
4329 | PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); | 4344 | PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); |
@@ -4412,134 +4427,132 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
4412 | { | 4427 | { |
4413 | struct v4l2_fmtdesc *vfd = arg; | 4428 | struct v4l2_fmtdesc *vfd = arg; |
4414 | 4429 | ||
4415 | if ( (dga == 0) && | ||
4416 | (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && | ||
4417 | (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && | ||
4418 | (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { | ||
4419 | return -EINVAL; | ||
4420 | } | ||
4421 | if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { | 4430 | if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { |
4422 | return -EINVAL; | 4431 | return -EINVAL; |
4423 | } | 4432 | } |
4424 | vfd->flags = 0; | 4433 | vfd->flags = 0; |
4434 | vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
4425 | strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); | 4435 | strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); |
4426 | vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; | 4436 | vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; |
4437 | memset(vfd->reserved, 0, sizeof(vfd->reserved)); | ||
4427 | return 0; | 4438 | return 0; |
4428 | } | 4439 | } |
4429 | case VIDIOC_G_FMT: | 4440 | case VIDIOC_G_FMT: |
4430 | { | 4441 | { |
4431 | struct v4l2_format *vf = arg; | 4442 | struct v4l2_format *vf = arg; |
4432 | 4443 | ||
4433 | if ( (dga == 0) && | 4444 | switch (vf->type) { |
4434 | (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && | 4445 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
4435 | (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && | 4446 | { |
4436 | (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { | 4447 | vf->fmt.pix.width = usbvision->curwidth; |
4437 | return -EINVAL; | 4448 | vf->fmt.pix.height = usbvision->curheight; |
4449 | vf->fmt.pix.pixelformat = usbvision->palette.format; | ||
4450 | vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel; | ||
4451 | vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; | ||
4452 | vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
4453 | vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ | ||
4454 | } | ||
4455 | return 0; | ||
4456 | default: | ||
4457 | PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type); | ||
4458 | return -EINVAL; | ||
4438 | } | 4459 | } |
4439 | down(&usbvision->lock); | 4460 | PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d",vf->fmt.win.w.width, vf->fmt.win.w.height); |
4440 | *vf = usbvision->vid_win; | ||
4441 | up(&usbvision->lock); | ||
4442 | PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", | ||
4443 | vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); | ||
4444 | return 0; | 4461 | return 0; |
4445 | } | 4462 | } |
4463 | case VIDIOC_TRY_FMT: | ||
4446 | case VIDIOC_S_FMT: | 4464 | case VIDIOC_S_FMT: |
4447 | { | 4465 | { |
4448 | struct v4l2_format *vf = arg; | 4466 | struct v4l2_format *vf = arg; |
4449 | struct v4l2_clip *vc=NULL; | 4467 | struct v4l2_clip *vc=NULL; |
4450 | int on,formatIdx; | 4468 | int on,formatIdx; |
4451 | 4469 | ||
4452 | if ( (dga == 0) && | 4470 | switch(vf->type) { |
4453 | (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && | 4471 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
4454 | (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && | 4472 | { |
4455 | (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { | 4473 | if (vf->fmt.win.clipcount>256) { |
4456 | return -EINVAL; | 4474 | return -EDOM; /* Too many clips! */ |
4457 | } | 4475 | } |
4458 | if(vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) { | 4476 | // Do every clips. |
4459 | if (vf->fmt.win.clipcount>256) { | 4477 | vc = vmalloc(sizeof(struct v4l2_clip)*(vf->fmt.win.clipcount+4)); |
4460 | return -EDOM; /* Too many clips! */ | 4478 | if (vc == NULL) { |
4461 | } | 4479 | return -ENOMEM; |
4462 | // Do every clips. | 4480 | } |
4463 | vc = vmalloc(sizeof(struct v4l2_clip)*(vf->fmt.win.clipcount+4)); | 4481 | if (vf->fmt.win.clipcount && copy_from_user(vc,vf->fmt.win.clips,sizeof(struct v4l2_clip)*vf->fmt.win.clipcount)) { |
4464 | if (vc == NULL) { | 4482 | return -EFAULT; |
4465 | return -ENOMEM; | 4483 | } |
4466 | } | 4484 | on = usbvision->overlay; // Save overlay state |
4467 | if (vf->fmt.win.clipcount && copy_from_user(vc,vf->fmt.win.clips,sizeof(struct v4l2_clip)*vf->fmt.win.clipcount)) { | 4485 | if (on) { |
4468 | return -EFAULT; | 4486 | usbvision_cap(usbvision, 0); |
4469 | } | 4487 | } |
4470 | on = usbvision->overlay; // Save overlay state | ||
4471 | if (on) { | ||
4472 | usbvision_cap(usbvision, 0); | ||
4473 | } | ||
4474 | 4488 | ||
4475 | // strange, it seems xawtv sometimes calls us with 0 | 4489 | // strange, it seems xawtv sometimes calls us with 0 |
4476 | // width and/or height. Ignore these values | 4490 | // width and/or height. Ignore these values |
4477 | if (vf->fmt.win.w.left == 0) { | 4491 | if (vf->fmt.win.w.left == 0) { |
4478 | vf->fmt.win.w.left = usbvision->vid_win.fmt.win.w.left; | 4492 | vf->fmt.win.w.left = usbvision->vid_win.fmt.win.w.left; |
4479 | } | 4493 | } |
4480 | if (vf->fmt.win.w.top == 0) { | 4494 | if (vf->fmt.win.w.top == 0) { |
4481 | vf->fmt.win.w.top = usbvision->vid_win.fmt.win.w.top; | 4495 | vf->fmt.win.w.top = usbvision->vid_win.fmt.win.w.top; |
4482 | } | 4496 | } |
4483 | 4497 | ||
4484 | // by now we are committed to the new data... | 4498 | // by now we are committed to the new data... |
4485 | down(&usbvision->lock); | 4499 | down(&usbvision->lock); |
4486 | RESTRICT_TO_RANGE(vf->fmt.win.w.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); | 4500 | RESTRICT_TO_RANGE(vf->fmt.win.w.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); |
4487 | RESTRICT_TO_RANGE(vf->fmt.win.w.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); | 4501 | RESTRICT_TO_RANGE(vf->fmt.win.w.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); |
4488 | usbvision->vid_win = *vf; | 4502 | usbvision->vid_win = *vf; |
4489 | usbvision->overlay_frame.width = vf->fmt.win.w.width; | 4503 | usbvision->overlay_frame.width = vf->fmt.win.w.width; |
4490 | usbvision->overlay_frame.height = vf->fmt.win.w.height; | 4504 | usbvision->overlay_frame.height = vf->fmt.win.w.height; |
4491 | usbvision_set_output(usbvision, vf->fmt.win.w.width, vf->fmt.win.w.height); | 4505 | usbvision_set_output(usbvision, vf->fmt.win.w.width, vf->fmt.win.w.height); |
4492 | up(&usbvision->lock); | 4506 | up(&usbvision->lock); |
4493 | 4507 | ||
4494 | // Impose display clips | 4508 | // Impose display clips |
4495 | if (vf->fmt.win.w.left+vf->fmt.win.w.width > (unsigned int)usbvision->vid_buf.fmt.width) { | 4509 | if (vf->fmt.win.w.left+vf->fmt.win.w.width > (unsigned int)usbvision->vid_buf.fmt.width) { |
4496 | usbvision_new_clip(vf, vc, usbvision->vid_buf.fmt.width-vf->fmt.win.w.left, 0, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); | 4510 | usbvision_new_clip(vf, vc, usbvision->vid_buf.fmt.width-vf->fmt.win.w.left, 0, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); |
4497 | } | 4511 | } |
4498 | if (vf->fmt.win.w.top+vf->fmt.win.w.height > (unsigned int)usbvision->vid_buf.fmt.height) { | 4512 | if (vf->fmt.win.w.top+vf->fmt.win.w.height > (unsigned int)usbvision->vid_buf.fmt.height) { |
4499 | usbvision_new_clip(vf, vc, 0, usbvision->vid_buf.fmt.height-vf->fmt.win.w.top, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); | 4513 | usbvision_new_clip(vf, vc, 0, usbvision->vid_buf.fmt.height-vf->fmt.win.w.top, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); |
4500 | } | 4514 | } |
4501 | 4515 | ||
4502 | // built the requested clipping zones | 4516 | // built the requested clipping zones |
4503 | usbvision_built_overlay(usbvision, vf->fmt.win.clipcount, vc); | 4517 | usbvision_built_overlay(usbvision, vf->fmt.win.clipcount, vc); |
4504 | vfree(vc); | 4518 | vfree(vc); |
4505 | 4519 | ||
4506 | // restore overlay state | 4520 | // restore overlay state |
4507 | if (on) { | 4521 | if (on) { |
4508 | usbvision_cap(usbvision, 1); | 4522 | usbvision_cap(usbvision, 1); |
4523 | } | ||
4524 | usbvision->vid_win_valid = 1; | ||
4525 | PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT overlay x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", | ||
4526 | vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); | ||
4527 | return 0; | ||
4509 | } | 4528 | } |
4510 | usbvision->vid_win_valid = 1; | 4529 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
4511 | PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT overlay x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", | 4530 | { |
4512 | vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); | 4531 | /* Find requested format in available ones */ |
4513 | } | 4532 | for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) { |
4514 | else { | 4533 | if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { |
4515 | /* Find requested format in available ones */ | 4534 | usbvision->palette = usbvision_v4l2_format[formatIdx]; |
4516 | for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) { | 4535 | break; |
4517 | if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { | 4536 | } |
4518 | usbvision->palette = usbvision_v4l2_format[formatIdx]; | 4537 | } |
4519 | break; | 4538 | /* robustness */ |
4539 | if(formatIdx == USBVISION_SUPPORTED_PALETTES) { | ||
4540 | return -EINVAL; | ||
4520 | } | 4541 | } |
4542 | RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); | ||
4543 | RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); | ||
4544 | // by now we are committed to the new data... | ||
4545 | down(&usbvision->lock); | ||
4546 | usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); | ||
4547 | up(&usbvision->lock); | ||
4548 | |||
4549 | PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s", | ||
4550 | vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); | ||
4551 | return 0; | ||
4521 | } | 4552 | } |
4522 | /* robustness */ | 4553 | default: |
4523 | if(formatIdx == USBVISION_SUPPORTED_PALETTES) { | ||
4524 | return -EINVAL; | 4554 | return -EINVAL; |
4525 | } | ||
4526 | usbvision->vid_win.fmt.pix.pixelformat = vf->fmt.pix.pixelformat; | ||
4527 | usbvision->vid_win.fmt.pix.width = vf->fmt.pix.width; //Image width in pixels. | ||
4528 | usbvision->vid_win.fmt.pix.height = vf->fmt.pix.height; // Image height in pixels. | ||
4529 | |||
4530 | // by now we are committed to the new data... | ||
4531 | down(&usbvision->lock); | ||
4532 | RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); | ||
4533 | RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); | ||
4534 | usbvision->vid_win = *vf; | ||
4535 | usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); | ||
4536 | up(&usbvision->lock); | ||
4537 | |||
4538 | usbvision->vid_win_valid = 1; | ||
4539 | PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, ", | ||
4540 | vf->fmt.pix.width, vf->fmt.pix.height); | ||
4541 | } | 4555 | } |
4542 | return 0; | ||
4543 | } | 4556 | } |
4544 | case VIDIOC_OVERLAY: | 4557 | case VIDIOC_OVERLAY: |
4545 | { | 4558 | { |
@@ -4586,99 +4599,97 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, | |||
4586 | struct video_device *dev = video_devdata(file); | 4599 | struct video_device *dev = video_devdata(file); |
4587 | struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); | 4600 | struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); |
4588 | int noblock = file->f_flags & O_NONBLOCK; | 4601 | int noblock = file->f_flags & O_NONBLOCK; |
4602 | unsigned long lock_flags; | ||
4589 | 4603 | ||
4590 | int frmx = -1; | 4604 | int frmx = -1; |
4591 | int rc = 0; | 4605 | int ret,i; |
4592 | struct usbvision_frame *frame; | 4606 | struct usbvision_frame *frame; |
4593 | return -EINVAL; | 4607 | |
4594 | PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); | 4608 | PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); |
4595 | 4609 | ||
4596 | if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) | 4610 | if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) |
4597 | return -EFAULT; | 4611 | return -EFAULT; |
4598 | 4612 | ||
4599 | down(&usbvision->lock); | 4613 | /* no stream is running, make it running ! */ |
4600 | //code for testing compression | 4614 | usbvision->streaming = Stream_On; |
4601 | if (usbvision->isocMode == ISOC_MODE_COMPRESS) { | 4615 | call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); |
4602 | usbvision->frame[0].v4l2_format = usbvision_v4l2_format[0]; //V4L2_PIX_FMT_GREY; | ||
4603 | usbvision->frame[1].v4l2_format = usbvision_v4l2_format[0]; // V4L2_PIX_FMT_GREY; | ||
4604 | } | ||
4605 | 4616 | ||
4606 | // See if a frame is completed, then use it. | 4617 | /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */ |
4607 | if (usbvision->frame[0].grabstate >= FrameState_Done) // _Done or _Error | 4618 | for(i=0;i<USBVISION_NUMFRAMES;i++) { |
4608 | frmx = 0; | 4619 | frame = &usbvision->frame[i]; |
4609 | else if (usbvision->frame[1].grabstate >= FrameState_Done)// _Done or _Error | 4620 | if(frame->grabstate == FrameState_Unused) { |
4610 | frmx = 1; | 4621 | /* Mark it as ready and enqueue frame */ |
4622 | frame->grabstate = FrameState_Ready; | ||
4623 | frame->scanstate = ScanState_Scanning; | ||
4624 | frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ | ||
4611 | 4625 | ||
4612 | if (noblock && (frmx == -1)) { | 4626 | /* set v4l2_format index */ |
4613 | count = -EAGAIN; | 4627 | frame->v4l2_format = usbvision->palette; |
4614 | goto usbvision_v4l2_read_done; | ||
4615 | } | ||
4616 | 4628 | ||
4617 | // If no FRAME_DONE, look for a FRAME_GRABBING state. | 4629 | spin_lock_irqsave(&usbvision->queue_lock, lock_flags); |
4618 | // See if a frame is in process (grabbing), then use it. | 4630 | list_add_tail(&frame->frame, &usbvision->inqueue); |
4619 | if (frmx == -1) { | 4631 | spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); |
4620 | if (usbvision->frame[0].grabstate == FrameState_Grabbing) | 4632 | } |
4621 | frmx = 0; | ||
4622 | else if (usbvision->frame[1].grabstate == FrameState_Grabbing) | ||
4623 | frmx = 1; | ||
4624 | } | 4633 | } |
4625 | 4634 | ||
4626 | // If no frame is active, start one. | 4635 | /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */ |
4627 | if (frmx == -1) | 4636 | if (list_empty(&(usbvision->outqueue))) { |
4628 | // FIXME: enqueue all inqueue... | 4637 | if(noblock) |
4629 | /* usbvision_new_frame(usbvision, frmx = 0); */ | 4638 | return -EAGAIN; |
4630 | |||
4631 | frame = &usbvision->frame[frmx]; | ||
4632 | 4639 | ||
4633 | restart: | 4640 | ret = wait_event_interruptible |
4634 | if (!USBVISION_IS_OPERATIONAL(usbvision)) { | 4641 | (usbvision->wait_frame, |
4635 | count = -EIO; | 4642 | !list_empty(&(usbvision->outqueue))); |
4636 | goto usbvision_v4l2_read_done; | 4643 | if (ret) |
4644 | return ret; | ||
4637 | } | 4645 | } |
4638 | PDEBUG(DBG_IO, "Waiting frame grabbing"); | 4646 | |
4639 | rc = wait_event_interruptible(usbvision->wait_frame, (frame->grabstate == FrameState_Done) || | 4647 | spin_lock_irqsave(&usbvision->queue_lock, lock_flags); |
4640 | (frame->grabstate == FrameState_Error)); | 4648 | frame = list_entry(usbvision->outqueue.next, |
4641 | if (rc) { | 4649 | struct usbvision_frame, frame); |
4642 | goto usbvision_v4l2_read_done; | 4650 | list_del(usbvision->outqueue.next); |
4651 | spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); | ||
4652 | |||
4653 | if(debug & DBG_IOCTL) { // do not spend computing time for debug stuff if not needed ! | ||
4654 | if(usbvision_counter == 100) { | ||
4655 | PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF delta=%d",(unsigned)(jiffies-usbvision_timestamp)); | ||
4656 | usbvision_counter = 0; | ||
4657 | usbvision_timestamp = jiffies; | ||
4658 | } | ||
4659 | else { | ||
4660 | usbvision_counter++; | ||
4661 | } | ||
4643 | } | 4662 | } |
4644 | 4663 | ||
4664 | /* An error returns an empty frame */ | ||
4645 | if (frame->grabstate == FrameState_Error) { | 4665 | if (frame->grabstate == FrameState_Error) { |
4646 | frame->bytes_read = 0; | 4666 | frame->bytes_read = 0; |
4647 | // FIXME: enqueue all inqueue... | 4667 | return 0; |
4648 | /* if (usbvision_new_frame(usbvision, frmx)) { */ | ||
4649 | /* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ | ||
4650 | /* } */ | ||
4651 | goto restart; | ||
4652 | } | 4668 | } |
4653 | 4669 | ||
4654 | PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, | 4670 | PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, |
4655 | frmx, frame->bytes_read, frame->scanlength); | 4671 | frame->index, frame->bytes_read, frame->scanlength); |
4656 | 4672 | ||
4657 | /* copy bytes to user space; we allow for partials reads */ | 4673 | /* copy bytes to user space; we allow for partials reads */ |
4658 | if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) | 4674 | if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) |
4659 | count = frame->scanlength - frame->bytes_read; | 4675 | count = frame->scanlength - frame->bytes_read; |
4660 | 4676 | ||
4661 | if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { | 4677 | if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { |
4662 | count = -EFAULT; | 4678 | return -EFAULT; |
4663 | goto usbvision_v4l2_read_done; | ||
4664 | } | 4679 | } |
4665 | 4680 | ||
4666 | frame->bytes_read += count; | 4681 | frame->bytes_read += count; |
4667 | PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, | 4682 | PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, |
4668 | (unsigned long)count, frame->bytes_read); | 4683 | (unsigned long)count, frame->bytes_read); |
4669 | 4684 | ||
4670 | if (frame->bytes_read >= frame->scanlength) {// All data has been read | 4685 | // For now, forget the frame if it has not been read in one shot. |
4686 | /* if (frame->bytes_read >= frame->scanlength) {// All data has been read */ | ||
4671 | frame->bytes_read = 0; | 4687 | frame->bytes_read = 0; |
4672 | 4688 | ||
4673 | /* Mark it as available to be used again. */ | 4689 | /* Mark it as available to be used again. */ |
4674 | usbvision->frame[frmx].grabstate = FrameState_Unused; | 4690 | usbvision->frame[frmx].grabstate = FrameState_Unused; |
4675 | // FIXME enqueue another frame | 4691 | /* } */ |
4676 | /* if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) */ | ||
4677 | /* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ | ||
4678 | } | ||
4679 | 4692 | ||
4680 | usbvision_v4l2_read_done: | ||
4681 | up(&usbvision->lock); | ||
4682 | return count; | 4693 | return count; |
4683 | } | 4694 | } |
4684 | 4695 | ||