static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
{
+ #if 0 /* ddl@rock-chips.com: address must align to 4-bytes */
return ctrl->uvc_data + id * ctrl->info.size;
+ #else
+ return ctrl->uvc_data + id * ((ctrl->info.size+3)/4*4);
+ #endif
}
static inline int uvc_test_bit(const __u8 *data, int bit)
INIT_LIST_HEAD(&ctrl->info.mappings);
/* Allocate an array to save control values (cur, def, max, etc.) */
+ #if 0 /* ddl@rock-chips.com: address must align to 4-bytes */
ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
GFP_KERNEL);
+ #else
+ ctrl->uvc_data = kzalloc(((ctrl->info.size+3)/4*4) * UVC_CTRL_DATA_LAST + 1,
+ GFP_KERNEL);
+ #endif
if (ctrl->uvc_data == NULL) {
ret = -ENOMEM;
goto done;
urb->transfer_buffer_length = stream->urb_size - len;
}
-
-static void uvc_video_complete(struct urb *urb)
-{
+/* ddl@rock-chips.com : uvc_video_complete is run in_interrupt(), so uvc decode operation delay run in tasklet for
+* usb host reenable interrupt soon
+*/
+static void uvc_video_complete_fun (struct urb *urb)
+{
struct uvc_streaming *stream = urb->context;
struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *buf = NULL;
unsigned long flags;
int ret;
+ int i;
+ atomic_t *urb_state=NULL;
switch (urb->status) {
case 0:
return;
}
+ for (i = 0; i < UVC_URBS; ++i) {
+ if (stream->urb[i] == urb) {
+ urb_state = &stream->urb_state[i];
+ break;
+ }
+ }
+
+ if (urb_state == NULL) {
+ printk("urb(%p) cann't be finded in stream->urb(%p, %p, %p, %p, %p)\n",
+ urb,stream->urb[0],stream->urb[1],stream->urb[2],stream->urb[3],stream->urb[4]);
+ /* BUG(); */
+ uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+ return;
+ }
+
+ if (atomic_read(urb_state)==UrbDeactive) {
+ printk(KERN_DEBUG "urb is deactive, this urb complete cancel!");
+ uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+ return;
+ }
+
spin_lock_irqsave(&queue->irqlock, flags);
if (!list_empty(&queue->irqqueue))
buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
ret);
+ uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+ return;
+ }
+}
+static void uvc_video_complete_tasklet(unsigned long data)
+{
+ struct urb *urb = (struct urb*)data;
+
+ uvc_video_complete_fun(urb);
+
+ return;
+}
+static void uvc_video_complete(struct urb *urb)
+{
+ int i;
+ struct uvc_streaming *stream = urb->context;
+ struct tasklet_struct *tasklet = NULL;
+ atomic_t *urb_state;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ if (stream->urb[i] == urb) {
+ tasklet = stream->tasklet[i];
+ urb_state = &stream->urb_state[i];
+ break;
+ }
+ }
+
+ if ((tasklet != NULL)&&(atomic_read(urb_state)==UrbActive)) {
+ tasklet_hi_schedule(tasklet);
+ } else {
+ uvc_video_complete_fun(urb);
}
}
urb = stream->urb[i];
if (urb == NULL)
continue;
+ else
+ atomic_set(&stream->urb_state[i],UrbDeactive);
+
+ if (stream->tasklet[i]) {
+ tasklet_kill(stream->tasklet[i]);
+ kfree(stream->tasklet[i]);
+ stream->tasklet[i] = NULL;
+ }
usb_kill_urb(urb);
usb_free_urb(urb);
}
stream->urb[i] = urb;
+ /* ddl@rock-chips.com */
+ atomic_set(&stream->urb_state[i],UrbActive);
+ stream->tasklet[i] = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+ if (stream->tasklet[i] == NULL) {
+ uvc_printk(KERN_ERR, "device %s requested tasklet memory fail!\n",
+ stream->dev->name);
+ } else {
+ tasklet_init(stream->tasklet[i], uvc_video_complete_tasklet, (unsigned long)urb);
+ }
}
return 0;
#endif
stream->urb[i] = urb;
+
+ /* ddl@rock-chips.com */
+ stream->tasklet[i] = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+ if (stream->tasklet[i] == NULL) {
+ uvc_printk(KERN_ERR, "device %s requested tasklet memory fail!\n",
+ stream->dev->name);
+ } else {
+ tasklet_init(stream->tasklet[i], uvc_video_complete_tasklet, (unsigned long)urb);
+ }
}
return 0;