.. | .. |
---|
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 | + queue_work(video->async_wq, &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 | |
---|
.. | .. |
---|
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 | + /* Allocate a work queue for asynchronous video pump handler. */ |
---|
| 464 | + video->async_wq = alloc_workqueue("uvcgadget", WQ_UNBOUND | WQ_HIGHPRI, 0); |
---|
| 465 | + if (!video->async_wq) |
---|
| 466 | + return -EINVAL; |
---|
| 467 | + |
---|
| 468 | + video->uvc = uvc; |
---|
374 | 469 | video->fcc = V4L2_PIX_FMT_YUYV; |
---|
375 | 470 | video->bpp = 16; |
---|
376 | 471 | video->width = 320; |
---|