goto error;
}
- buffer = usb_buffer_alloc(dev, buffer_len,
+ buffer = usb_alloc_coherent(dev, buffer_len,
GFP_KERNEL, &urb->transfer_dma);
if (!buffer) {
ret = -ENOMEM;
return ret;
error_submit:
- usb_buffer_free(dev,
- urb->transfer_buffer_length,
- urb->transfer_buffer,
- urb->transfer_dma);
+ usb_free_coherent(dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
error_buffer:
usb_free_urb(urb);
error:
if (urb) {
gspca_dev->int_urb = NULL;
usb_kill_urb(urb);
- usb_buffer_free(gspca_dev->dev,
- urb->transfer_buffer_length,
- urb->transfer_buffer,
- urb->transfer_dma);
+ usb_free_coherent(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
usb_free_urb(urb);
}
}
}
#endif
-/* get the current input frame buffer */
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
-{
- struct gspca_frame *frame;
-
- frame = gspca_dev->cur_frame;
- if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
- != V4L2_BUF_FLAG_QUEUED)
- return NULL;
- return frame;
-}
-EXPORT_SYMBOL(gspca_get_i_frame);
-
/*
* fill a video frame from an URB and resubmit
*/
PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
- /* check the availability of the frame buffer */
- frame = gspca_dev->cur_frame;
- if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
- != V4L2_BUF_FLAG_QUEUED) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
- /* when start of a new frame, if the current frame buffer
- * is not queued, discard the whole frame */
if (packet_type == FIRST_PACKET) {
- frame->data_end = frame->data;
+ i = atomic_read(&gspca_dev->fr_i);
+
+ /* if there are no queued buffer, discard the whole frame */
+ if (i == atomic_read(&gspca_dev->fr_q)) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+ gspca_dev->image = frame->data;
+ gspca_dev->image_len = 0;
} else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
if (packet_type == LAST_PACKET)
gspca_dev->last_packet_type = packet_type;
/* append the packet to the frame buffer */
if (len > 0) {
- if (frame->data_end - frame->data + len
- > frame->v4l2_buf.length) {
- PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
- frame->data_end - frame->data + len,
- frame->v4l2_buf.length);
+ if (gspca_dev->image_len + len > gspca_dev->frsz) {
+ PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+ gspca_dev->image_len + len,
+ gspca_dev->frsz);
packet_type = DISCARD_PACKET;
} else {
- memcpy(frame->data_end, data, len);
- frame->data_end += len;
+ memcpy(gspca_dev->image + gspca_dev->image_len,
+ data, len);
+ gspca_dev->image_len += len;
}
}
gspca_dev->last_packet_type = packet_type;
- /* if last packet, wake up the application and advance in the queue */
+ /* if last packet, invalidate packet concatenation until
+ * next first packet, wake up the application and advance
+ * in the queue */
if (packet_type == LAST_PACKET) {
- frame->v4l2_buf.bytesused = frame->data_end - frame->data;
- frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
- frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
- wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
- i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
- gspca_dev->fr_i = i;
- PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
- frame->v4l2_buf.bytesused,
- gspca_dev->fr_q,
- i,
- gspca_dev->fr_o);
+ i = atomic_read(&gspca_dev->fr_i);
j = gspca_dev->fr_queue[i];
- gspca_dev->cur_frame = &gspca_dev->frame[j];
+ frame = &gspca_dev->frame[j];
+ frame->v4l2_buf.bytesused = gspca_dev->image_len;
+ frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+ | V4L2_BUF_FLAG_DONE)
+ & ~V4L2_BUF_FLAG_QUEUED;
+ i = (i + 1) % GSPCA_MAX_FRAMES;
+ atomic_set(&gspca_dev->fr_i, i);
+ wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
+ PDEBUG(D_FRAM, "frame complete len:%d",
+ frame->v4l2_buf.bytesused);
+ gspca_dev->image = NULL;
+ gspca_dev->image_len = 0;
}
}
EXPORT_SYMBOL(gspca_frame_add);
return 0;
}
-static void *rvmalloc(long size)
-{
- void *mem;
- unsigned long adr;
-
- mem = vmalloc_32(size);
- if (mem != NULL) {
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *) adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- }
- return mem;
-}
-
-static void rvfree(void *mem, long size)
-{
- unsigned long adr;
-
- adr = (unsigned long) mem;
- while (size > 0) {
- ClearPageReserved(vmalloc_to_page((void *) adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
static int frame_alloc(struct gspca_dev *gspca_dev,
unsigned int count)
{
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
frsz = PAGE_ALIGN(frsz);
gspca_dev->frsz = frsz;
- if (count > GSPCA_MAX_FRAMES)
- count = GSPCA_MAX_FRAMES;
- gspca_dev->frbuf = rvmalloc(frsz * count);
+ if (count >= GSPCA_MAX_FRAMES)
+ count = GSPCA_MAX_FRAMES - 1;
+ gspca_dev->frbuf = vmalloc_32(frsz * count);
if (!gspca_dev->frbuf) {
err("frame alloc failed");
return -ENOMEM;
frame->v4l2_buf.length = frsz;
frame->v4l2_buf.memory = gspca_dev->memory;
frame->v4l2_buf.sequence = 0;
- frame->data = frame->data_end =
- gspca_dev->frbuf + i * frsz;
+ frame->data = gspca_dev->frbuf + i * frsz;
frame->v4l2_buf.m.offset = i * frsz;
}
- gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
- gspca_dev->cur_frame = &gspca_dev->frame[0];
- gspca_dev->last_packet_type = DISCARD_PACKET;
- gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->fr_q, 0);
+ atomic_set(&gspca_dev->fr_i, 0);
+ gspca_dev->fr_o = 0;
return 0;
}
PDEBUG(D_STREAM, "frame free");
if (gspca_dev->frbuf != NULL) {
- rvfree(gspca_dev->frbuf,
- gspca_dev->nframes * gspca_dev->frsz);
+ vfree(gspca_dev->frbuf);
gspca_dev->frbuf = NULL;
for (i = 0; i < gspca_dev->nframes; i++)
gspca_dev->frame[i].data = NULL;
gspca_dev->urb[i] = NULL;
usb_kill_urb(urb);
if (urb->transfer_buffer != NULL)
- usb_buffer_free(gspca_dev->dev,
- urb->transfer_buffer_length,
- urb->transfer_buffer,
- urb->transfer_dma);
+ usb_free_coherent(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
usb_free_urb(urb);
}
}
return -ENOMEM;
}
gspca_dev->urb[n] = urb;
- urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+ urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
bsize,
GFP_KERNEL,
&urb->transfer_dma);
if (urb->transfer_buffer == NULL) {
- err("usb_buffer_alloc failed");
+ err("usb_alloc_coherent failed");
return -ENOMEM;
}
urb->dev = gspca_dev->dev;
goto out;
}
+ /* reset the streaming variables */
+ gspca_dev->image = NULL;
+ gspca_dev->image_len = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+
gspca_dev->usb_err = 0;
/* set the higher alternate setting and
struct gspca_dev *gspca_dev = priv;
int i, ret = 0, streaming;
- switch (rb->memory) {
+ i = rb->memory; /* (avoid compilation warning) */
+ switch (i) {
case GSPCA_MEMORY_READ: /* (internal call) */
case V4L2_MEMORY_MMAP:
case V4L2_MEMORY_USERPTR:
enum v4l2_buf_type buf_type)
{
struct gspca_dev *gspca_dev = priv;
- int i, ret;
+ int ret;
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
- /* empty the application queues */
- for (i = 0; i < gspca_dev->nframes; i++)
- gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
- gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
- gspca_dev->last_packet_type = DISCARD_PACKET;
- gspca_dev->sequence = 0;
+ /* empty the transfer queues */
+ atomic_set(&gspca_dev->fr_q, 0);
+ atomic_set(&gspca_dev->fr_i, 0);
+ gspca_dev->fr_o = 0;
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
int n;
n = parm->parm.capture.readbuffers;
- if (n == 0 || n > GSPCA_MAX_FRAMES)
+ if (n == 0 || n >= GSPCA_MAX_FRAMES)
parm->parm.capture.readbuffers = gspca_dev->nbufread;
else
gspca_dev->nbufread = n;
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
- struct video_mbuf *mbuf)
-{
- struct gspca_dev *gspca_dev = file->private_data;
- int i;
-
- PDEBUG(D_STREAM, "cgmbuf");
- if (gspca_dev->nframes == 0) {
- int ret;
-
- {
- struct v4l2_format fmt;
-
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- i = gspca_dev->cam.nmodes - 1; /* highest mode */
- fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
- fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
- ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
- if (ret != 0)
- return ret;
- }
- {
- struct v4l2_requestbuffers rb;
-
- memset(&rb, 0, sizeof rb);
- rb.count = 4;
- rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rb.memory = V4L2_MEMORY_MMAP;
- ret = vidioc_reqbufs(file, priv, &rb);
- if (ret != 0)
- return ret;
- }
- }
- mbuf->frames = gspca_dev->nframes;
- mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
- for (i = 0; i < mbuf->frames; i++)
- mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
- return 0;
-}
-#endif
-
static int dev_mmap(struct file *file, struct vm_area_struct *vma)
{
struct gspca_dev *gspca_dev = file->private_data;
ret = -EINVAL;
goto out;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* v4l1 maps all the buffers */
- if (i != 0
- || size != frame->v4l2_buf.length * gspca_dev->nframes)
-#endif
- if (size != frame->v4l2_buf.length) {
+ if (size != frame->v4l2_buf.length) {
PDEBUG(D_STREAM, "mmap bad size");
ret = -EINVAL;
goto out;
static int frame_wait(struct gspca_dev *gspca_dev,
int nonblock_ing)
{
- struct gspca_frame *frame;
- int i, j, ret;
+ int i, ret;
/* check if a frame is ready */
i = gspca_dev->fr_o;
- j = gspca_dev->fr_queue[i];
- frame = &gspca_dev->frame[j];
-
- if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) {
+ if (i == atomic_read(&gspca_dev->fr_i)) {
if (nonblock_ing)
return -EAGAIN;
/* wait till a frame is ready */
ret = wait_event_interruptible_timeout(gspca_dev->wq,
- (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) ||
+ i != atomic_read(&gspca_dev->fr_i) ||
!gspca_dev->streaming || !gspca_dev->present,
msecs_to_jiffies(3000));
if (ret < 0)
return -EIO;
}
- gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
- PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
- gspca_dev->fr_q,
- gspca_dev->fr_i,
- gspca_dev->fr_o);
+ gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
if (gspca_dev->sd_desc->dq_callback) {
mutex_lock(&gspca_dev->usb_lock);
gspca_dev->sd_desc->dq_callback(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
- return j;
+ return gspca_dev->fr_queue[i];
}
/*
}
/* put the buffer in the 'queued' queue */
- i = gspca_dev->fr_q;
+ i = atomic_read(&gspca_dev->fr_q);
gspca_dev->fr_queue[i] = index;
- if (gspca_dev->fr_i == i)
- gspca_dev->cur_frame = frame;
- gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
- PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
- gspca_dev->fr_q,
- gspca_dev->fr_i,
- gspca_dev->fr_o);
+ atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES);
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
static unsigned int dev_poll(struct file *file, poll_table *wait)
{
struct gspca_dev *gspca_dev = file->private_data;
- int i, ret;
+ int ret;
PDEBUG(D_FRAM, "poll");
if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
return POLLERR;
- /* check the next incoming buffer */
- i = gspca_dev->fr_o;
- i = gspca_dev->fr_queue[i];
- if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
- ret = POLLIN | POLLRDNORM; /* something to read */
+ /* check if an image has been received */
+ if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+ ret = POLLIN | POLLRDNORM; /* yes */
else
ret = 0;
mutex_unlock(&gspca_dev->queue_lock);
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device gspca_template = {
* This function must be called by the sub-driver when it is
* called for probing a new device.
*/
-int gspca_dev_probe(struct usb_interface *intf,
+int gspca_dev_probe2(struct usb_interface *intf,
const struct usb_device_id *id,
const struct sd_desc *sd_desc,
int dev_size,
struct module *module)
{
- struct usb_interface_descriptor *interface;
struct gspca_dev *gspca_dev;
struct usb_device *dev = interface_to_usbdev(intf);
int ret;
PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
- /* we don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1) {
- PDEBUG(D_ERR, "Too many config");
- return -ENODEV;
- }
-
- /* the USB video interface must be the first one */
- interface = &intf->cur_altsetting->desc;
- if (dev->config->desc.bNumInterfaces != 1 &&
- interface->bInterfaceNumber != 0)
- return -ENODEV;
-
/* create the device */
if (dev_size < sizeof *gspca_dev)
dev_size = sizeof *gspca_dev;
goto out;
}
gspca_dev->dev = dev;
- gspca_dev->iface = interface->bInterfaceNumber;
+ gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
gspca_dev->nbalt = intf->num_altsetting;
gspca_dev->sd_desc = sd_desc;
gspca_dev->nbufread = 2;
kfree(gspca_dev);
return ret;
}
+EXPORT_SYMBOL(gspca_dev_probe2);
+
+/* same function as the previous one, but check the interface */
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+
+ /* we don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1) {
+ PDEBUG(D_ERR, "%04x:%04x too many config",
+ id->idVendor, id->idProduct);
+ return -ENODEV;
+ }
+
+ /* the USB video interface must be the first one */
+ if (dev->config->desc.bNumInterfaces != 1
+ && intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+ PDEBUG(D_ERR, "%04x:%04x bad interface %d",
+ id->idVendor, id->idProduct,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+ return -ENODEV;
+ }
+
+ return gspca_dev_probe2(intf, id, sd_desc, dev_size, module);
+}
EXPORT_SYMBOL(gspca_dev_probe);
/*