| .. | .. |
|---|
| 21 | 21 | #include "uvc_video.h" |
|---|
| 22 | 22 | #include "u_uvc.h" |
|---|
| 23 | 23 | |
|---|
| 24 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
|---|
| 25 | +static bool uvc_using_zero_copy(struct uvc_video *video) |
|---|
| 26 | +{ |
|---|
| 27 | + struct uvc_device *uvc = container_of(video, struct uvc_device, video); |
|---|
| 28 | + struct f_uvc_opts *opts = fi_to_f_uvc_opts(uvc->func.fi); |
|---|
| 29 | + |
|---|
| 30 | + if (opts && opts->uvc_zero_copy && video->fcc != V4L2_PIX_FMT_YUYV) |
|---|
| 31 | + return true; |
|---|
| 32 | + else |
|---|
| 33 | + return false; |
|---|
| 34 | +} |
|---|
| 35 | + |
|---|
| 36 | +static void uvc_wait_req_complete(struct uvc_video *video, struct uvc_request *ureq) |
|---|
| 37 | +{ |
|---|
| 38 | + unsigned long flags; |
|---|
| 39 | + struct usb_request *req; |
|---|
| 40 | + int ret; |
|---|
| 41 | + |
|---|
| 42 | + spin_lock_irqsave(&video->req_lock, flags); |
|---|
| 43 | + |
|---|
| 44 | + list_for_each_entry(req, &video->req_free, list) { |
|---|
| 45 | + if (req == ureq->req) |
|---|
| 46 | + break; |
|---|
| 47 | + } |
|---|
| 48 | + |
|---|
| 49 | + if (req != ureq->req) { |
|---|
| 50 | + reinit_completion(&ureq->req_done); |
|---|
| 51 | + |
|---|
| 52 | + spin_unlock_irqrestore(&video->req_lock, flags); |
|---|
| 53 | + ret = wait_for_completion_timeout(&ureq->req_done, |
|---|
| 54 | + msecs_to_jiffies(500)); |
|---|
| 55 | + if (ret == 0) |
|---|
| 56 | + uvcg_warn(&video->uvc->func, |
|---|
| 57 | + "timed out waiting for req done\n"); |
|---|
| 58 | + return; |
|---|
| 59 | + } |
|---|
| 60 | + |
|---|
| 61 | + spin_unlock_irqrestore(&video->req_lock, flags); |
|---|
| 62 | +} |
|---|
| 63 | +#else |
|---|
| 64 | +static inline bool uvc_using_zero_copy(struct uvc_video *video) |
|---|
| 65 | +{ |
|---|
| 66 | + return false; |
|---|
| 67 | +} |
|---|
| 68 | + |
|---|
| 69 | +static inline void uvc_wait_req_complete(struct uvc_video *video, struct uvc_request *ureq) |
|---|
| 70 | +{ } |
|---|
| 71 | +#endif |
|---|
| 72 | + |
|---|
| 24 | 73 | /* -------------------------------------------------------------------------- |
|---|
| 25 | 74 | * Video codecs |
|---|
| 26 | 75 | */ |
|---|
| .. | .. |
|---|
| 29 | 78 | uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf, |
|---|
| 30 | 79 | u8 *data, int len) |
|---|
| 31 | 80 | { |
|---|
| 81 | + if (uvc_using_zero_copy(video)) { |
|---|
| 82 | + u8 *mem; |
|---|
| 83 | + |
|---|
| 84 | + mem = buf->mem + video->queue.buf_used + |
|---|
| 85 | + (video->queue.buf_used / (video->req_size - 2)) * 2; |
|---|
| 86 | + |
|---|
| 87 | + mem[0] = 2; |
|---|
| 88 | + mem[1] = UVC_STREAM_EOH | video->fid; |
|---|
| 89 | + if (buf->bytesused - video->queue.buf_used <= len - 2) |
|---|
| 90 | + mem[1] |= UVC_STREAM_EOF; |
|---|
| 91 | + |
|---|
| 92 | + return 2; |
|---|
| 93 | + } |
|---|
| 94 | + |
|---|
| 32 | 95 | data[0] = 2; |
|---|
| 33 | 96 | data[1] = UVC_STREAM_EOH | video->fid; |
|---|
| 34 | 97 | |
|---|
| .. | .. |
|---|
| 50 | 113 | mem = buf->mem + queue->buf_used; |
|---|
| 51 | 114 | nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used); |
|---|
| 52 | 115 | |
|---|
| 53 | | - memcpy(data, mem, nbytes); |
|---|
| 116 | + if (!uvc_using_zero_copy(video)) |
|---|
| 117 | + memcpy(data, mem, nbytes); |
|---|
| 54 | 118 | queue->buf_used += nbytes; |
|---|
| 55 | 119 | |
|---|
| 56 | 120 | return nbytes; |
|---|
| .. | .. |
|---|
| 105 | 169 | int len = video->req_size; |
|---|
| 106 | 170 | int ret; |
|---|
| 107 | 171 | |
|---|
| 172 | + if (uvc_using_zero_copy(video)) |
|---|
| 173 | + req->buf = buf->mem + video->queue.buf_used + |
|---|
| 174 | + (video->queue.buf_used / (video->req_size - 2)) * 2; |
|---|
| 175 | + |
|---|
| 108 | 176 | /* Add the header. */ |
|---|
| 109 | 177 | ret = uvc_video_encode_header(video, buf, mem, len); |
|---|
| 110 | 178 | mem += ret; |
|---|
| .. | .. |
|---|
| 134 | 202 | |
|---|
| 135 | 203 | ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); |
|---|
| 136 | 204 | if (ret < 0) { |
|---|
| 137 | | - printk(KERN_INFO "Failed to queue request (%d).\n", ret); |
|---|
| 138 | | - /* Isochronous endpoints can't be halted. */ |
|---|
| 139 | | - if (video->ep->desc && usb_endpoint_xfer_bulk(video->ep->desc)) |
|---|
| 140 | | - usb_ep_set_halt(video->ep); |
|---|
| 205 | + uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n", |
|---|
| 206 | + ret); |
|---|
| 207 | + |
|---|
| 208 | + /* If the endpoint is disabled the descriptor may be NULL. */ |
|---|
| 209 | + if (video->ep->desc) { |
|---|
| 210 | + /* Isochronous endpoints can't be halted. */ |
|---|
| 211 | + if (usb_endpoint_xfer_bulk(video->ep->desc)) |
|---|
| 212 | + usb_ep_set_halt(video->ep); |
|---|
| 213 | + } |
|---|
| 141 | 214 | } |
|---|
| 142 | 215 | |
|---|
| 143 | 216 | return ret; |
|---|
| .. | .. |
|---|
| 146 | 219 | static void |
|---|
| 147 | 220 | uvc_video_complete(struct usb_ep *ep, struct usb_request *req) |
|---|
| 148 | 221 | { |
|---|
| 149 | | - struct uvc_video *video = req->context; |
|---|
| 222 | + struct uvc_request *ureq = req->context; |
|---|
| 223 | + struct uvc_video *video = ureq->video; |
|---|
| 150 | 224 | struct uvc_video_queue *queue = &video->queue; |
|---|
| 225 | + struct uvc_device *uvc = video->uvc; |
|---|
| 151 | 226 | unsigned long flags; |
|---|
| 152 | 227 | |
|---|
| 153 | 228 | switch (req->status) { |
|---|
| .. | .. |
|---|
| 155 | 230 | break; |
|---|
| 156 | 231 | |
|---|
| 157 | 232 | case -ESHUTDOWN: /* disconnect from host. */ |
|---|
| 158 | | - printk(KERN_DEBUG "VS request cancelled.\n"); |
|---|
| 233 | + uvcg_dbg(&video->uvc->func, "VS request cancelled.\n"); |
|---|
| 159 | 234 | uvcg_queue_cancel(queue, 1); |
|---|
| 160 | 235 | break; |
|---|
| 161 | 236 | |
|---|
| 162 | 237 | default: |
|---|
| 163 | | - printk(KERN_INFO "VS request completed with status %d.\n", |
|---|
| 164 | | - req->status); |
|---|
| 238 | + uvcg_warn(&video->uvc->func, |
|---|
| 239 | + "VS request completed with status %d.\n", |
|---|
| 240 | + req->status); |
|---|
| 165 | 241 | uvcg_queue_cancel(queue, 0); |
|---|
| 166 | | - break; |
|---|
| 167 | 242 | } |
|---|
| 168 | 243 | |
|---|
| 169 | 244 | spin_lock_irqsave(&video->req_lock, flags); |
|---|
| 170 | 245 | list_add_tail(&req->list, &video->req_free); |
|---|
| 246 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
|---|
| 247 | + complete(&ureq->req_done); |
|---|
| 248 | +#endif |
|---|
| 171 | 249 | spin_unlock_irqrestore(&video->req_lock, flags); |
|---|
| 172 | 250 | |
|---|
| 173 | | - queue_work(video->async_wq, &video->pump); |
|---|
| 251 | + if (uvc->state == UVC_STATE_STREAMING) |
|---|
| 252 | + schedule_work(&video->pump); |
|---|
| 174 | 253 | } |
|---|
| 175 | 254 | |
|---|
| 176 | 255 | static int |
|---|
| 177 | 256 | uvc_video_free_requests(struct uvc_video *video) |
|---|
| 178 | 257 | { |
|---|
| 179 | 258 | unsigned int i; |
|---|
| 180 | | - struct uvc_device *uvc; |
|---|
| 181 | | - struct f_uvc_opts *opts; |
|---|
| 182 | 259 | |
|---|
| 183 | | - uvc = container_of(video, struct uvc_device, video); |
|---|
| 184 | | - opts = fi_to_f_uvc_opts(uvc->func.fi); |
|---|
| 260 | + if (video->ureq) { |
|---|
| 261 | + for (i = 0; i < video->uvc_num_requests; ++i) { |
|---|
| 262 | + if (video->ureq[i].req) { |
|---|
| 263 | + uvc_wait_req_complete(video, &video->ureq[i]); |
|---|
| 264 | + usb_ep_free_request(video->ep, video->ureq[i].req); |
|---|
| 265 | + video->ureq[i].req = NULL; |
|---|
| 266 | + } |
|---|
| 185 | 267 | |
|---|
| 186 | | - for (i = 0; i < opts->uvc_num_request; ++i) { |
|---|
| 187 | | - if (video->req[i]) { |
|---|
| 188 | | - usb_ep_free_request(video->ep, video->req[i]); |
|---|
| 189 | | - video->req[i] = NULL; |
|---|
| 268 | + if (video->ureq[i].req_buffer) { |
|---|
| 269 | + kfree(video->ureq[i].req_buffer); |
|---|
| 270 | + video->ureq[i].req_buffer = NULL; |
|---|
| 271 | + } |
|---|
| 190 | 272 | } |
|---|
| 191 | 273 | |
|---|
| 192 | | - if (video->req_buffer[i]) { |
|---|
| 193 | | - kfree(video->req_buffer[i]); |
|---|
| 194 | | - video->req_buffer[i] = NULL; |
|---|
| 195 | | - } |
|---|
| 274 | + kfree(video->ureq); |
|---|
| 275 | + video->ureq = NULL; |
|---|
| 196 | 276 | } |
|---|
| 197 | 277 | |
|---|
| 198 | 278 | INIT_LIST_HEAD(&video->req_free); |
|---|
| .. | .. |
|---|
| 206 | 286 | unsigned int req_size; |
|---|
| 207 | 287 | unsigned int i; |
|---|
| 208 | 288 | int ret = -ENOMEM; |
|---|
| 209 | | - struct uvc_device *uvc; |
|---|
| 210 | | - struct f_uvc_opts *opts; |
|---|
| 211 | | - |
|---|
| 212 | | - uvc = container_of(video, struct uvc_device, video); |
|---|
| 213 | | - opts = fi_to_f_uvc_opts(uvc->func.fi); |
|---|
| 214 | 289 | |
|---|
| 215 | 290 | BUG_ON(video->req_size); |
|---|
| 216 | 291 | |
|---|
| .. | .. |
|---|
| 223 | 298 | * max_t(unsigned int, video->ep->maxburst, 1); |
|---|
| 224 | 299 | } |
|---|
| 225 | 300 | |
|---|
| 226 | | - for (i = 0; i < opts->uvc_num_request; ++i) { |
|---|
| 227 | | - video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL); |
|---|
| 228 | | - if (video->req_buffer[i] == NULL) |
|---|
| 301 | + video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL); |
|---|
| 302 | + if (video->ureq == NULL) |
|---|
| 303 | + return -ENOMEM; |
|---|
| 304 | + |
|---|
| 305 | + for (i = 0; i < video->uvc_num_requests; ++i) { |
|---|
| 306 | + video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL); |
|---|
| 307 | + if (video->ureq[i].req_buffer == NULL) |
|---|
| 229 | 308 | goto error; |
|---|
| 230 | 309 | |
|---|
| 231 | | - video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL); |
|---|
| 232 | | - if (video->req[i] == NULL) |
|---|
| 310 | + video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL); |
|---|
| 311 | + if (video->ureq[i].req == NULL) |
|---|
| 233 | 312 | goto error; |
|---|
| 234 | 313 | |
|---|
| 235 | | - video->req[i]->buf = video->req_buffer[i]; |
|---|
| 236 | | - video->req[i]->length = 0; |
|---|
| 237 | | - video->req[i]->complete = uvc_video_complete; |
|---|
| 238 | | - video->req[i]->context = video; |
|---|
| 314 | + video->ureq[i].req->buf = video->ureq[i].req_buffer; |
|---|
| 315 | + video->ureq[i].req->length = 0; |
|---|
| 316 | + video->ureq[i].req->complete = uvc_video_complete; |
|---|
| 317 | + video->ureq[i].req->context = &video->ureq[i]; |
|---|
| 318 | + video->ureq[i].video = video; |
|---|
| 239 | 319 | |
|---|
| 240 | | - list_add_tail(&video->req[i]->list, &video->req_free); |
|---|
| 320 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
|---|
| 321 | + init_completion(&video->ureq[i].req_done); |
|---|
| 322 | +#endif |
|---|
| 323 | + list_add_tail(&video->ureq[i].req->list, &video->req_free); |
|---|
| 241 | 324 | } |
|---|
| 242 | 325 | |
|---|
| 243 | 326 | video->req_size = req_size; |
|---|
| .. | .. |
|---|
| 263 | 346 | { |
|---|
| 264 | 347 | struct uvc_video *video = container_of(work, struct uvc_video, pump); |
|---|
| 265 | 348 | struct uvc_video_queue *queue = &video->queue; |
|---|
| 266 | | - struct usb_request *req; |
|---|
| 349 | + struct usb_request *req = NULL; |
|---|
| 267 | 350 | struct uvc_buffer *buf; |
|---|
| 268 | 351 | unsigned long flags; |
|---|
| 269 | 352 | int ret; |
|---|
| 270 | 353 | |
|---|
| 271 | | - while (1) { |
|---|
| 354 | + while (video->ep->enabled) { |
|---|
| 272 | 355 | /* Retrieve the first available USB request, protected by the |
|---|
| 273 | 356 | * request lock. |
|---|
| 274 | 357 | */ |
|---|
| .. | .. |
|---|
| 302 | 385 | uvcg_queue_cancel(queue, 0); |
|---|
| 303 | 386 | break; |
|---|
| 304 | 387 | } |
|---|
| 388 | + |
|---|
| 389 | + /* Endpoint now owns the request */ |
|---|
| 390 | + req = NULL; |
|---|
| 305 | 391 | } |
|---|
| 392 | + |
|---|
| 393 | + if (!req) |
|---|
| 394 | + return; |
|---|
| 306 | 395 | |
|---|
| 307 | 396 | spin_lock_irqsave(&video->req_lock, flags); |
|---|
| 308 | 397 | list_add_tail(&req->list, &video->req_free); |
|---|
| .. | .. |
|---|
| 321 | 410 | struct f_uvc_opts *opts; |
|---|
| 322 | 411 | |
|---|
| 323 | 412 | if (video->ep == NULL) { |
|---|
| 324 | | - printk(KERN_INFO "Video enable failed, device is " |
|---|
| 325 | | - "uninitialized.\n"); |
|---|
| 413 | + uvcg_info(&video->uvc->func, |
|---|
| 414 | + "Video enable failed, device is uninitialized.\n"); |
|---|
| 326 | 415 | return -ENODEV; |
|---|
| 327 | 416 | } |
|---|
| 328 | 417 | |
|---|
| .. | .. |
|---|
| 332 | 421 | if (!enable) { |
|---|
| 333 | 422 | cancel_work_sync(&video->pump); |
|---|
| 334 | 423 | uvcg_queue_cancel(&video->queue, 0); |
|---|
| 335 | | - for (i = 0; i < opts->uvc_num_request; ++i) |
|---|
| 336 | | - if (video->req[i]) |
|---|
| 337 | | - usb_ep_dequeue(video->ep, video->req[i]); |
|---|
| 424 | + |
|---|
| 425 | + for (i = 0; i < video->uvc_num_requests; ++i) |
|---|
| 426 | + if (video->ureq && video->ureq[i].req) |
|---|
| 427 | + usb_ep_dequeue(video->ep, video->ureq[i].req); |
|---|
| 338 | 428 | |
|---|
| 339 | 429 | uvc_video_free_requests(video); |
|---|
| 340 | 430 | uvcg_queue_enable(&video->queue, 0); |
|---|
| 341 | | - if (pm_qos_request_active(&uvc->pm_qos)) |
|---|
| 342 | | - pm_qos_remove_request(&uvc->pm_qos); |
|---|
| 431 | + if (cpu_latency_qos_request_active(&uvc->pm_qos)) |
|---|
| 432 | + cpu_latency_qos_remove_request(&uvc->pm_qos); |
|---|
| 343 | 433 | return 0; |
|---|
| 344 | 434 | } |
|---|
| 345 | 435 | |
|---|
| 346 | | - pm_qos_add_request(&uvc->pm_qos, PM_QOS_CPU_DMA_LATENCY, |
|---|
| 347 | | - opts->pm_qos_latency); |
|---|
| 436 | + cpu_latency_qos_add_request(&uvc->pm_qos, opts->pm_qos_latency); |
|---|
| 348 | 437 | if ((ret = uvcg_queue_enable(&video->queue, 1)) < 0) |
|---|
| 349 | 438 | return ret; |
|---|
| 350 | 439 | |
|---|
| .. | .. |
|---|
| 357 | 446 | } else |
|---|
| 358 | 447 | video->encode = uvc_video_encode_isoc; |
|---|
| 359 | 448 | |
|---|
| 360 | | - queue_work(video->async_wq, &video->pump); |
|---|
| 449 | + schedule_work(&video->pump); |
|---|
| 361 | 450 | |
|---|
| 362 | 451 | return ret; |
|---|
| 363 | 452 | } |
|---|
| .. | .. |
|---|
| 365 | 454 | /* |
|---|
| 366 | 455 | * Initialize the UVC video stream. |
|---|
| 367 | 456 | */ |
|---|
| 368 | | -int uvcg_video_init(struct uvc_video *video) |
|---|
| 457 | +int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) |
|---|
| 369 | 458 | { |
|---|
| 370 | 459 | INIT_LIST_HEAD(&video->req_free); |
|---|
| 371 | 460 | spin_lock_init(&video->req_lock); |
|---|
| 372 | 461 | INIT_WORK(&video->pump, uvcg_video_pump); |
|---|
| 373 | 462 | |
|---|
| 463 | + video->uvc = uvc; |
|---|
| 374 | 464 | video->fcc = V4L2_PIX_FMT_YUYV; |
|---|
| 375 | 465 | video->bpp = 16; |
|---|
| 376 | 466 | video->width = 320; |
|---|