mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (8232): gspca: Change the USERPTR mechanism.
main: Change the packet copy mechanism for userptr. Cannot do reqbufs ioctl when already done and count != 0. Accept count < frame size in read(). Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
c41492c89a
commit
ac0d6df69b
|
@ -36,15 +36,14 @@
|
||||||
#include "gspca.h"
|
#include "gspca.h"
|
||||||
|
|
||||||
/* global values */
|
/* global values */
|
||||||
#define DEF_NURBS 2 /* default number of URBs (mmap) */
|
#define DEF_NURBS 2 /* default number of URBs */
|
||||||
#define USR_NURBS 5 /* default number of URBs (userptr) */
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
|
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
|
||||||
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
|
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
|
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 6)
|
||||||
static const char version[] = "2.1.5";
|
static const char version[] = "2.1.6";
|
||||||
|
|
||||||
static int video_nr = -1;
|
static int video_nr = -1;
|
||||||
|
|
||||||
|
@ -153,7 +152,6 @@ static void fill_frame(struct gspca_dev *gspca_dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resubmit the URB */
|
/* resubmit the URB */
|
||||||
/*fixme: don't do that when userptr and too many URBs sent*/
|
|
||||||
urb->status = 0;
|
urb->status = 0;
|
||||||
st = usb_submit_urb(urb, GFP_ATOMIC);
|
st = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
if (st < 0)
|
if (st < 0)
|
||||||
|
@ -163,18 +161,9 @@ static void fill_frame(struct gspca_dev *gspca_dev,
|
||||||
/*
|
/*
|
||||||
* ISOC message interrupt from the USB device
|
* ISOC message interrupt from the USB device
|
||||||
*
|
*
|
||||||
* Analyse each packet and call the subdriver for copy
|
* Analyse each packet and call the subdriver for copy to the frame buffer.
|
||||||
* to the frame buffer.
|
|
||||||
*
|
|
||||||
* There are 2 functions:
|
|
||||||
* - the first one (isoc_irq_mmap) is used when the application
|
|
||||||
* buffers are mapped. The frame detection and copy is done
|
|
||||||
* at interrupt level.
|
|
||||||
* - the second one (isoc_irq_user) is used when the application
|
|
||||||
* buffers are in user space (userptr). The frame detection
|
|
||||||
* and copy is done by the application.
|
|
||||||
*/
|
*/
|
||||||
static void isoc_irq_mmap(struct urb *urb
|
static void isoc_irq(struct urb *urb
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
|
struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
|
||||||
|
@ -185,56 +174,11 @@ static void isoc_irq_mmap(struct urb *urb
|
||||||
fill_frame(gspca_dev, urb);
|
fill_frame(gspca_dev, urb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isoc_irq_user(struct urb *urb
|
|
||||||
)
|
|
||||||
{
|
|
||||||
struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
PDEBUG(D_PACK, "isoc irq user");
|
|
||||||
if (!gspca_dev->streaming)
|
|
||||||
return;
|
|
||||||
|
|
||||||
i = gspca_dev->urb_in % gspca_dev->nurbs;
|
|
||||||
if (urb != gspca_dev->urb[i]) {
|
|
||||||
PDEBUG(D_ERR|D_PACK, "urb out of sequence");
|
|
||||||
return; /* should never occur */
|
|
||||||
}
|
|
||||||
|
|
||||||
gspca_dev->urb_in++;
|
|
||||||
atomic_inc(&gspca_dev->nevent); /* new event */
|
|
||||||
wake_up_interruptible(&gspca_dev->wq);
|
|
||||||
/*fixme: submit a new URBs until urb_in == urb_out (% nurbs)*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* treat the isoc messages
|
|
||||||
*
|
|
||||||
* This routine is called by the application (case userptr).
|
|
||||||
*/
|
|
||||||
static void isoc_transfer(struct gspca_dev *gspca_dev)
|
|
||||||
{
|
|
||||||
struct urb *urb;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
i = gspca_dev->urb_out;
|
|
||||||
PDEBUG(D_PACK, "isoc transf i:%d o:%d", gspca_dev->urb_in, i);
|
|
||||||
if (i == gspca_dev->urb_in) /* isoc message to read */
|
|
||||||
break; /* no (more) message */
|
|
||||||
atomic_dec(&gspca_dev->nevent);
|
|
||||||
/*PDEBUG(D_PACK, "isoc_trf nevent: %d", atomic_read(&gspca_dev->nevent));*/
|
|
||||||
gspca_dev->urb_out = i + 1; /* message treated */
|
|
||||||
urb = gspca_dev->urb[i % gspca_dev->nurbs];
|
|
||||||
fill_frame(gspca_dev, urb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add data to the current frame
|
* add data to the current frame
|
||||||
*
|
*
|
||||||
* This function is called by the subdrivers at interrupt level
|
* This function is called by the subdrivers at interrupt level.
|
||||||
* or user level.
|
*
|
||||||
* To build a frame, these ones must add
|
* To build a frame, these ones must add
|
||||||
* - one FIRST_PACKET
|
* - one FIRST_PACKET
|
||||||
* - 0 or many INTER_PACKETs
|
* - 0 or many INTER_PACKETs
|
||||||
|
@ -277,16 +221,7 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
|
||||||
frame->v4l2_buf.length);
|
frame->v4l2_buf.length);
|
||||||
packet_type = DISCARD_PACKET;
|
packet_type = DISCARD_PACKET;
|
||||||
} else {
|
} else {
|
||||||
if (frame->v4l2_buf.memory != V4L2_MEMORY_USERPTR) {
|
|
||||||
memcpy(frame->data_end, data, len);
|
memcpy(frame->data_end, data, len);
|
||||||
} else {
|
|
||||||
if (copy_to_user(frame->data_end,
|
|
||||||
data, len) != 0) {
|
|
||||||
PDEBUG(D_ERR|D_PACK,
|
|
||||||
"copy to user failed");
|
|
||||||
packet_type = DISCARD_PACKET;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
frame->data_end += len;
|
frame->data_end += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +268,6 @@ static void *rvmalloc(unsigned long size)
|
||||||
/* size = PAGE_ALIGN(size); (already done) */
|
/* size = PAGE_ALIGN(size); (already done) */
|
||||||
mem = vmalloc_32(size);
|
mem = vmalloc_32(size);
|
||||||
if (mem != NULL) {
|
if (mem != NULL) {
|
||||||
memset(mem, 0, size);
|
|
||||||
adr = (unsigned long) mem;
|
adr = (unsigned long) mem;
|
||||||
while ((long) size > 0) {
|
while ((long) size > 0) {
|
||||||
SetPageReserved(vmalloc_to_page((void *) adr));
|
SetPageReserved(vmalloc_to_page((void *) adr));
|
||||||
|
@ -344,14 +278,12 @@ static void *rvmalloc(unsigned long size)
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rvfree(void *mem, unsigned long size)
|
static void rvfree(void *mem, long size)
|
||||||
{
|
{
|
||||||
unsigned long adr;
|
unsigned long adr;
|
||||||
|
|
||||||
if (!mem)
|
|
||||||
return;
|
|
||||||
adr = (unsigned long) mem;
|
adr = (unsigned long) mem;
|
||||||
while ((long) size > 0) {
|
while (size > 0) {
|
||||||
ClearPageReserved(vmalloc_to_page((void *) adr));
|
ClearPageReserved(vmalloc_to_page((void *) adr));
|
||||||
adr += PAGE_SIZE;
|
adr += PAGE_SIZE;
|
||||||
size -= PAGE_SIZE;
|
size -= PAGE_SIZE;
|
||||||
|
@ -370,17 +302,14 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
|
||||||
frsz = gspca_dev->cam.cam_mode[i].sizeimage;
|
frsz = gspca_dev->cam.cam_mode[i].sizeimage;
|
||||||
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
|
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
|
||||||
frsz = PAGE_ALIGN(frsz);
|
frsz = PAGE_ALIGN(frsz);
|
||||||
PDEBUG(D_STREAM, "new fr_sz: %d", frsz);
|
|
||||||
gspca_dev->frsz = frsz;
|
gspca_dev->frsz = frsz;
|
||||||
if (count > GSPCA_MAX_FRAMES)
|
if (count > GSPCA_MAX_FRAMES)
|
||||||
count = GSPCA_MAX_FRAMES;
|
count = GSPCA_MAX_FRAMES;
|
||||||
if (gspca_dev->memory == V4L2_MEMORY_MMAP) {
|
|
||||||
gspca_dev->frbuf = rvmalloc(frsz * count);
|
gspca_dev->frbuf = rvmalloc(frsz * count);
|
||||||
if (!gspca_dev->frbuf) {
|
if (!gspca_dev->frbuf) {
|
||||||
err("frame alloc failed");
|
err("frame alloc failed");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
gspca_dev->nframes = count;
|
gspca_dev->nframes = count;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
frame = &gspca_dev->frame[i];
|
frame = &gspca_dev->frame[i];
|
||||||
|
@ -391,12 +320,10 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
|
||||||
frame->v4l2_buf.length = frsz;
|
frame->v4l2_buf.length = frsz;
|
||||||
frame->v4l2_buf.memory = gspca_dev->memory;
|
frame->v4l2_buf.memory = gspca_dev->memory;
|
||||||
frame->v4l2_buf.sequence = 0;
|
frame->v4l2_buf.sequence = 0;
|
||||||
if (gspca_dev->memory == V4L2_MEMORY_MMAP) {
|
|
||||||
frame->data = frame->data_end =
|
frame->data = frame->data_end =
|
||||||
gspca_dev->frbuf + i * frsz;
|
gspca_dev->frbuf + i * frsz;
|
||||||
frame->v4l2_buf.m.offset = i * frsz;
|
frame->v4l2_buf.m.offset = i * frsz;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
|
gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
|
||||||
gspca_dev->last_packet_type = DISCARD_PACKET;
|
gspca_dev->last_packet_type = DISCARD_PACKET;
|
||||||
gspca_dev->sequence = 0;
|
gspca_dev->sequence = 0;
|
||||||
|
@ -509,7 +436,6 @@ static int create_urbs(struct gspca_dev *gspca_dev,
|
||||||
{
|
{
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
int n, nurbs, i, psize, npkt, bsize;
|
int n, nurbs, i, psize, npkt, bsize;
|
||||||
usb_complete_t usb_complete;
|
|
||||||
|
|
||||||
/* calculate the packet size and the number of packets */
|
/* calculate the packet size and the number of packets */
|
||||||
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
|
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
|
||||||
|
@ -522,14 +448,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
|
||||||
bsize = psize * npkt;
|
bsize = psize * npkt;
|
||||||
PDEBUG(D_STREAM,
|
PDEBUG(D_STREAM,
|
||||||
"isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
|
"isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
|
||||||
/*fixme:don't submit all URBs when userptr*/
|
|
||||||
if (gspca_dev->memory != V4L2_MEMORY_USERPTR) {
|
|
||||||
usb_complete = isoc_irq_mmap;
|
|
||||||
nurbs = DEF_NURBS;
|
nurbs = DEF_NURBS;
|
||||||
} else {
|
|
||||||
usb_complete = isoc_irq_user;
|
|
||||||
nurbs = USR_NURBS;
|
|
||||||
}
|
|
||||||
gspca_dev->nurbs = nurbs;
|
gspca_dev->nurbs = nurbs;
|
||||||
for (n = 0; n < nurbs; n++) {
|
for (n = 0; n < nurbs; n++) {
|
||||||
urb = usb_alloc_urb(npkt, GFP_KERNEL);
|
urb = usb_alloc_urb(npkt, GFP_KERNEL);
|
||||||
|
@ -556,7 +475,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
|
||||||
urb->transfer_flags = URB_ISO_ASAP
|
urb->transfer_flags = URB_ISO_ASAP
|
||||||
| URB_NO_TRANSFER_DMA_MAP;
|
| URB_NO_TRANSFER_DMA_MAP;
|
||||||
urb->interval = ep->desc.bInterval;
|
urb->interval = ep->desc.bInterval;
|
||||||
urb->complete = usb_complete;
|
urb->complete = isoc_irq;
|
||||||
urb->number_of_packets = npkt;
|
urb->number_of_packets = npkt;
|
||||||
urb->transfer_buffer_length = bsize;
|
urb->transfer_buffer_length = bsize;
|
||||||
for (i = 0; i < npkt; i++) {
|
for (i = 0; i < npkt; i++) {
|
||||||
|
@ -564,7 +483,6 @@ static int create_urbs(struct gspca_dev *gspca_dev,
|
||||||
urb->iso_frame_desc[i].offset = psize * i;
|
urb->iso_frame_desc[i].offset = psize * i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gspca_dev->urb_in = gspca_dev->urb_out = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,6 +981,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
|
||||||
if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
switch (rb->memory) {
|
switch (rb->memory) {
|
||||||
|
case GSPCA_MEMORY_READ:
|
||||||
case V4L2_MEMORY_MMAP:
|
case V4L2_MEMORY_MMAP:
|
||||||
case V4L2_MEMORY_USERPTR:
|
case V4L2_MEMORY_USERPTR:
|
||||||
break;
|
break;
|
||||||
|
@ -1072,13 +991,6 @@ static int vidioc_reqbufs(struct file *file, void *priv,
|
||||||
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
|
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
for (i = 0; i < gspca_dev->nframes; i++) {
|
|
||||||
if (gspca_dev->frame[i].vma_use_count) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* only one file may do capture */
|
/* only one file may do capture */
|
||||||
if ((gspca_dev->capt_file != NULL && gspca_dev->capt_file != file)
|
if ((gspca_dev->capt_file != NULL && gspca_dev->capt_file != file)
|
||||||
|| gspca_dev->streaming) {
|
|| gspca_dev->streaming) {
|
||||||
|
@ -1086,10 +998,20 @@ static int vidioc_reqbufs(struct file *file, void *priv,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rb->count == 0) { /* unrequest? */
|
if (rb->count == 0) { /* unrequest */
|
||||||
|
for (i = 0; i < gspca_dev->nframes; i++) {
|
||||||
|
if (gspca_dev->frame[i].vma_use_count) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
frame_free(gspca_dev);
|
frame_free(gspca_dev);
|
||||||
gspca_dev->capt_file = NULL;
|
gspca_dev->capt_file = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
if (gspca_dev->nframes != 0) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
gspca_dev->memory = rb->memory;
|
gspca_dev->memory = rb->memory;
|
||||||
ret = frame_alloc(gspca_dev, rb->count);
|
ret = frame_alloc(gspca_dev, rb->count);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
@ -1301,9 +1223,6 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned long addr, start, size;
|
unsigned long addr, start, size;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
|
||||||
int compat = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
start = vma->vm_start;
|
start = vma->vm_start;
|
||||||
size = vma->vm_end - vma->vm_start;
|
size = vma->vm_end - vma->vm_start;
|
||||||
|
@ -1338,9 +1257,9 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
||||||
if (i == 0 && size == frame->v4l2_buf.length * gspca_dev->nframes)
|
/* v4l1 maps all the buffers */
|
||||||
compat = 1;
|
if (i != 0
|
||||||
else
|
|| size != frame->v4l2_buf.length * gspca_dev->nframes)
|
||||||
#endif
|
#endif
|
||||||
if (size != frame->v4l2_buf.length) {
|
if (size != frame->v4l2_buf.length) {
|
||||||
PDEBUG(D_STREAM, "mmap bad size");
|
PDEBUG(D_STREAM, "mmap bad size");
|
||||||
|
@ -1368,14 +1287,6 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
vma->vm_ops = &gspca_vm_ops;
|
vma->vm_ops = &gspca_vm_ops;
|
||||||
vma->vm_private_data = frame;
|
vma->vm_private_data = frame;
|
||||||
gspca_vm_open(vma);
|
gspca_vm_open(vma);
|
||||||
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
|
||||||
if (compat) {
|
|
||||||
/*fixme: ugly*/
|
|
||||||
for (i = 1; i < gspca_dev->nframes; ++i)
|
|
||||||
gspca_dev->frame[i].v4l2_buf.flags |=
|
|
||||||
V4L2_BUF_FLAG_MAPPED;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&gspca_dev->queue_lock);
|
mutex_unlock(&gspca_dev->queue_lock);
|
||||||
|
@ -1393,10 +1304,6 @@ static int frame_wait(struct gspca_dev *gspca_dev,
|
||||||
struct gspca_frame *frame;
|
struct gspca_frame *frame;
|
||||||
int i, j, ret;
|
int i, j, ret;
|
||||||
|
|
||||||
/* if userptr, treat the awaiting URBs */
|
|
||||||
if (gspca_dev->memory == V4L2_MEMORY_USERPTR)
|
|
||||||
isoc_transfer(gspca_dev);
|
|
||||||
|
|
||||||
/* check if a frame is ready */
|
/* check if a frame is ready */
|
||||||
i = gspca_dev->fr_o;
|
i = gspca_dev->fr_o;
|
||||||
j = gspca_dev->fr_queue[i];
|
j = gspca_dev->fr_queue[i];
|
||||||
|
@ -1421,8 +1328,6 @@ static int frame_wait(struct gspca_dev *gspca_dev,
|
||||||
atomic_dec(&gspca_dev->nevent);
|
atomic_dec(&gspca_dev->nevent);
|
||||||
if (!gspca_dev->streaming || !gspca_dev->present)
|
if (!gspca_dev->streaming || !gspca_dev->present)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (gspca_dev->memory == V4L2_MEMORY_USERPTR)
|
|
||||||
isoc_transfer(gspca_dev);
|
|
||||||
i = gspca_dev->fr_o;
|
i = gspca_dev->fr_o;
|
||||||
j = gspca_dev->fr_queue[i];
|
j = gspca_dev->fr_queue[i];
|
||||||
frame = &gspca_dev->frame[j];
|
frame = &gspca_dev->frame[j];
|
||||||
|
@ -1455,9 +1360,9 @@ static int vidioc_dqbuf(struct file *file, void *priv,
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
PDEBUG(D_FRAM, "dqbuf");
|
PDEBUG(D_FRAM, "dqbuf");
|
||||||
if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
|
if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||||
|| (v4l2_buf->memory != V4L2_MEMORY_MMAP
|
return -EINVAL;
|
||||||
&& v4l2_buf->memory != V4L2_MEMORY_USERPTR))
|
if (v4l2_buf->memory != gspca_dev->memory)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!gspca_dev->streaming)
|
if (!gspca_dev->streaming)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1475,6 +1380,16 @@ static int vidioc_dqbuf(struct file *file, void *priv,
|
||||||
goto out;
|
goto out;
|
||||||
i = ret; /* frame index */
|
i = ret; /* frame index */
|
||||||
frame = &gspca_dev->frame[i];
|
frame = &gspca_dev->frame[i];
|
||||||
|
if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
|
||||||
|
if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
|
||||||
|
frame->data,
|
||||||
|
frame->v4l2_buf.bytesused)) {
|
||||||
|
PDEBUG(D_ERR|D_STREAM,
|
||||||
|
"dqbuf cp to user failed");
|
||||||
|
ret = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
|
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
|
||||||
memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
|
memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
|
||||||
PDEBUG(D_FRAM, "dqbuf %d", i);
|
PDEBUG(D_FRAM, "dqbuf %d", i);
|
||||||
|
@ -1529,8 +1444,6 @@ static int vidioc_qbuf(struct file *file, void *priv,
|
||||||
/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
|
/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
|
||||||
|
|
||||||
if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
|
if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
|
||||||
frame->data = frame->data_end =
|
|
||||||
(__u8 *) v4l2_buf->m.userptr;
|
|
||||||
frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
|
frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
|
||||||
frame->v4l2_buf.length = v4l2_buf->length;
|
frame->v4l2_buf.length = v4l2_buf->length;
|
||||||
}
|
}
|
||||||
|
@ -1568,7 +1481,7 @@ static int read_alloc(struct gspca_dev *gspca_dev,
|
||||||
memset(&rb, 0, sizeof rb);
|
memset(&rb, 0, sizeof rb);
|
||||||
rb.count = gspca_dev->nbufread;
|
rb.count = gspca_dev->nbufread;
|
||||||
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
rb.memory = V4L2_MEMORY_MMAP;
|
rb.memory = GSPCA_MEMORY_READ;
|
||||||
ret = vidioc_reqbufs(file, gspca_dev, &rb);
|
ret = vidioc_reqbufs(file, gspca_dev, &rb);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
PDEBUG(D_STREAM, "read reqbuf err %d", ret);
|
PDEBUG(D_STREAM, "read reqbuf err %d", ret);
|
||||||
|
@ -1576,7 +1489,7 @@ static int read_alloc(struct gspca_dev *gspca_dev,
|
||||||
}
|
}
|
||||||
memset(&v4l2_buf, 0, sizeof v4l2_buf);
|
memset(&v4l2_buf, 0, sizeof v4l2_buf);
|
||||||
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
v4l2_buf.memory = V4L2_MEMORY_MMAP;
|
v4l2_buf.memory = GSPCA_MEMORY_READ;
|
||||||
for (i = 0; i < gspca_dev->nbufread; i++) {
|
for (i = 0; i < gspca_dev->nbufread; i++) {
|
||||||
v4l2_buf.index = i;
|
v4l2_buf.index = i;
|
||||||
/*fixme: ugly!*/
|
/*fixme: ugly!*/
|
||||||
|
@ -1629,11 +1542,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if userptr, treat the awaiting URBs */
|
|
||||||
if (gspca_dev->memory == V4L2_MEMORY_USERPTR
|
|
||||||
&& gspca_dev->capt_file == file)
|
|
||||||
isoc_transfer(gspca_dev);
|
|
||||||
|
|
||||||
i = gspca_dev->fr_o;
|
i = gspca_dev->fr_o;
|
||||||
i = gspca_dev->fr_queue[i];
|
i = gspca_dev->fr_queue[i];
|
||||||
if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
|
if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
|
||||||
|
@ -1678,7 +1586,7 @@ static ssize_t dev_read(struct file *file, char __user *data,
|
||||||
for (;;) {
|
for (;;) {
|
||||||
memset(&v4l2_buf, 0, sizeof v4l2_buf);
|
memset(&v4l2_buf, 0, sizeof v4l2_buf);
|
||||||
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
v4l2_buf.memory = V4L2_MEMORY_MMAP;
|
v4l2_buf.memory = GSPCA_MEMORY_READ;
|
||||||
ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);
|
ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
PDEBUG(D_STREAM, "read dqbuf err %d", ret);
|
PDEBUG(D_STREAM, "read dqbuf err %d", ret);
|
||||||
|
@ -1700,13 +1608,7 @@ static ssize_t dev_read(struct file *file, char __user *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy the frame */
|
/* copy the frame */
|
||||||
if (count < frame->v4l2_buf.bytesused) {
|
if (count > frame->v4l2_buf.bytesused)
|
||||||
PDEBUG(D_STREAM, "read bad count: %d < %d",
|
|
||||||
count, frame->v4l2_buf.bytesused);
|
|
||||||
/*fixme: special errno?*/
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
count = frame->v4l2_buf.bytesused;
|
count = frame->v4l2_buf.bytesused;
|
||||||
ret = copy_to_user(data, frame->data, count);
|
ret = copy_to_user(data, frame->data, count);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
|
|
|
@ -156,8 +156,6 @@ struct gspca_dev {
|
||||||
char nbufread; /* number of buffers for read() */
|
char nbufread; /* number of buffers for read() */
|
||||||
char nurbs; /* number of allocated URBs */
|
char nurbs; /* number of allocated URBs */
|
||||||
char memory; /* memory type (V4L2_MEMORY_xxx) */
|
char memory; /* memory type (V4L2_MEMORY_xxx) */
|
||||||
__u8 urb_in; /* URB pointers - used when !mmap */
|
|
||||||
__u8 urb_out;
|
|
||||||
__u8 nbalt; /* number of USB alternate settings */
|
__u8 nbalt; /* number of USB alternate settings */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue