diff options
Diffstat (limited to 'drivers/media/video/gspca/gspca.c')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 517 |
1 files changed, 246 insertions, 271 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 678675bb3652..8fe8fb486d62 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 9, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 10, 0) #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -148,7 +148,7 @@ static void int_irq(struct urb *urb) if (ret == 0) { ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - PDEBUG(D_ERR, "Resubmit URB failed with error %i", ret); + err("Resubmit URB failed with error %i", ret); } } @@ -177,8 +177,8 @@ static int gspca_input_connect(struct gspca_dev *dev) err = input_register_device(input_dev); if (err) { - PDEBUG(D_ERR, "Input device registration failed " - "with error %i", err); + err("Input device registration failed with error %i", + err); input_dev->dev.parent = NULL; input_free_device(input_dev); } else { @@ -201,7 +201,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, buffer_len = le16_to_cpu(ep->wMaxPacketSize); interval = ep->bInterval; - PDEBUG(D_PROBE, "found int in endpoint: 0x%x, " + PDEBUG(D_CONF, "found int in endpoint: 0x%x, " "buffer_len=%u, interval=%u", ep->bEndpointAddress, buffer_len, interval); @@ -223,10 +223,11 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, usb_rcvintpipe(dev, ep->bEndpointAddress), buffer, buffer_len, int_irq, (void *)gspca_dev, interval); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; gspca_dev->int_urb = urb; ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { - PDEBUG(D_ERR, "submit URB failed with error %i", ret); + PDEBUG(D_ERR, "submit int URB failed with error %i", ret); goto error_submit; } return ret; @@ -294,19 +295,6 @@ static inline int gspca_input_connect(struct gspca_dev *dev) } #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 */ @@ -340,8 +328,7 @@ static void fill_frame(struct gspca_dev *gspca_dev, } st = urb->iso_frame_desc[i].status; if (st) { - PDEBUG(D_ERR, - "ISOC data error: [%d] len=%d, status=%d", + err("ISOC data error: [%d] len=%d, status=%d", i, len, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; @@ -359,7 +346,7 @@ resubmit: /* resubmit the URB */ st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); + err("usb_submit_urb() ret %d", st); } /* @@ -413,7 +400,7 @@ resubmit: if (gspca_dev->cam.bulk_nurbs != 0) { st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); + err("usb_submit_urb() ret %d", st); } } @@ -439,56 +426,71 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, 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; + gspca_dev->sequence++; + 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; - } else if (gspca_dev->last_packet_type == DISCARD_PACKET) { - if (packet_type == LAST_PACKET) - gspca_dev->last_packet_type = packet_type; - return; + frame->v4l2_buf.sequence = gspca_dev->sequence++; + gspca_dev->image = frame->data; + gspca_dev->image_len = 0; + } else { + switch (gspca_dev->last_packet_type) { + case DISCARD_PACKET: + if (packet_type == LAST_PACKET) + gspca_dev->last_packet_type = packet_type; + return; + case LAST_PACKET: + return; + } } /* 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; +/* !! image is NULL only when last pkt is LAST or DISCARD + if (gspca_dev->image == NULL) { + err("gspca_frame_add() image == NULL"); + return; + } + */ + 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); @@ -506,36 +508,6 @@ static int gspca_is_compressed(__u32 format) 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) { @@ -548,9 +520,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev, 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; @@ -565,14 +537,12 @@ static int frame_alloc(struct gspca_dev *gspca_dev, 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; } @@ -582,8 +552,7 @@ static void frame_free(struct gspca_dev *gspca_dev) 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; @@ -621,7 +590,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) return 0; ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); if (ret < 0) - PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret); + err("set alt 0 err %d", ret); return ret; } @@ -683,12 +652,16 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) : USB_ENDPOINT_XFER_ISOC; i = gspca_dev->alt; /* previous alt setting */ if (gspca_dev->cam.reverse_alts) { + if (gspca_dev->audio && i < gspca_dev->nbalt - 2) + i++; while (++i < gspca_dev->nbalt) { ep = alt_xfer(&intf->altsetting[i], xfer); if (ep) break; } } else { + if (gspca_dev->audio && i > 1) + i--; while (--i >= 0) { ep = alt_xfer(&intf->altsetting[i], xfer); if (ep) @@ -811,6 +784,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_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 @@ -871,8 +850,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) break; gspca_stream_off(gspca_dev); if (ret != -ENOSPC) { - PDEBUG(D_ERR|D_STREAM, - "usb_submit_urb alt %d err %d", + err("usb_submit_urb alt %d err %d", gspca_dev->alt, ret); goto out; } @@ -901,6 +879,7 @@ out: static void gspca_set_default_mode(struct gspca_dev *gspca_dev) { + struct gspca_ctrl *ctrl; int i; i = gspca_dev->cam.nmodes - 1; /* take the highest mode */ @@ -908,6 +887,16 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev) gspca_dev->width = gspca_dev->cam.cam_mode[i].width; gspca_dev->height = gspca_dev->cam.cam_mode[i].height; gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat; + + /* set the current control values to their default values + * which may have changed in sd_init() */ + ctrl = gspca_dev->cam.ctrls; + if (ctrl != NULL) { + for (i = 0; + i < gspca_dev->sd_desc->nctrls; + i++, ctrl++) + ctrl->val = ctrl->def; + } } static int wxh_to_mode(struct gspca_dev *gspca_dev, @@ -1331,7 +1320,7 @@ out: return ret; } -static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev, +static int get_ctrl(struct gspca_dev *gspca_dev, int id) { const struct ctrl *ctrls; @@ -1343,9 +1332,9 @@ static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev, if (gspca_dev->ctrl_dis & (1 << i)) continue; if (id == ctrls->qctrl.id) - return ctrls; + return i; } - return NULL; + return -1; } static int vidioc_queryctrl(struct file *file, void *priv, @@ -1353,34 +1342,40 @@ static int vidioc_queryctrl(struct file *file, void *priv, { struct gspca_dev *gspca_dev = priv; const struct ctrl *ctrls; - int i; + struct gspca_ctrl *gspca_ctrl; + int i, idx; u32 id; - ctrls = NULL; id = q_ctrl->id; if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { id &= V4L2_CTRL_ID_MASK; id++; + idx = -1; for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { if (gspca_dev->ctrl_dis & (1 << i)) continue; if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) continue; - if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id - > ctrls->qctrl.id) + if (idx >= 0 + && gspca_dev->sd_desc->ctrls[i].qctrl.id + > gspca_dev->sd_desc->ctrls[idx].qctrl.id) continue; - ctrls = &gspca_dev->sd_desc->ctrls[i]; + idx = i; } - if (ctrls == NULL) - return -EINVAL; } else { - ctrls = get_ctrl(gspca_dev, id); - if (ctrls == NULL) - return -EINVAL; - i = ctrls - gspca_dev->sd_desc->ctrls; + idx = get_ctrl(gspca_dev, id); } - memcpy(q_ctrl, ctrls, sizeof *q_ctrl); - if (gspca_dev->ctrl_inac & (1 << i)) + if (idx < 0) + return -EINVAL; + ctrls = &gspca_dev->sd_desc->ctrls[idx]; + memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl); + if (gspca_dev->cam.ctrls != NULL) { + gspca_ctrl = &gspca_dev->cam.ctrls[idx]; + q_ctrl->default_value = gspca_ctrl->def; + q_ctrl->minimum = gspca_ctrl->min; + q_ctrl->maximum = gspca_ctrl->max; + } + if (gspca_dev->ctrl_inac & (1 << idx)) q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; } @@ -1390,23 +1385,46 @@ static int vidioc_s_ctrl(struct file *file, void *priv, { struct gspca_dev *gspca_dev = priv; const struct ctrl *ctrls; - int ret; + struct gspca_ctrl *gspca_ctrl; + int idx, ret; - ctrls = get_ctrl(gspca_dev, ctrl->id); - if (ctrls == NULL) + idx = get_ctrl(gspca_dev, ctrl->id); + if (idx < 0) return -EINVAL; - - if (ctrl->value < ctrls->qctrl.minimum - || ctrl->value > ctrls->qctrl.maximum) - return -ERANGE; + if (gspca_dev->ctrl_inac & (1 << idx)) + return -EINVAL; + ctrls = &gspca_dev->sd_desc->ctrls[idx]; + if (gspca_dev->cam.ctrls != NULL) { + gspca_ctrl = &gspca_dev->cam.ctrls[idx]; + if (ctrl->value < gspca_ctrl->min + || ctrl->value > gspca_ctrl->max) + return -ERANGE; + } else { + gspca_ctrl = NULL; + if (ctrl->value < ctrls->qctrl.minimum + || ctrl->value > ctrls->qctrl.maximum) + return -ERANGE; + } PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } gspca_dev->usb_err = 0; - if (gspca_dev->present) + if (ctrls->set != NULL) { ret = ctrls->set(gspca_dev, ctrl->value); - else - ret = -ENODEV; + goto out; + } + if (gspca_ctrl != NULL) { + gspca_ctrl->val = ctrl->value; + if (ctrls->set_control != NULL + && gspca_dev->streaming) + ctrls->set_control(gspca_dev); + } + ret = gspca_dev->usb_err; +out: mutex_unlock(&gspca_dev->usb_lock); return ret; } @@ -1416,51 +1434,32 @@ static int vidioc_g_ctrl(struct file *file, void *priv, { struct gspca_dev *gspca_dev = priv; const struct ctrl *ctrls; - int ret; + int idx, ret; - ctrls = get_ctrl(gspca_dev, ctrl->id); - if (ctrls == NULL) + idx = get_ctrl(gspca_dev, ctrl->id); + if (idx < 0) return -EINVAL; + ctrls = &gspca_dev->sd_desc->ctrls[idx]; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } gspca_dev->usb_err = 0; - if (gspca_dev->present) + if (ctrls->get != NULL) { ret = ctrls->get(gspca_dev, &ctrl->value); - else - ret = -ENODEV; + goto out; + } + if (gspca_dev->cam.ctrls != NULL) + ctrl->value = gspca_dev->cam.ctrls[idx].val; + ret = 0; +out: mutex_unlock(&gspca_dev->usb_lock); return ret; } -/*fixme: have an audio flag in gspca_dev?*/ -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - strcpy(audio->name, "Microphone"); - return 0; -} - -static int vidioc_enumaudio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - - strcpy(audio->name, "Microphone"); - audio->capability = 0; - audio->mode = 0; - return 0; -} - static int vidioc_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qmenu) { @@ -1504,7 +1503,8 @@ static int vidioc_reqbufs(struct file *file, void *priv, 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: @@ -1626,7 +1626,7 @@ static int vidioc_streamoff(struct file *file, void *priv, 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; @@ -1650,12 +1650,10 @@ static int vidioc_streamoff(struct file *file, void *priv, 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); @@ -1732,7 +1730,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, 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; @@ -1755,49 +1753,6 @@ static int vidioc_s_parm(struct file *filp, void *priv, 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; @@ -1838,12 +1793,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) 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; @@ -1883,21 +1833,17 @@ 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) @@ -1906,11 +1852,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, 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); @@ -1919,7 +1861,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, gspca_dev->sd_desc->dq_callback(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); } - return j; + return gspca_dev->fr_queue[i]; } /* @@ -2024,15 +1966,9 @@ static int vidioc_qbuf(struct file *file, void *priv, } /* 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; @@ -2088,7 +2024,7 @@ static int read_alloc(struct gspca_dev *gspca_dev, 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"); @@ -2106,11 +2042,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) 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); @@ -2214,9 +2148,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_enumaudio = vidioc_enumaudio, .vidioc_querymenu = vidioc_querymenu, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -2235,9 +2166,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .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 = { @@ -2247,37 +2175,40 @@ static struct video_device gspca_template = { .release = gspca_release, }; +/* initialize the controls */ +static void ctrls_init(struct gspca_dev *gspca_dev) +{ + struct gspca_ctrl *ctrl; + int i; + + for (i = 0, ctrl = gspca_dev->cam.ctrls; + i < gspca_dev->sd_desc->nctrls; + i++, ctrl++) { + ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value; + ctrl->val = ctrl->def; + ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum; + ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum; + } +} + /* * probe and create a new gspca device * * 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; @@ -2293,8 +2224,26 @@ int gspca_dev_probe(struct usb_interface *intf, 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; + + /* check if any audio device */ + if (dev->config->desc.bNumInterfaces != 1) { + int i; + struct usb_interface *intf2; + + for (i = 0; i < dev->config->desc.bNumInterfaces; i++) { + intf2 = dev->config->interface[i]; + if (intf2 != NULL + && intf2->altsetting != NULL + && intf2->altsetting->desc.bInterfaceClass == + USB_CLASS_AUDIO) { + gspca_dev->audio = 1; + break; + } + } + } + gspca_dev->sd_desc = sd_desc; gspca_dev->nbufread = 2; gspca_dev->empty_packet = -1; /* don't check the empty packets */ @@ -2303,6 +2252,8 @@ int gspca_dev_probe(struct usb_interface *intf, ret = sd_desc->config(gspca_dev, id); if (ret < 0) goto out; + if (gspca_dev->cam.ctrls != NULL) + ctrls_init(gspca_dev); ret = sd_desc->init(gspca_dev); if (ret < 0) goto out; @@ -2345,6 +2296,31 @@ out: 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) { + 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) + return -ENODEV; + + return gspca_dev_probe2(intf, id, sd_desc, dev_size, module); +} EXPORT_SYMBOL(gspca_dev_probe); /* @@ -2518,7 +2494,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) { - info("main v%d.%d.%d registered", + info("v%d.%d.%d registered", (DRIVER_VERSION_NUMBER >> 16) & 0xff, (DRIVER_VERSION_NUMBER >> 8) & 0xff, DRIVER_VERSION_NUMBER & 0xff); @@ -2526,7 +2502,6 @@ static int __init gspca_init(void) } static void __exit gspca_exit(void) { - info("main deregistered"); } module_init(gspca_init); |