Commit f2242ee5 authored by Thierry MERLE's avatar Thierry MERLE Committed by Mauro Carvalho Chehab

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: default avatarThierry MERLE <thierry.merle@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 18d8a454
...@@ -437,6 +437,25 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { ...@@ -437,6 +437,25 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } { 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 * 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; ...@@ -451,7 +470,7 @@ static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;
// Function prototypes // Function prototypes
static int usbvision_restart_isoc(struct usb_usbvision *usbvision); static int usbvision_restart_isoc(struct usb_usbvision *usbvision);
static int usbvision_begin_streaming(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_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_i2c_read(void *data, unsigned char addr, char *buf, short len);
static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); 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); ...@@ -463,6 +482,8 @@ static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);
static void usbvision_release(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_input(struct usb_usbvision *usbvision);
static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); 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); 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) ...@@ -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 video_device *vdev = to_video_device(class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev); 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); 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); ...@@ -639,17 +660,18 @@ static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
static void usbvision_create_sysfs(struct video_device *vdev) static void usbvision_create_sysfs(struct video_device *vdev)
{ {
int res;
if (vdev) { if (vdev) {
video_device_create_file(vdev, &class_device_attr_version); res=video_device_create_file(vdev, &class_device_attr_version);
video_device_create_file(vdev, &class_device_attr_model); res=video_device_create_file(vdev, &class_device_attr_model);
video_device_create_file(vdev, &class_device_attr_hue); res=video_device_create_file(vdev, &class_device_attr_hue);
video_device_create_file(vdev, &class_device_attr_contrast); res=video_device_create_file(vdev, &class_device_attr_contrast);
video_device_create_file(vdev, &class_device_attr_brightness); res=video_device_create_file(vdev, &class_device_attr_brightness);
video_device_create_file(vdev, &class_device_attr_saturation); res=video_device_create_file(vdev, &class_device_attr_saturation);
video_device_create_file(vdev, &class_device_attr_streaming); res=video_device_create_file(vdev, &class_device_attr_streaming);
video_device_create_file(vdev, &class_device_attr_overlay); res=video_device_create_file(vdev, &class_device_attr_overlay);
video_device_create_file(vdev, &class_device_attr_compression); res=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_bridge);
} }
} }
...@@ -1209,15 +1231,13 @@ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, ...@@ -1209,15 +1231,13 @@ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe,
printk(KERN_ERR "%s: usbvision == NULL\n", proc); printk(KERN_ERR "%s: usbvision == NULL\n", proc);
return; return;
} }
if ((usbvision->curFrameNum < 0) if (usbvision->curFrame == NULL) {
|| (usbvision->curFrameNum >= USBVISION_NUMFRAMES)) { printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc);
printk(KERN_ERR "%s: usbvision->curFrameNum=%d.\n", proc,
usbvision->curFrameNum);
return; return;
} }
/* Grab the current frame */ /* Grab the current frame */
frame = &usbvision->frame[usbvision->curFrameNum]; frame = usbvision->curFrame;
/* Optionally start at the beginning */ /* Optionally start at the beginning */
if (fullframe) { if (fullframe) {
...@@ -1290,7 +1310,7 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) ...@@ -1290,7 +1310,7 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision)
frame = &usbvision->overlay_frame; frame = &usbvision->overlay_frame;
} }
else { else {
frame = &usbvision->frame[usbvision->curFrameNum]; frame = usbvision->curFrame;
} }
while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) { while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) {
...@@ -1325,7 +1345,6 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) ...@@ -1325,7 +1345,6 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision)
frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width; frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width;
frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height; frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height;
frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3; frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3;
usbvision->curFrame = frame;
} }
else { // no header found else { // no header found
PDEBUG(DBG_HEADER, "skipping scratch data, no header"); PDEBUG(DBG_HEADER, "skipping scratch data, no header");
...@@ -1380,7 +1399,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision ...@@ -1380,7 +1399,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
usbvision->vid_buf.fmt.bytesperline; usbvision->vid_buf.fmt.bytesperline;
} }
else { else {
frame = &usbvision->frame[usbvision->curFrameNum]; frame = usbvision->curFrame;
f = frame->data + (frame->v4l2_linesize * frame->curline); f = frame->data + (frame->v4l2_linesize * frame->curline);
} }
...@@ -1612,7 +1631,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, ...@@ -1612,7 +1631,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
usbvision->vid_buf.fmt.bytesperline; usbvision->vid_buf.fmt.bytesperline;
} }
else { else {
frame = &usbvision->frame[usbvision->curFrameNum]; frame = usbvision->curFrame;
imageSize = frame->frmwidth * frame->frmheight; imageSize = frame->frmwidth * frame->frmheight;
if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
(frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) )
...@@ -1833,7 +1852,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision ...@@ -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; f_odd = f_even + usbvision->vid_buf.fmt.bytesperline * usbvision->stretch_height;
} }
else { else {
frame = &usbvision->frame[usbvision->curFrameNum]; frame = usbvision->curFrame;
f_even = frame->data + (frame->v4l2_linesize * frame->curline); f_even = frame->data + (frame->v4l2_linesize * frame->curline);
f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height;
} }
...@@ -2088,17 +2107,17 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) ...@@ -2088,17 +2107,17 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision)
struct usbvision_frame *frame; struct usbvision_frame *frame;
enum ParseState newstate; enum ParseState newstate;
long copylen = 0; long copylen = 0;
unsigned long lock_flags;
if (usbvision->overlay) { if (usbvision->overlay) {
frame = &usbvision->overlay_frame; frame = &usbvision->overlay_frame;
} }
else { else {
frame = &usbvision->frame[usbvision->curFrameNum]; frame = usbvision->curFrame;
} }
PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision)); PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision));
while (1) { while (1) {
newstate = ParseState_Out; newstate = ParseState_Out;
...@@ -2141,7 +2160,10 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) ...@@ -2141,7 +2160,10 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision)
copylen = 0; copylen = 0;
} }
else { 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++; usbvision->frame_num++;
...@@ -2150,10 +2172,14 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) ...@@ -2150,10 +2172,14 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision)
usbvision_osd_stats(usbvision, frame); usbvision_osd_stats(usbvision, frame);
/* This will cause the process to request another frame. */ /* This will cause the process to request another frame. */
if (waitqueue_active(&frame->wq)) { if (waitqueue_active(&usbvision->wait_frame)) {
wake_up_interruptible(&frame->wq); PDEBUG(DBG_PARSE, "Wake up !");
wake_up_interruptible(&usbvision->wait_frame);
} }
} }
else
frame->grabstate = FrameState_Grabbing;
/* Update the frame's uncompressed length. */ /* Update the frame's uncompressed length. */
frame->scanlength += copylen; frame->scanlength += copylen;
...@@ -2251,14 +2277,23 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) ...@@ -2251,14 +2277,23 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs)
struct usb_usbvision *usbvision = urb->context; struct usb_usbvision *usbvision = urb->context;
int i; int i;
unsigned long startTime = jiffies; unsigned long startTime = jiffies;
struct usbvision_frame **f;
/* We don't want to do anything if we are about to be removed! */ /* We don't want to do anything if we are about to be removed! */
if (!USBVISION_IS_OPERATIONAL(usbvision)) if (!USBVISION_IS_OPERATIONAL(usbvision))
return; return;
if (!usbvision->streaming) { f = &usbvision->curFrame;
PDEBUG(DBG_IRQ, "oops, not streaming, but interrupt");
return; /* 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);
} }
/* Copy the data received into our scratch buffer */ /* Copy the data received into our scratch buffer */
...@@ -2267,30 +2302,40 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) ...@@ -2267,30 +2302,40 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs)
usbvision->isocUrbCount++; usbvision->isocUrbCount++;
usbvision->urb_length = len; usbvision->urb_length = len;
for (i = 0; i < USBVISION_URB_FRAMES; i++) { if (usbvision->streaming == Stream_On) {
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);
// }
/* If we collected enough data let's parse! */ /* If we collected enough data let's parse! */
if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */
/*If we don't have a frame we're current working on, complain */ /*If we don't have a frame we're current working on, complain */
if ((usbvision->curFrameNum >= 0) || (usbvision->overlay)) if((!list_empty(&(usbvision->inqueue))) || (usbvision->overlay)) {
if (!(*f)) {
(*f) = list_entry(usbvision->inqueue.next,struct usbvision_frame, frame);
}
usbvision_parse_data(usbvision); usbvision_parse_data(usbvision);
}
else { else {
PDEBUG(DBG_IRQ, "received data, but no one needs it"); PDEBUG(DBG_IRQ, "received data, but no one needs it");
scratch_reset(usbvision); scratch_reset(usbvision);
} }
} }
}
usbvision->timeInIrq += jiffies - startTime; 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; return;
} }
...@@ -2539,7 +2584,6 @@ static int attach_inform(struct i2c_client *client) ...@@ -2539,7 +2584,6 @@ static int attach_inform(struct i2c_client *client)
struct usb_usbvision *usbvision; struct usb_usbvision *usbvision;
struct tuner_setup tun_addr; struct tuner_setup tun_addr;
int i; int i;
v4l2_std_id stdId;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
usbvision = (struct usb_usbvision *)client->adapter->data; usbvision = (struct usb_usbvision *)client->adapter->data;
...@@ -2560,13 +2604,11 @@ static int attach_inform(struct i2c_client *client) ...@@ -2560,13 +2604,11 @@ static int attach_inform(struct i2c_client *client)
tun_addr.type = usbvision->tuner_type; tun_addr.type = usbvision->tuner_type;
tun_addr.addr = ADDR_UNSET; tun_addr.addr = ADDR_UNSET;
client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr);
call_i2c_clients(usbvision, VIDIOC_INT_RESET, NULL);
call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); 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, VIDIOC_S_STD, &usbvision->tvnorm->id);
/* call_i2c_clients(usbvision, DECODER_SET_PICTURE, &usbvision->vpic); */
stdId = usbvision->input.std;
call_i2c_clients(usbvision, VIDIOC_S_STD, &stdId);
PDEBUG(DBG_I2C, "usbvision[%d] attaches %s", usbvision->nr, client->name); 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, ...@@ -2995,10 +3037,10 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width,
frameRate = FRAMERATE_MAX; frameRate = FRAMERATE_MAX;
} }
if (usbvision->input.std & V4L2_STD_625_50) { if (usbvision->tvnorm->id & V4L2_STD_625_50) {
frameDrop = frameRate * 32 / 25 - 1; 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; frameDrop = frameRate * 32 / 30 - 1;
} }
...@@ -3021,6 +3063,40 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, ...@@ -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() * usbvision_set_compress_params()
* *
...@@ -3135,7 +3211,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) ...@@ -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[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20; value[2] = 0x20;
...@@ -3144,7 +3220,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) ...@@ -3144,7 +3220,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision)
value[5] = 0x00; //0x0060 -> 96 Input video h offset value[5] = 0x00; //0x0060 -> 96 Input video h offset
value[6] = 0x16; value[6] = 0x16;
value[7] = 0x00; //0x0016 -> 22 Input video v offset 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[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20; value[2] = 0x20;
...@@ -3434,7 +3510,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) ...@@ -3434,7 +3510,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision)
if (!USBVISION_IS_OPERATIONAL(usbvision)) if (!USBVISION_IS_OPERATIONAL(usbvision))
return -EFAULT; return -EFAULT;
usbvision->curFrameNum = -1; usbvision->curFrame = NULL;
scratch_reset(usbvision); scratch_reset(usbvision);
/* Alternate interface 1 is is the biggest frame size */ /* Alternate interface 1 is is the biggest frame size */
...@@ -3503,7 +3579,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) ...@@ -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); PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp);
return 0; return 0;
} }
...@@ -3519,7 +3595,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) ...@@ -3519,7 +3595,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision)
{ {
int bufIdx, errCode, regValue; 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; return;
/* Unschedule all of the iso td's */ /* Unschedule all of the iso td's */
...@@ -3530,9 +3607,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) ...@@ -3530,9 +3607,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision)
} }
PDEBUG(DBG_ISOC, "%s: streaming=0\n", __FUNCTION__); PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__);
usbvision->streaming = 0; usbvision->streaming = Stream_Off;
if (!usbvision->remove_pending) { if (!usbvision->remove_pending) {
...@@ -3552,62 +3628,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) ...@@ -3552,62 +3628,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision)
} }
} }
/* static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
* 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)
{ {
int mode[4]; int mode[4];
int audio[]= {1, 0, 0, 0}; int audio[]= {1, 0, 0, 0};
...@@ -3618,16 +3639,10 @@ static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int no ...@@ -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) //channel 3 is additional video inputs to the device with audio channel 0 (line in)
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs); RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
/* set the new video norm */ usbvision->ctl_input = channel;
if (usbvision->input.std != norm) {
v4l2_std_id video_command = norm;
route.input = SAA7115_COMPOSITE1; route.input = SAA7115_COMPOSITE1;
call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
call_i2c_clients(usbvision, VIDIOC_S_STD, &video_command); call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
usbvision->input.std = norm;
call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); //set norm in tuner
}
// set the new channel // set the new channel
// Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video // 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) ...@@ -3703,8 +3718,13 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
errCode = -ENOMEM; errCode = -ENOMEM;
} }
else { else {
spin_lock_init(&usbvision->queue_lock);
init_waitqueue_head(&usbvision->wait_frame);
init_waitqueue_head(&usbvision->wait_stream);
/* Allocate all buffers */ /* Allocate all buffers */
for (i = 0; i < USBVISION_NUMFRAMES; i++) { for (i = 0; i < USBVISION_NUMFRAMES; i++) {
usbvision->frame[i].index = i;
usbvision->frame[i].grabstate = FrameState_Unused; usbvision->frame[i].grabstate = FrameState_Unused;
usbvision->frame[i].data = usbvision->fbuf + usbvision->frame[i].data = usbvision->fbuf +
i * MAX_FRAME_SIZE; i * MAX_FRAME_SIZE;
...@@ -3804,6 +3824,9 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) ...@@ -3804,6 +3824,9 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
if (errCode) { if (errCode) {
} }
/* prepare queues */
usbvision_empty_framequeues(usbvision);
PDEBUG(DBG_IO, "success"); PDEBUG(DBG_IO, "success");
return errCode; return errCode;
} }
...@@ -3875,6 +3898,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -3875,6 +3898,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if (!USBVISION_IS_OPERATIONAL(usbvision)) if (!USBVISION_IS_OPERATIONAL(usbvision))
return -EFAULT; return -EFAULT;
// if (debug & DBG_IOCTL) v4l_printk_ioctl(cmd);
switch (cmd) { switch (cmd) {
case UVIOCSREG: case UVIOCSREG:
{ {
...@@ -3914,7 +3939,20 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -3914,7 +3939,20 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_QUERYCAP: case VIDIOC_QUERYCAP:
{ {
struct v4l2_capability *vc=arg; 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"); PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
return 0; return 0;
} }
...@@ -3975,38 +4013,24 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -3975,38 +4013,24 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
} }
case VIDIOC_ENUMSTD: case VIDIOC_ENUMSTD:
{ {
struct v4l2_standard *vs = arg; struct v4l2_standard *e = arg;
switch(vs->index) { unsigned int i;
case 0: int ret;
vs->id = V4L2_STD_PAL;
strcpy(vs->name,"PAL"); i = e->index;
vs->frameperiod.numerator = 1; if (i >= TVNORMS)
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:
return -EINVAL; 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; return 0;
} }
case VIDIOC_G_INPUT: case VIDIOC_G_INPUT:
{ {
int *input = arg; int *input = arg;
*input = usbvision->input.index; *input = usbvision->ctl_input;
return 0; return 0;
} }
case VIDIOC_S_INPUT: case VIDIOC_S_INPUT:
...@@ -4014,10 +4038,10 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4014,10 +4038,10 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
int *input = arg; int *input = arg;
if ((*input >= usbvision->video_inputs) || (*input < 0) ) if ((*input >= usbvision->video_inputs) || (*input < 0) )
return -EINVAL; return -EINVAL;
usbvision->input.index = *input; usbvision->ctl_input = *input;
down(&usbvision->lock); down(&usbvision->lock);
usbvision_muxsel(usbvision, usbvision->input.index, usbvision->input.std); usbvision_muxsel(usbvision, usbvision->ctl_input);
usbvision_set_input(usbvision); usbvision_set_input(usbvision);
usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
up(&usbvision->lock); up(&usbvision->lock);
...@@ -4025,43 +4049,50 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4025,43 +4049,50 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
} }
case VIDIOC_G_STD: case VIDIOC_G_STD:
{ {
v4l2_std_id *std = arg; v4l2_std_id *id = arg;
*std = usbvision->input.std;
PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%x", (unsigned)*std); *id = usbvision->tvnorm->id;
PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
return 0; return 0;
} }
case VIDIOC_S_STD: 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); down(&usbvision->lock);
usbvision_muxsel(usbvision, usbvision->input.index, *std); usbvision->tvnorm = &tvnorms[i];
usbvision_set_input(usbvision);
usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); call_i2c_clients(usbvision, VIDIOC_S_STD,
&usbvision->tvnorm->id);
up(&usbvision->lock); up(&usbvision->lock);
usbvision->input.std = *std; PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%x", (unsigned)*std);
return 0; return 0;
} }
case VIDIOC_G_TUNER: case VIDIOC_G_TUNER:
{ {
struct v4l2_tuner *vt = arg; struct v4l2_tuner *vt = arg;
struct v4l2_tuner status;
if (!usbvision->have_tuner || vt->index) // Only tuner 0 if (!usbvision->have_tuner || vt->index) // Only tuner 0
return -EINVAL; return -EINVAL;
strcpy(vt->name, "Television"); strcpy(vt->name, "Television");
vt->type = V4L2_TUNER_ANALOG_TV; /* Let clients fill in the remainder of this struct */
vt->capability = V4L2_TUNER_CAP_NORM; call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
vt->rangelow = 0;
vt->rangehigh = ~0; PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
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");
return 0; return 0;
} }
case VIDIOC_S_TUNER: case VIDIOC_S_TUNER:
...@@ -4071,15 +4102,16 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4071,15 +4102,16 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
// Only no or one tuner for now // Only no or one tuner for now
if (!usbvision->have_tuner || vt->index) if (!usbvision->have_tuner || vt->index)
return -EINVAL; return -EINVAL;
// FIXME vt->audmode Radio mode (STEREO/MONO/...) /* let clients handle this */
// vt->reserved Radio freq call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
// usbvision_muxsel(usbvision, vt->index, vt->mode);
PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
return 0; return 0;
} }
case VIDIOC_G_FREQUENCY: case VIDIOC_G_FREQUENCY:
{ {
struct v4l2_frequency *freq = arg; struct v4l2_frequency *freq = arg;
freq->tuner = 0; // Only one tuner freq->tuner = 0; // Only one tuner
freq->type = V4L2_TUNER_ANALOG_TV; freq->type = V4L2_TUNER_ANALOG_TV;
freq->frequency = usbvision->freq; freq->frequency = usbvision->freq;
...@@ -4089,6 +4121,11 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4089,6 +4121,11 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_FREQUENCY: case VIDIOC_S_FREQUENCY:
{ {
struct v4l2_frequency *freq = arg; struct v4l2_frequency *freq = arg;
// Only no or one tuner for now
if (!usbvision->have_tuner || freq->tuner)
return -EINVAL;
usbvision->freq = freq->frequency; usbvision->freq = freq->frequency;
call_i2c_clients(usbvision, cmd, freq); call_i2c_clients(usbvision, cmd, freq);
PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); 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, ...@@ -4149,11 +4186,27 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_REQBUFS: case VIDIOC_REQBUFS:
{ {
struct v4l2_requestbuffers *vr = arg; struct v4l2_requestbuffers *vr = arg;
// FIXME : normally we allocate the requested number of buffers. int ret;
// this driver allocates statically the buffers.
vr->count = 2; RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
if(vr->memory != V4L2_MEMORY_MMAP)
// 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; 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; return 0;
} }
case VIDIOC_QUERYBUF: case VIDIOC_QUERYBUF:
...@@ -4161,16 +4214,18 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4161,16 +4214,18 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_buffer *vb = arg; struct v4l2_buffer *vb = arg;
struct usbvision_frame *frame; 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) { if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
return -EINVAL; return -EINVAL;
} }
if(vb->index>1) { if(vb->index>=USBVISION_NUMFRAMES) {
return -EINVAL; return -EINVAL;
} }
// Updating the corresponding frame state
vb->flags = 0; vb->flags = 0;
frame = &usbvision->frame[vb->index]; frame = &usbvision->frame[vb->index];
if(frame->grabstate == FrameState_Grabbing) if(frame->grabstate >= FrameState_Ready)
vb->flags |= V4L2_BUF_FLAG_QUEUED; vb->flags |= V4L2_BUF_FLAG_QUEUED;
if(frame->grabstate >= FrameState_Done) if(frame->grabstate >= FrameState_Done)
vb->flags |= V4L2_BUF_FLAG_DONE; vb->flags |= V4L2_BUF_FLAG_DONE;
...@@ -4183,119 +4238,115 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4183,119 +4238,115 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
else { else {
vb->m.offset = MAX_FRAME_SIZE; vb->m.offset = MAX_FRAME_SIZE;
} }
vb->memory = V4L2_MEMORY_MMAP;
vb->field = V4L2_FIELD_NONE;
vb->length = MAX_FRAME_SIZE; vb->length = MAX_FRAME_SIZE;
vb->timestamp = usbvision->frame[vb->index].timestamp; vb->timestamp = usbvision->frame[vb->index].timestamp;
vb->sequence = usbvision->frame_num; vb->sequence = usbvision->frame[vb->index].sequence;
return 0; return 0;
} }
case VIDIOC_QBUF: // VIDIOCMCAPTURE + VIDIOCSYNC case VIDIOC_QBUF:
{ {
struct v4l2_buffer *vb = arg; struct v4l2_buffer *vb = arg;
struct usbvision_frame *frame; struct usbvision_frame *frame;
unsigned long lock_flags;
// FIXME : works only on VIDEO_CAPTURE MODE, MMAP. // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
return -EINVAL; return -EINVAL;
} }
if(vb->index>1) { if(vb->index>=USBVISION_NUMFRAMES) {
return -EINVAL; return -EINVAL;
} }
frame = &usbvision->frame[vb->index]; frame = &usbvision->frame[vb->index];
if (frame->grabstate == FrameState_Grabbing) { if (frame->grabstate != FrameState_Unused) {
return -EBUSY; return -EAGAIN;
} }
usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); /* Mark it as ready and enqueue frame */
/* Mark it as ready */
frame->grabstate = FrameState_Ready; frame->grabstate = FrameState_Ready;
frame->scanstate = ScanState_Scanning;
frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
vb->flags &= ~V4L2_BUF_FLAG_DONE; vb->flags &= ~V4L2_BUF_FLAG_DONE;
/* set v4l2_format index */ /* set v4l2_format index */
frame->v4l2_format = usbvision->palette; 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: case VIDIOC_DQBUF:
{ {
struct v4l2_buffer *vb = arg; struct v4l2_buffer *vb = arg;
int errCode = 0; int ret;
struct usbvision_frame *f;
unsigned long lock_flags;
DECLARE_WAITQUEUE(wait, current); if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
// 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)
return -EINVAL; return -EINVAL;
PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame=%d, grabstate=%d, curframeNum=%d", if (list_empty(&(usbvision->outqueue))) {
vb->index, usbvision->frame[vb->index].grabstate,usbvision->curFrameNum); if (usbvision->streaming == Stream_Off)
return -EINVAL;
ret = wait_event_interruptible
(usbvision->wait_frame,
!list_empty(&(usbvision->outqueue)));
if (ret)
return ret;
}
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;
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->memory = V4L2_MEMORY_MMAP;
vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
vb->field = V4L2_FIELD_NONE; vb->index = f->index;
vb->sequence = usbvision->frame[vb->index].sequence; vb->sequence = f->sequence;
usbvision->frame[vb->index].grabstate = FrameState_Unused;
break;
}
usbvision->frame[vb->index].grabstate = FrameState_Unused; return 0;
return errCode;
} }
case VIDIOC_STREAMON: case VIDIOC_STREAMON:
{ {
int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; 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); call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
return 0; return 0;
} }
case VIDIOC_STREAMOFF: case VIDIOC_STREAMOFF:
{ {
int *type = arg;
int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
down(&usbvision->lock);
if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if(usbvision->streaming == Stream_On) {
usbvision_stream_interrupt(usbvision);
// Stop all video streamings // Stop all video streamings
call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
usbvision->frame_num = -1; }
usbvision->frame[0].grabstate = FrameState_Unused; usbvision_empty_framequeues(usbvision);
usbvision->frame[1].grabstate = FrameState_Unused;
up(&usbvision->lock); PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
return 0; return 0;
} }
case VIDIOC_G_FBUF: case VIDIOC_G_FBUF:
...@@ -4361,6 +4412,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4361,6 +4412,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUM_FMT: case VIDIOC_ENUM_FMT:
{ {
struct v4l2_fmtdesc *vfd = arg; struct v4l2_fmtdesc *vfd = arg;
if ( (dga == 0) && if ( (dga == 0) &&
(vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) &&
(usbvision->palette.format != V4L2_PIX_FMT_YVU420) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) &&
...@@ -4539,7 +4591,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, ...@@ -4539,7 +4591,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
int frmx = -1; int frmx = -1;
int rc = 0; int rc = 0;
struct usbvision_frame *frame; struct usbvision_frame *frame;
return -EINVAL;
PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
...@@ -4574,7 +4626,8 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, ...@@ -4574,7 +4626,8 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
// If no frame is active, start one. // If no frame is active, start one.
if (frmx == -1) if (frmx == -1)
usbvision_new_frame(usbvision, frmx = 0); // FIXME: enqueue all inqueue...
/* usbvision_new_frame(usbvision, frmx = 0); */
frame = &usbvision->frame[frmx]; frame = &usbvision->frame[frmx];
...@@ -4584,7 +4637,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, ...@@ -4584,7 +4637,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
goto usbvision_v4l2_read_done; goto usbvision_v4l2_read_done;
} }
PDEBUG(DBG_IO, "Waiting frame grabbing"); 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)); (frame->grabstate == FrameState_Error));
if (rc) { if (rc) {
goto usbvision_v4l2_read_done; goto usbvision_v4l2_read_done;
...@@ -4592,9 +4645,10 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, ...@@ -4592,9 +4645,10 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
if (frame->grabstate == FrameState_Error) { if (frame->grabstate == FrameState_Error) {
frame->bytes_read = 0; frame->bytes_read = 0;
if (usbvision_new_frame(usbvision, frmx)) { // FIXME: enqueue all inqueue...
err("%s: usbvision_new_frame() failed", __FUNCTION__); /* if (usbvision_new_frame(usbvision, frmx)) { */
} /* err("%s: usbvision_new_frame() failed", __FUNCTION__); */
/* } */
goto restart; goto restart;
} }
...@@ -4619,8 +4673,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, ...@@ -4619,8 +4673,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
/* Mark it as available to be used again. */ /* Mark it as available to be used again. */
usbvision->frame[frmx].grabstate = FrameState_Unused; usbvision->frame[frmx].grabstate = FrameState_Unused;
if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) // FIXME enqueue another frame
err("%s: usbvision_new_frame() failed", __FUNCTION__); /* if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) */
/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */
} }
usbvision_v4l2_read_done: usbvision_v4l2_read_done:
...@@ -5198,7 +5253,7 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, ...@@ -5198,7 +5253,7 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
static void usbvision_configure_video(struct usb_usbvision *usbvision) static void usbvision_configure_video(struct usb_usbvision *usbvision)
{ {
int model; int model,i;
if (usbvision == NULL) if (usbvision == NULL)
return; return;
...@@ -5215,17 +5270,26 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) ...@@ -5215,17 +5270,26 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
memset(&usbvision->vcap, 0, sizeof(usbvision->vcap)); memset(&usbvision->vcap, 0, sizeof(usbvision->vcap));
strcpy(usbvision->vcap.driver, "USBVision"); 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) | (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) |
(usbvision->have_tuner ? V4L2_CAP_TUNER : 0); (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */ usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */
usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
memset(&usbvision->input, 0, sizeof(usbvision->input)); for (i = 0; i < TVNORMS; i++)
usbvision->input.tuner = 0; if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
usbvision->input.type = V4L2_INPUT_TYPE_TUNER|VIDEO_TYPE_CAMERA; break;
usbvision->input.std = usbvision_device_data[model].VideoNorm; 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 */ /* This should be here to make i2c clients to be able to register */
usbvision_audio_off(usbvision); //first switch off audio usbvision_audio_off(usbvision); //first switch off audio
...@@ -5440,7 +5504,6 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) ...@@ -5440,7 +5504,6 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
{ {
struct usb_usbvision *usbvision; struct usb_usbvision *usbvision;
int FrameIdx;
if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
goto err_exit; goto err_exit;
...@@ -5448,10 +5511,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) ...@@ -5448,10 +5511,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
usbvision->dev = 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 */ init_MUTEX(&usbvision->lock); /* to 1 == available */
// prepare control urb for control messages during interrupts // prepare control urb for control messages during interrupts
...@@ -5460,7 +5519,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) ...@@ -5460,7 +5519,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
goto err_exit; goto err_exit;
} }
init_waitqueue_head(&usbvision->ctrlUrb_wq); init_waitqueue_head(&usbvision->ctrlUrb_wq);
init_MUTEX(&usbvision->ctrlUrbLock); init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */
init_timer(&usbvision->powerOffTimer); init_timer(&usbvision->powerOffTimer);
usbvision->powerOffTimer.data = (long) usbvision; usbvision->powerOffTimer.data = (long) usbvision;
...@@ -5536,7 +5595,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us ...@@ -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", PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
/* Is it an USBVISION video dev? */ /* Is it an USBVISION video dev? */
model = 0; model = 0;
for(model = 0; usbvision_device_data[model].idVendor; model++) { for(model = 0; usbvision_device_data[model].idVendor; model++) {
...@@ -5655,6 +5713,9 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) ...@@ -5655,6 +5713,9 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
usb_put_dev(usbvision->dev); usb_put_dev(usbvision->dev);
usbvision->dev = NULL; // USB device is no more usbvision->dev = NULL; // USB device is no more
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
up(&usbvision->lock); up(&usbvision->lock);
if (usbvision->user) { if (usbvision->user) {
......
...@@ -205,8 +205,6 @@ static u32 usb_func(struct i2c_adapter *adap) ...@@ -205,8 +205,6 @@ static u32 usb_func(struct i2c_adapter *adap)
static struct i2c_algorithm i2c_usb_algo = { static struct i2c_algorithm i2c_usb_algo = {
.master_xfer = usb_xfer, .master_xfer = usb_xfer,
.smbus_xfer = NULL, .smbus_xfer = NULL,
.slave_send = NULL,
.slave_recv = NULL,
.algo_control = algo_control, .algo_control = algo_control,
.functionality = usb_func, .functionality = usb_func,
}; };
......
...@@ -139,7 +139,7 @@ ...@@ -139,7 +139,7 @@
#define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023 #define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023
#define USBVISION_NUM_HEADERMARKER 20 #define USBVISION_NUM_HEADERMARKER 20
#define USBVISION_NUMFRAMES 2 #define USBVISION_NUMFRAMES 3
#define USBVISION_NUMSBUF 2 #define USBVISION_NUMSBUF 2
#define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds #define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds
...@@ -225,6 +225,13 @@ enum FrameState { ...@@ -225,6 +225,13 @@ enum FrameState {
FrameState_Error, /* Something bad happened while processing */ FrameState_Error, /* Something bad happened while processing */
}; };
/* stream states */
enum StreamState {
Stream_Off,
Stream_Interrupt,
Stream_On,
};
enum IsocState { enum IsocState {
IsocState_InFrame, /* Isoc packet is member of frame */ IsocState_InFrame, /* Isoc packet is member of frame */
IsocState_NoFrame, /* Isoc packet is not member of any frame */ IsocState_NoFrame, /* Isoc packet is not member of any frame */
...@@ -272,19 +279,29 @@ struct usbvision_frame_header { ...@@ -272,19 +279,29 @@ struct usbvision_frame_header {
__u16 frameHeight; /* 10 - 11 after endian correction*/ __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 { struct usbvision_frame {
char *data; /* Frame buffer */ char *data; /* Frame buffer */
struct usbvision_frame_header isocHeader; /* Header from stream */ struct usbvision_frame_header isocHeader; /* Header from stream */
int width; /* Width application is expecting */ int width; /* Width application is expecting */
int height; /* Height */ int height; /* Height */
int index; /* Frame index */
int frmwidth; /* Width the frame actually is */ int frmwidth; /* Width the frame actually is */
int frmheight; /* Height */ int frmheight; /* Height */
volatile int grabstate; /* State of grabbing */ volatile int grabstate; /* State of grabbing */
int scanstate; /* State of scanning */ int scanstate; /* State of scanning */
struct list_head frame;
int curline; /* Line of frame we're working on */ int curline; /* Line of frame we're working on */
long scanlength; /* uncompressed, raw data length of frame */ long scanlength; /* uncompressed, raw data length of frame */
...@@ -292,7 +309,6 @@ struct usbvision_frame { ...@@ -292,7 +309,6 @@ struct usbvision_frame {
struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/ struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/
int v4l2_linesize; /* bytes for one videoline*/ int v4l2_linesize; /* bytes for one videoline*/
struct timeval timestamp; struct timeval timestamp;
wait_queue_head_t wq; /* Processes waiting */
int sequence; // How many video frames we send to user int sequence; // How many video frames we send to user
}; };
...@@ -373,7 +389,7 @@ struct usb_usbvision { ...@@ -373,7 +389,7 @@ struct usb_usbvision {
int usbvision_used; /* Is this structure in use? */ int usbvision_used; /* Is this structure in use? */
int initialized; /* Had we already sent init sequence? */ int initialized; /* Had we already sent init sequence? */
int DevModel; /* What type of USBVISION device we got? */ 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 last_error; /* What calamity struck us? */
int curwidth; /* width of the frame the device is currently set to*/ int curwidth; /* width of the frame the device is currently set to*/
int curheight; /* height 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 { ...@@ -382,7 +398,10 @@ struct usb_usbvision {
char *fbuf; /* Videodev buffer area for mmap*/ char *fbuf; /* Videodev buffer area for mmap*/
int max_frame_size; /* Bytes in one video frame */ int max_frame_size; /* Bytes in one video frame */
int fbuf_size; /* Videodev buffer size */ 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 *curFrame; // pointer to current frame, set by usbvision_find_header
struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer
int curSbufNum; // number of current receiving sbuf int curSbufNum; // number of current receiving sbuf
...@@ -406,7 +425,8 @@ struct usb_usbvision { ...@@ -406,7 +425,8 @@ struct usb_usbvision {
struct usbvision_v4l2_format_st palette; struct usbvision_v4l2_format_st palette;
struct v4l2_capability vcap; /* Video capabilities */ 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 */ unsigned char video_endp; /* 0x82 for USBVISION devices based */
// Overlay stuff: // Overlay stuff:
...@@ -463,3 +483,10 @@ struct usb_usbvision { ...@@ -463,3 +483,10 @@ struct usb_usbvision {
#endif /* __LINUX_USBVISION_H */ #endif /* __LINUX_USBVISION_H */
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment