From: Thierry MERLE Date: Mon, 4 Dec 2006 11:31:14 +0000 (-0300) Subject: V4L/DVB (4927): Enhancements on usbvision driver X-Git-Tag: v2.6.20-rc1~145^2~5^2~26 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f2242ee5474f46d87a45cd4e214b5c3aa02ff293;p=linux-2.6 V4L/DVB (4927): Enhancements on usbvision driver Enhance the buffer management of this driver + some corrections - linux list.h usage for buffer management - VIDIOC_ENUMSTD/VIDIOC_G_STD/VIDIOC_S_STD simplification (use of v4l2_video_std_construct) - create_sysfs : remove of warnings for video_device_create_file return code - make the driver compatible with 2.6.19 kernel version (remove slave_send and slave_recv in usbvision-i2c, change ctrlUrb_complete function prototype) - deactivated v4l2_read because this code was not the priority but working on it :) Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index f225701f16..06e8e67da3 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -437,6 +437,25 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } }; +/* supported tv norms */ +static struct usbvision_tvnorm tvnorms[] = { + { + .name = "PAL", + .id = V4L2_STD_PAL, + }, { + .name = "NTSC", + .id = V4L2_STD_NTSC, + }, { + .name = "SECAM", + .id = V4L2_STD_SECAM, + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + } +}; + +#define TVNORMS ARRAY_SIZE(tvnorms) + /* * The value of 'scratch_buf_size' affects quality of the picture @@ -451,7 +470,7 @@ static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE; // Function prototypes static int usbvision_restart_isoc(struct usb_usbvision *usbvision); static int usbvision_begin_streaming(struct usb_usbvision *usbvision); -static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm); +static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel); static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, short len); static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, short len); static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); @@ -463,6 +482,8 @@ static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision); static void usbvision_release(struct usb_usbvision *usbvision); static int usbvision_set_input(struct usb_usbvision *usbvision); static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); +static void usbvision_empty_framequeues(struct usb_usbvision *dev); +static int usbvision_stream_interrupt(struct usb_usbvision *dev); static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg); @@ -609,7 +630,7 @@ static ssize_t show_streaming(struct class_device *class_dev, char *buf) { struct video_device *vdev = to_video_device(class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->streaming)); + return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); @@ -639,17 +660,18 @@ static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { + int res; if (vdev) { - video_device_create_file(vdev, &class_device_attr_version); - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_hue); - video_device_create_file(vdev, &class_device_attr_contrast); - video_device_create_file(vdev, &class_device_attr_brightness); - video_device_create_file(vdev, &class_device_attr_saturation); - video_device_create_file(vdev, &class_device_attr_streaming); - video_device_create_file(vdev, &class_device_attr_overlay); - video_device_create_file(vdev, &class_device_attr_compression); - video_device_create_file(vdev, &class_device_attr_bridge); + res=video_device_create_file(vdev, &class_device_attr_version); + res=video_device_create_file(vdev, &class_device_attr_model); + res=video_device_create_file(vdev, &class_device_attr_hue); + res=video_device_create_file(vdev, &class_device_attr_contrast); + res=video_device_create_file(vdev, &class_device_attr_brightness); + res=video_device_create_file(vdev, &class_device_attr_saturation); + res=video_device_create_file(vdev, &class_device_attr_streaming); + res=video_device_create_file(vdev, &class_device_attr_overlay); + res=video_device_create_file(vdev, &class_device_attr_compression); + res=video_device_create_file(vdev, &class_device_attr_bridge); } } @@ -1209,15 +1231,13 @@ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, printk(KERN_ERR "%s: usbvision == NULL\n", proc); return; } - if ((usbvision->curFrameNum < 0) - || (usbvision->curFrameNum >= USBVISION_NUMFRAMES)) { - printk(KERN_ERR "%s: usbvision->curFrameNum=%d.\n", proc, - usbvision->curFrameNum); + if (usbvision->curFrame == NULL) { + printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc); return; } /* Grab the current frame */ - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; /* Optionally start at the beginning */ if (fullframe) { @@ -1290,7 +1310,7 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) frame = &usbvision->overlay_frame; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; } while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) { @@ -1325,7 +1345,6 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width; frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height; frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3; - usbvision->curFrame = frame; } else { // no header found PDEBUG(DBG_HEADER, "skipping scratch data, no header"); @@ -1380,7 +1399,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision usbvision->vid_buf.fmt.bytesperline; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; f = frame->data + (frame->v4l2_linesize * frame->curline); } @@ -1612,7 +1631,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, usbvision->vid_buf.fmt.bytesperline; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; imageSize = frame->frmwidth * frame->frmheight; if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) @@ -1833,7 +1852,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision f_odd = f_even + usbvision->vid_buf.fmt.bytesperline * usbvision->stretch_height; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; f_even = frame->data + (frame->v4l2_linesize * frame->curline); f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; } @@ -2088,17 +2107,17 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) struct usbvision_frame *frame; enum ParseState newstate; long copylen = 0; + unsigned long lock_flags; if (usbvision->overlay) { frame = &usbvision->overlay_frame; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; } PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision)); - while (1) { newstate = ParseState_Out; @@ -2141,7 +2160,10 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) copylen = 0; } else { - usbvision->curFrameNum = -1; + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_move_tail(&(frame->frame), &usbvision->outqueue); + usbvision->curFrame = NULL; + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); } usbvision->frame_num++; @@ -2150,10 +2172,14 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) usbvision_osd_stats(usbvision, frame); /* This will cause the process to request another frame. */ - if (waitqueue_active(&frame->wq)) { - wake_up_interruptible(&frame->wq); + if (waitqueue_active(&usbvision->wait_frame)) { + PDEBUG(DBG_PARSE, "Wake up !"); + wake_up_interruptible(&usbvision->wait_frame); } } + else + frame->grabstate = FrameState_Grabbing; + /* Update the frame's uncompressed length. */ frame->scanlength += copylen; @@ -2164,7 +2190,7 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) * Make all of the blocks of data contiguous */ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, - struct urb *urb) + struct urb *urb) { unsigned char *packet_data; int i, totlen = 0; @@ -2246,51 +2272,70 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) { - int errCode = 0; - int len; - struct usb_usbvision *usbvision = urb->context; - int i; - unsigned long startTime = jiffies; - - /* We don't want to do anything if we are about to be removed! */ - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return; + int errCode = 0; + int len; + struct usb_usbvision *usbvision = urb->context; + int i; + unsigned long startTime = jiffies; + struct usbvision_frame **f; - if (!usbvision->streaming) { - PDEBUG(DBG_IRQ, "oops, not streaming, but interrupt"); - return; - } + /* We don't want to do anything if we are about to be removed! */ + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return; - /* Copy the data received into our scratch buffer */ - len = usbvision_compress_isochronous(usbvision, urb); + f = &usbvision->curFrame; - usbvision->isocUrbCount++; - usbvision->urb_length = len; + /* Manage streaming interruption */ + if (usbvision->streaming == Stream_Interrupt) { + usbvision->streaming = Stream_Off; + if ((*f)) { + (*f)->grabstate = FrameState_Ready; + (*f)->scanstate = ScanState_Scanning; + } + PDEBUG(DBG_IRQ, "stream interrupted"); + wake_up_interruptible(&usbvision->wait_stream); + } - for (i = 0; i < USBVISION_URB_FRAMES; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - urb->dev = usbvision->dev; - errCode = usb_submit_urb (urb, GFP_ATOMIC); + /* Copy the data received into our scratch buffer */ + len = usbvision_compress_isochronous(usbvision, urb); -/* Disable this warning. By design of the driver. */ -// if(errCode) { -// err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode); -// } + usbvision->isocUrbCount++; + usbvision->urb_length = len; - /* If we collected enough data let's parse! */ - if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ - /*If we don't have a frame we're current working on, complain */ - if ((usbvision->curFrameNum >= 0) || (usbvision->overlay)) - usbvision_parse_data(usbvision); - else { - PDEBUG(DBG_IRQ, "received data, but no one needs it"); - scratch_reset(usbvision); + if (usbvision->streaming == Stream_On) { + + /* If we collected enough data let's parse! */ + if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ + /*If we don't have a frame we're current working on, complain */ + if((!list_empty(&(usbvision->inqueue))) || (usbvision->overlay)) { + if (!(*f)) { + (*f) = list_entry(usbvision->inqueue.next,struct usbvision_frame, frame); + } + usbvision_parse_data(usbvision); + } + else { + PDEBUG(DBG_IRQ, "received data, but no one needs it"); + scratch_reset(usbvision); + } } } + usbvision->timeInIrq += jiffies - startTime; + + for (i = 0; i < USBVISION_URB_FRAMES; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + + urb->status = 0; + urb->dev = usbvision->dev; + errCode = usb_submit_urb (urb, GFP_ATOMIC); + + /* Disable this warning. By design of the driver. */ + // if(errCode) { + // err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode); + // } + return; } @@ -2539,7 +2584,6 @@ static int attach_inform(struct i2c_client *client) struct usb_usbvision *usbvision; struct tuner_setup tun_addr; int i; - v4l2_std_id stdId; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) usbvision = (struct usb_usbvision *)client->adapter->data; @@ -2560,13 +2604,11 @@ static int attach_inform(struct i2c_client *client) tun_addr.type = usbvision->tuner_type; tun_addr.addr = ADDR_UNSET; client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); - - call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); + call_i2c_clients(usbvision, VIDIOC_INT_RESET, NULL); + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input); + call_i2c_clients(usbvision, VIDIOC_STREAMON, NULL); } - // FIXME : need to add a call VIDIOC_S_CTRL for each control -/* call_i2c_clients(usbvision, DECODER_SET_PICTURE, &usbvision->vpic); */ - stdId = usbvision->input.std; - call_i2c_clients(usbvision, VIDIOC_S_STD, &stdId); + call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnorm->id); PDEBUG(DBG_I2C, "usbvision[%d] attaches %s", usbvision->nr, client->name); @@ -2995,10 +3037,10 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, frameRate = FRAMERATE_MAX; } - if (usbvision->input.std & V4L2_STD_625_50) { + if (usbvision->tvnorm->id & V4L2_STD_625_50) { frameDrop = frameRate * 32 / 25 - 1; } - else if (usbvision->input.std & V4L2_STD_525_60) { + else if (usbvision->tvnorm->id & V4L2_STD_525_60) { frameDrop = frameRate * 32 / 30 - 1; } @@ -3021,6 +3063,40 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, } +/* + * usbvision_empty_framequeues() + * prepare queues for incoming and outgoing frames + */ +static void usbvision_empty_framequeues(struct usb_usbvision *usbvision) +{ + u32 i; + + INIT_LIST_HEAD(&(usbvision->inqueue)); + INIT_LIST_HEAD(&(usbvision->outqueue)); + + for (i = 0; i < USBVISION_NUMFRAMES; i++) { + usbvision->frame[i].grabstate = FrameState_Unused; + usbvision->frame[i].bytes_read = 0; + } +} + +/* + * usbvision_stream_interrupt() + * stops streaming + */ +static int usbvision_stream_interrupt(struct usb_usbvision *usbvision) +{ + int ret = 0; + + /* stop reading from the device */ + + usbvision->streaming = Stream_Interrupt; + ret = wait_event_timeout(usbvision->wait_stream, + (usbvision->streaming == Stream_Off), + msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES)); + return ret; +} + /* * usbvision_set_compress_params() * @@ -3135,7 +3211,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) } - if (usbvision->input.std & V4L2_STD_PAL) { + if (usbvision->tvnorm->id & V4L2_STD_PAL) { value[0] = 0xC0; value[1] = 0x02; //0x02C0 -> 704 Input video line length value[2] = 0x20; @@ -3144,7 +3220,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) value[5] = 0x00; //0x0060 -> 96 Input video h offset value[6] = 0x16; value[7] = 0x00; //0x0016 -> 22 Input video v offset - } else if (usbvision->input.std & V4L2_STD_SECAM) { + } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) { value[0] = 0xC0; value[1] = 0x02; //0x02C0 -> 704 Input video line length value[2] = 0x20; @@ -3434,7 +3510,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) if (!USBVISION_IS_OPERATIONAL(usbvision)) return -EFAULT; - usbvision->curFrameNum = -1; + usbvision->curFrame = NULL; scratch_reset(usbvision); /* Alternate interface 1 is is the biggest frame size */ @@ -3503,7 +3579,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) } } - usbvision->streaming = 1; + usbvision->streaming = Stream_On; PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp); return 0; } @@ -3519,7 +3595,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) { int bufIdx, errCode, regValue; - if (!usbvision->streaming || (usbvision->dev == NULL)) + // FIXME : removed the streaming==Stream_Off. This field has not the same signification than before ! + if (usbvision->dev == NULL) return; /* Unschedule all of the iso td's */ @@ -3530,9 +3607,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) } - PDEBUG(DBG_ISOC, "%s: streaming=0\n", __FUNCTION__); - usbvision->streaming = 0; - + PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__); + usbvision->streaming = Stream_Off; if (!usbvision->remove_pending) { @@ -3552,62 +3628,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) } } -/* - * usbvision_new_frame() - * - */ -static int usbvision_new_frame(struct usb_usbvision *usbvision, int framenum) -{ - struct usbvision_frame *frame; - int n; //byhec , width, height; - - /* If we're not grabbing a frame right now and the other frame is */ - /* ready to be grabbed into, then use it instead */ - if (usbvision->curFrameNum != -1) - return 0; - - n = (framenum - 1 + USBVISION_NUMFRAMES) % USBVISION_NUMFRAMES; - if (usbvision->frame[n].grabstate == FrameState_Ready) - framenum = n; - - frame = &usbvision->frame[framenum]; - - frame->grabstate = FrameState_Grabbing; - frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ - usbvision->curFrameNum = framenum; - - /* - * Normally we would want to copy previous frame into the current one - * before we even start filling it with data; this allows us to stop - * filling at any moment; top portion of the frame will be new and - * bottom portion will stay as it was in previous frame. If we don't - * do that then missing chunks of video stream will result in flickering - * portions of old data whatever it was before. - * - * If we choose not to copy previous frame (to, for example, save few - * bus cycles - the frame can be pretty large!) then we have an option - * to clear the frame before using. If we experience losses in this - * mode then missing picture will be black (flickering). - * - * Finally, if user chooses not to clean the current frame before - * filling it with data then the old data will be visible if we fail - * to refill entire frame with new data. - */ - if (!(flags & FLAGS_SEPARATE_FRAMES)) { - /* This copies previous frame into this one to mask losses */ - memmove(frame->data, usbvision->frame[1 - framenum].data, - MAX_FRAME_SIZE); - } else { - if (flags & FLAGS_CLEAN_FRAMES) { - /*This provides a "clean" frame but slows things down */ - memset(frame->data, 0, MAX_FRAME_SIZE); - } - } - return 0; -} - -static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm) +static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) { int mode[4]; int audio[]= {1, 0, 0, 0}; @@ -3618,16 +3639,10 @@ static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int no //channel 3 is additional video inputs to the device with audio channel 0 (line in) RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs); - /* set the new video norm */ - if (usbvision->input.std != norm) { - v4l2_std_id video_command = norm; - + usbvision->ctl_input = channel; route.input = SAA7115_COMPOSITE1; call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); - call_i2c_clients(usbvision, VIDIOC_S_STD, &video_command); - usbvision->input.std = norm; - call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); //set norm in tuner - } + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input); // set the new channel // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video @@ -3703,8 +3718,13 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) errCode = -ENOMEM; } else { + spin_lock_init(&usbvision->queue_lock); + init_waitqueue_head(&usbvision->wait_frame); + init_waitqueue_head(&usbvision->wait_stream); + /* Allocate all buffers */ for (i = 0; i < USBVISION_NUMFRAMES; i++) { + usbvision->frame[i].index = i; usbvision->frame[i].grabstate = FrameState_Unused; usbvision->frame[i].data = usbvision->fbuf + i * MAX_FRAME_SIZE; @@ -3804,6 +3824,9 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) if (errCode) { } + /* prepare queues */ + usbvision_empty_framequeues(usbvision); + PDEBUG(DBG_IO, "success"); return errCode; } @@ -3875,6 +3898,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, if (!USBVISION_IS_OPERATIONAL(usbvision)) return -EFAULT; + // if (debug & DBG_IOCTL) v4l_printk_ioctl(cmd); + switch (cmd) { case UVIOCSREG: { @@ -3914,7 +3939,20 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_QUERYCAP: { struct v4l2_capability *vc=arg; - *vc = usbvision->vcap; + + memset(vc, 0, sizeof(*vc)); + strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); + strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, + sizeof(vc->card)); + strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + sizeof(vc->bus_info)); + vc->version = USBVISION_DRIVER_VERSION; + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | + (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP"); return 0; } @@ -3975,38 +4013,24 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_ENUMSTD: { - struct v4l2_standard *vs = arg; - switch(vs->index) { - case 0: - vs->id = V4L2_STD_PAL; - strcpy(vs->name,"PAL"); - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - break; - case 1: - vs->id = V4L2_STD_NTSC; - strcpy(vs->name,"NTSC"); - vs->frameperiod.numerator = 1001; - vs->frameperiod.denominator = 30000; - vs->framelines = 525; - break; - case 2: - vs->id = V4L2_STD_SECAM; - strcpy(vs->name,"SECAM"); - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - break; - default: + struct v4l2_standard *e = arg; + unsigned int i; + int ret; + + i = e->index; + if (i >= TVNORMS) return -EINVAL; - } + ret = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + e->index = i; + if (ret < 0) + return ret; return 0; } case VIDIOC_G_INPUT: { int *input = arg; - *input = usbvision->input.index; + *input = usbvision->ctl_input; return 0; } case VIDIOC_S_INPUT: @@ -4014,10 +4038,10 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, int *input = arg; if ((*input >= usbvision->video_inputs) || (*input < 0) ) return -EINVAL; - usbvision->input.index = *input; + usbvision->ctl_input = *input; down(&usbvision->lock); - usbvision_muxsel(usbvision, usbvision->input.index, usbvision->input.std); + usbvision_muxsel(usbvision, usbvision->ctl_input); usbvision_set_input(usbvision); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); up(&usbvision->lock); @@ -4025,43 +4049,50 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_G_STD: { - v4l2_std_id *std = arg; - *std = usbvision->input.std; - PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%x", (unsigned)*std); + v4l2_std_id *id = arg; + + *id = usbvision->tvnorm->id; + + PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name); return 0; } case VIDIOC_S_STD: { - v4l2_std_id *std = arg; + v4l2_std_id *id = arg; + unsigned int i; + + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; down(&usbvision->lock); - usbvision_muxsel(usbvision, usbvision->input.index, *std); - usbvision_set_input(usbvision); - usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); + usbvision->tvnorm = &tvnorms[i]; + + call_i2c_clients(usbvision, VIDIOC_S_STD, + &usbvision->tvnorm->id); + up(&usbvision->lock); - usbvision->input.std = *std; - PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%x", (unsigned)*std); + PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name); return 0; } case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; - struct v4l2_tuner status; if (!usbvision->have_tuner || vt->index) // Only tuner 0 return -EINVAL; strcpy(vt->name, "Television"); - vt->type = V4L2_TUNER_ANALOG_TV; - vt->capability = V4L2_TUNER_CAP_NORM; - vt->rangelow = 0; - vt->rangehigh = ~0; - vt->audmode = V4L2_TUNER_MODE_MONO; - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - call_i2c_clients(usbvision,VIDIOC_G_TUNER,&status); - vt->signal = status.signal; - - PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER"); + /* Let clients fill in the remainder of this struct */ + call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); + + PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc); return 0; } case VIDIOC_S_TUNER: @@ -4071,15 +4102,16 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, // Only no or one tuner for now if (!usbvision->have_tuner || vt->index) return -EINVAL; - // FIXME vt->audmode Radio mode (STEREO/MONO/...) - // vt->reserved Radio freq - // usbvision_muxsel(usbvision, vt->index, vt->mode); + /* let clients handle this */ + call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); + PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *freq = arg; + freq->tuner = 0; // Only one tuner freq->type = V4L2_TUNER_ANALOG_TV; freq->frequency = usbvision->freq; @@ -4089,6 +4121,11 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *freq = arg; + + // Only no or one tuner for now + if (!usbvision->have_tuner || freq->tuner) + return -EINVAL; + usbvision->freq = freq->frequency; call_i2c_clients(usbvision, cmd, freq); PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); @@ -4149,11 +4186,27 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *vr = arg; - // FIXME : normally we allocate the requested number of buffers. - // this driver allocates statically the buffers. - vr->count = 2; - if(vr->memory != V4L2_MEMORY_MMAP) + int ret; + + RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); + + // Check input validity : the user must do a VIDEO CAPTURE and MMAP method. + if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vr->memory != V4L2_MEMORY_MMAP)) return -EINVAL; + + // FIXME : before this, we must control if buffers are still mapped. + // Then interrupt streaming if so... + if(usbvision->streaming == Stream_On) { + if ((ret = usbvision_stream_interrupt(usbvision))) + return ret; + } + + usbvision_empty_framequeues(usbvision); + + usbvision->curFrame = NULL; + + PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count); return 0; } case VIDIOC_QUERYBUF: @@ -4161,16 +4214,18 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, struct v4l2_buffer *vb = arg; struct usbvision_frame *frame; - // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. + // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called) + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { return -EINVAL; } - if(vb->index>1) { + if(vb->index>=USBVISION_NUMFRAMES) { return -EINVAL; } + // Updating the corresponding frame state vb->flags = 0; frame = &usbvision->frame[vb->index]; - if(frame->grabstate == FrameState_Grabbing) + if(frame->grabstate >= FrameState_Ready) vb->flags |= V4L2_BUF_FLAG_QUEUED; if(frame->grabstate >= FrameState_Done) vb->flags |= V4L2_BUF_FLAG_DONE; @@ -4183,119 +4238,115 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, else { vb->m.offset = MAX_FRAME_SIZE; } + vb->memory = V4L2_MEMORY_MMAP; + vb->field = V4L2_FIELD_NONE; vb->length = MAX_FRAME_SIZE; vb->timestamp = usbvision->frame[vb->index].timestamp; - vb->sequence = usbvision->frame_num; + vb->sequence = usbvision->frame[vb->index].sequence; return 0; } - case VIDIOC_QBUF: // VIDIOCMCAPTURE + VIDIOCSYNC + case VIDIOC_QBUF: { struct v4l2_buffer *vb = arg; struct usbvision_frame *frame; + unsigned long lock_flags; // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { return -EINVAL; } - if(vb->index>1) { + if(vb->index>=USBVISION_NUMFRAMES) { return -EINVAL; } frame = &usbvision->frame[vb->index]; - if (frame->grabstate == FrameState_Grabbing) { - return -EBUSY; + if (frame->grabstate != FrameState_Unused) { + return -EAGAIN; } - usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - - /* Mark it as ready */ + /* Mark it as ready and enqueue frame */ frame->grabstate = FrameState_Ready; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + vb->flags &= ~V4L2_BUF_FLAG_DONE; /* set v4l2_format index */ frame->v4l2_format = usbvision->palette; - PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame=%d",vb->index); - return usbvision_new_frame(usbvision, vb->index); + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + return 0; } case VIDIOC_DQBUF: { struct v4l2_buffer *vb = arg; - int errCode = 0; + int ret; + struct usbvision_frame *f; + unsigned long lock_flags; - DECLARE_WAITQUEUE(wait, current); - // FIXME : not the proper way to get the last filled frame - vb->index=-1; - if(usbvision->curFrameNum != -1) vb->index=usbvision->curFrameNum; - else { - if(usbvision->frame[1].grabstate >= FrameState_Done) - vb->index = 1; - else if(usbvision->frame[0].grabstate >= FrameState_Done) - vb->index = 0; - // If no FRAME_DONE, look for a FRAME_GRABBING state. - // See if a frame is in process (grabbing), then use it. - if (vb->index == -1) { - if (usbvision->frame[1].grabstate == FrameState_Grabbing) - vb->index = 1; - else if (usbvision->frame[0].grabstate == FrameState_Grabbing) - vb->index = 0; - } - } - if (vb->index == -1) + if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame=%d, grabstate=%d, curframeNum=%d", - vb->index, usbvision->frame[vb->index].grabstate,usbvision->curFrameNum); - - switch (usbvision->frame[vb->index].grabstate) { - case FrameState_Unused: - errCode = -EINVAL; - break; - case FrameState_Grabbing: - add_wait_queue(&usbvision->frame[vb->index].wq, &wait); - current->state = TASK_INTERRUPTIBLE; - while (usbvision->frame[vb->index].grabstate == FrameState_Grabbing) { - schedule(); - if (signal_pending(current)) { - remove_wait_queue(&usbvision->frame[vb->index].wq, &wait); - current->state = TASK_RUNNING; - return -EINTR; - } - } - remove_wait_queue(&usbvision->frame[vb->index].wq, &wait); - current->state = TASK_RUNNING; - case FrameState_Ready: - case FrameState_Error: - case FrameState_Done: - errCode = (usbvision->frame[vb->index].grabstate == FrameState_Error) ? -EIO : 0; - vb->memory = V4L2_MEMORY_MMAP; - vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; - vb->field = V4L2_FIELD_NONE; - vb->sequence = usbvision->frame[vb->index].sequence; - usbvision->frame[vb->index].grabstate = FrameState_Unused; - break; + if (list_empty(&(usbvision->outqueue))) { + if (usbvision->streaming == Stream_Off) + return -EINVAL; + ret = wait_event_interruptible + (usbvision->wait_frame, + !list_empty(&(usbvision->outqueue))); + if (ret) + return ret; } - usbvision->frame[vb->index].grabstate = FrameState_Unused; - return errCode; + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + f = list_entry(usbvision->outqueue.next, + struct usbvision_frame, frame); + list_del(usbvision->outqueue.next); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + f->grabstate = FrameState_Unused; + + vb->memory = V4L2_MEMORY_MMAP; + vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; + vb->index = f->index; + vb->sequence = f->sequence; + + return 0; } case VIDIOC_STREAMON: { int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (list_empty(&usbvision->inqueue)) + return -EINVAL; + + usbvision->streaming = Stream_On; + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + + PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); + return 0; } case VIDIOC_STREAMOFF: { + int *type = arg; int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - down(&usbvision->lock); - // Stop all video streamings - call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); - usbvision->frame_num = -1; - usbvision->frame[0].grabstate = FrameState_Unused; - usbvision->frame[1].grabstate = FrameState_Unused; - up(&usbvision->lock); + + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if(usbvision->streaming == Stream_On) { + usbvision_stream_interrupt(usbvision); + // Stop all video streamings + call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); + } + usbvision_empty_framequeues(usbvision); + + PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF"); return 0; } case VIDIOC_G_FBUF: @@ -4361,6 +4412,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *vfd = arg; + if ( (dga == 0) && (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && @@ -4539,7 +4591,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, int frmx = -1; int rc = 0; struct usbvision_frame *frame; - +return -EINVAL; PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) @@ -4574,7 +4626,8 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, // If no frame is active, start one. if (frmx == -1) - usbvision_new_frame(usbvision, frmx = 0); + // FIXME: enqueue all inqueue... + /* usbvision_new_frame(usbvision, frmx = 0); */ frame = &usbvision->frame[frmx]; @@ -4584,7 +4637,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, goto usbvision_v4l2_read_done; } PDEBUG(DBG_IO, "Waiting frame grabbing"); - rc = wait_event_interruptible(frame->wq, (frame->grabstate == FrameState_Done) || + rc = wait_event_interruptible(usbvision->wait_frame, (frame->grabstate == FrameState_Done) || (frame->grabstate == FrameState_Error)); if (rc) { goto usbvision_v4l2_read_done; @@ -4592,9 +4645,10 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, if (frame->grabstate == FrameState_Error) { frame->bytes_read = 0; - if (usbvision_new_frame(usbvision, frmx)) { - err("%s: usbvision_new_frame() failed", __FUNCTION__); - } + // FIXME: enqueue all inqueue... +/* if (usbvision_new_frame(usbvision, frmx)) { */ +/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ +/* } */ goto restart; } @@ -4619,8 +4673,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, /* Mark it as available to be used again. */ usbvision->frame[frmx].grabstate = FrameState_Unused; - if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) - err("%s: usbvision_new_frame() failed", __FUNCTION__); + // FIXME enqueue another frame +/* if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) */ +/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ } usbvision_v4l2_read_done: @@ -5198,7 +5253,7 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, static void usbvision_configure_video(struct usb_usbvision *usbvision) { - int model; + int model,i; if (usbvision == NULL) return; @@ -5215,17 +5270,26 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) memset(&usbvision->vcap, 0, sizeof(usbvision->vcap)); strcpy(usbvision->vcap.driver, "USBVision"); - usbvision->vcap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + strlcpy(usbvision->vcap.bus_info, usbvision->dev->dev.bus_id, + sizeof(usbvision->vcap.bus_info)); + usbvision->vcap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */ - usbvision->video_inputs = usbvision_device_data[model].VideoChannels; - memset(&usbvision->input, 0, sizeof(usbvision->input)); - usbvision->input.tuner = 0; - usbvision->input.type = V4L2_INPUT_TYPE_TUNER|VIDEO_TYPE_CAMERA; - usbvision->input.std = usbvision_device_data[model].VideoNorm; + for (i = 0; i < TVNORMS; i++) + if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode) + break; + if (i == TVNORMS) + i = 0; + usbvision->tvnorm = &tvnorms[i]; /* set default norm */ + call_i2c_clients(usbvision, VIDIOC_S_STD, + &usbvision->tvnorm->id); + + usbvision->video_inputs = usbvision_device_data[model].VideoChannels; + usbvision->ctl_input = 0; +/* usbvision_muxsel(usbvision, usbvision->ctl_input); */ /* This should be here to make i2c clients to be able to register */ usbvision_audio_off(usbvision); //first switch off audio @@ -5440,7 +5504,6 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) { struct usb_usbvision *usbvision; - int FrameIdx; if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { goto err_exit; @@ -5448,10 +5511,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) usbvision->dev = dev; - for (FrameIdx = 0; FrameIdx < USBVISION_NUMFRAMES; FrameIdx++) { - init_waitqueue_head(&usbvision->frame[FrameIdx].wq); - } - init_waitqueue_head(&usbvision->overlay_frame.wq); init_MUTEX(&usbvision->lock); /* to 1 == available */ // prepare control urb for control messages during interrupts @@ -5460,7 +5519,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) goto err_exit; } init_waitqueue_head(&usbvision->ctrlUrb_wq); - init_MUTEX(&usbvision->ctrlUrbLock); + init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ init_timer(&usbvision->powerOffTimer); usbvision->powerOffTimer.data = (long) usbvision; @@ -5536,7 +5595,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); - /* Is it an USBVISION video dev? */ model = 0; for(model = 0; usbvision_device_data[model].idVendor; model++) { @@ -5655,6 +5713,9 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more + wake_up_interruptible(&usbvision->wait_frame); + wake_up_interruptible(&usbvision->wait_stream); + up(&usbvision->lock); if (usbvision->user) { diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 466e11f458..48afcd2aca 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -1,4 +1,4 @@ -/* +/* * I2C_ALGO_USB.C * i2c algorithm for USB-I2C Bridges * @@ -39,7 +39,7 @@ #include #include "usbvision-i2c.h" -static int debug_i2c_usb = 0; +static int debug_i2c_usb = 0; #if defined(module_param) // Showing parameters under SYSFS module_param (debug_i2c_usb, int, 0444); // debug_i2c_usb mode of the device driver @@ -108,7 +108,7 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, unsigned char *add) { unsigned short flags = msg->flags; - + unsigned char addr; int ret; if ((flags & I2C_M_TEN)) { @@ -205,8 +205,6 @@ static u32 usb_func(struct i2c_adapter *adap) static struct i2c_algorithm i2c_usb_algo = { .master_xfer = usb_xfer, .smbus_xfer = NULL, - .slave_send = NULL, - .slave_recv = NULL, .algo_control = algo_control, .functionality = usb_func, }; diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 813b258f89..870c0cc81d 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -1,4 +1,4 @@ -/* +/* * USBVISION.H * usbvision header file * @@ -38,7 +38,7 @@ #define USBVISION_SSPND_EN (1 << 1) #define USBVISION_RES2 (1 << 2) #define USBVISION_PWR_VID (1 << 5) - #define USBVISION_E2_EN (1 << 7) + #define USBVISION_E2_EN (1 << 7) #define USBVISION_CONFIG_REG 0x01 #define USBVISION_ADRS_REG 0x02 #define USBVISION_ALTER_REG 0x03 @@ -139,7 +139,7 @@ #define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023 #define USBVISION_NUM_HEADERMARKER 20 -#define USBVISION_NUMFRAMES 2 +#define USBVISION_NUMFRAMES 3 #define USBVISION_NUMSBUF 2 #define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds @@ -225,6 +225,13 @@ enum FrameState { FrameState_Error, /* Something bad happened while processing */ }; +/* stream states */ +enum StreamState { + Stream_Off, + Stream_Interrupt, + Stream_On, +}; + enum IsocState { IsocState_InFrame, /* Isoc packet is member of frame */ IsocState_NoFrame, /* Isoc packet is not member of any frame */ @@ -272,27 +279,36 @@ struct usbvision_frame_header { __u16 frameHeight; /* 10 - 11 after endian correction*/ }; +/* tvnorms */ +struct usbvision_tvnorm { + char *name; + v4l2_std_id id; + /* mode for saa7113h */ + int mode; +}; + struct usbvision_frame { char *data; /* Frame buffer */ struct usbvision_frame_header isocHeader; /* Header from stream */ int width; /* Width application is expecting */ int height; /* Height */ - + int index; /* Frame index */ int frmwidth; /* Width the frame actually is */ int frmheight; /* Height */ volatile int grabstate; /* State of grabbing */ int scanstate; /* State of scanning */ + struct list_head frame; + int curline; /* Line of frame we're working on */ long scanlength; /* uncompressed, raw data length of frame */ long bytes_read; /* amount of scanlength that has been read from data */ struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/ int v4l2_linesize; /* bytes for one videoline*/ - struct timeval timestamp; - wait_queue_head_t wq; /* Processes waiting */ + struct timeval timestamp; int sequence; // How many video frames we send to user }; @@ -305,23 +321,23 @@ struct usbvision_frame { #define USBVISION_I2C_CLIENTS_MAX 8 struct usbvision_device_data_st { - int idVendor; - int idProduct; - int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ - int Codec; - int VideoChannels; - __u64 VideoNorm; - int AudioChannels; - int Radio; - int vbi; - int Tuner; - int TunerType; - int Vin_Reg1; - int Vin_Reg2; - int X_Offset; - int Y_Offset; - int Dvi_yuv; - char *ModelString; + int idVendor; + int idProduct; + int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ + int Codec; + int VideoChannels; + __u64 VideoNorm; + int AudioChannels; + int Radio; + int vbi; + int Tuner; + int TunerType; + int Vin_Reg1; + int Vin_Reg2; + int X_Offset; + int Y_Offset; + int Dvi_yuv; + char *ModelString; }; /* Declared on usbvision-cards.c */ @@ -332,7 +348,7 @@ struct usb_usbvision { struct video_device *vdev; /* Video Device */ struct video_device *rdev; /* Radio Device */ struct video_device *vbi; /* VBI Device */ - struct video_audio audio_dev; /* Current audio params */ + struct video_audio audio_dev; /* Current audio params */ /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; @@ -373,7 +389,7 @@ struct usb_usbvision { int usbvision_used; /* Is this structure in use? */ int initialized; /* Had we already sent init sequence? */ int DevModel; /* What type of USBVISION device we got? */ - int streaming; /* Are we streaming Isochronous? */ + enum StreamState streaming; /* Are we streaming Isochronous? */ int last_error; /* What calamity struck us? */ int curwidth; /* width of the frame the device is currently set to*/ int curheight; /* height of the frame the device is currently set to*/ @@ -382,7 +398,10 @@ struct usb_usbvision { char *fbuf; /* Videodev buffer area for mmap*/ int max_frame_size; /* Bytes in one video frame */ int fbuf_size; /* Videodev buffer size */ - int curFrameNum; // number of current frame in frame buffer mode + spinlock_t queue_lock; /* spinlock for protecting mods on inqueue and outqueue */ + struct list_head inqueue, outqueue; /* queued frame list and ready to dequeue frame list */ + wait_queue_head_t wait_frame; /* Processes waiting */ + wait_queue_head_t wait_stream; /* Processes waiting */ struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer int curSbufNum; // number of current receiving sbuf @@ -397,20 +416,21 @@ struct usb_usbvision { int scratch_headermarker_read_ptr; int scratch_headermarker_write_ptr; int isocstate; - /* color controls */ + /* color controls */ int saturation; int hue; int brightness; - int contrast; + int contrast; int depth; struct usbvision_v4l2_format_st palette; struct v4l2_capability vcap; /* Video capabilities */ - struct v4l2_input input; /* May be used for tuner support */ + unsigned int ctl_input; /* selected input */ + struct usbvision_tvnorm *tvnorm; /* selected tv norm */ unsigned char video_endp; /* 0x82 for USBVISION devices based */ // Overlay stuff: - struct v4l2_framebuffer vid_buf; + struct v4l2_framebuffer vid_buf; struct v4l2_format vid_win; int vid_buf_valid; // Status: video buffer is valid (set) int vid_win_valid; // Status: video window is valid (set) @@ -435,8 +455,8 @@ struct usb_usbvision { struct proc_dir_entry *proc_devdir; /* Per-device proc directory */ struct proc_dir_entry *proc_info; /* /info entry */ struct proc_dir_entry *proc_register; /* /register entry */ - struct proc_dir_entry *proc_freq; /* /freq entry */ - struct proc_dir_entry *proc_input; /* /input entry */ + struct proc_dir_entry *proc_freq; /* /freq entry */ + struct proc_dir_entry *proc_input; /* /input entry */ struct proc_dir_entry *proc_frame; /* /frame entry */ struct proc_dir_entry *proc_button; /* /button entry */ struct proc_dir_entry *proc_control; /* /control entry */ @@ -463,3 +483,10 @@ struct usb_usbvision { #endif /* __LINUX_USBVISION_H */ +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */