]>
Commit | Line | Data |
---|---|---|
f3d27f34 | 1 | /* |
63ddf68d | 2 | * Fushicai USBTV007 Audio-Video Grabber Driver |
f3d27f34 LR |
3 | * |
4 | * Product web site: | |
5 | * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html | |
6 | * | |
7 | * Following LWN articles were very useful in construction of this driver: | |
8 | * Video4Linux2 API series: http://lwn.net/Articles/203924/ | |
9 | * videobuf2 API explanation: http://lwn.net/Articles/447435/ | |
10 | * Thanks go to Jonathan Corbet for providing this quality documentation. | |
11 | * He is awesome. | |
12 | * | |
13 | * Copyright (c) 2013 Lubomir Rintel | |
14 | * All rights reserved. | |
15 | * No physical hardware was harmed running Windows during the | |
16 | * reverse-engineering activity | |
17 | * | |
18 | * Redistribution and use in source and binary forms, with or without | |
19 | * modification, are permitted provided that the following conditions | |
20 | * are met: | |
21 | * 1. Redistributions of source code must retain the above copyright | |
22 | * notice, this list of conditions, and the following disclaimer, | |
23 | * without modification. | |
24 | * 2. The name of the author may not be used to endorse or promote products | |
25 | * derived from this software without specific prior written permission. | |
26 | * | |
27 | * Alternatively, this software may be distributed under the terms of the | |
28 | * GNU General Public License ("GPL"). | |
29 | */ | |
30 | ||
f3d27f34 | 31 | #include <media/v4l2-ioctl.h> |
c139990e | 32 | #include <media/videobuf2-v4l2.h> |
a3550ea6 FS |
33 | |
34 | #include "usbtv.h" | |
0e0fe395 GK |
35 | |
36 | static struct usbtv_norm_params norm_params[] = { | |
37 | { | |
38 | .norm = V4L2_STD_525_60, | |
39 | .cap_width = 720, | |
40 | .cap_height = 480, | |
41 | }, | |
42 | { | |
43 | .norm = V4L2_STD_PAL, | |
44 | .cap_width = 720, | |
45 | .cap_height = 576, | |
46 | } | |
47 | }; | |
48 | ||
0e0fe395 GK |
49 | static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) |
50 | { | |
51 | int i, ret = 0; | |
52 | struct usbtv_norm_params *params = NULL; | |
53 | ||
54 | for (i = 0; i < ARRAY_SIZE(norm_params); i++) { | |
55 | if (norm_params[i].norm & norm) { | |
56 | params = &norm_params[i]; | |
57 | break; | |
58 | } | |
59 | } | |
60 | ||
61 | if (params) { | |
62 | usbtv->width = params->cap_width; | |
63 | usbtv->height = params->cap_height; | |
64 | usbtv->n_chunks = usbtv->width * usbtv->height | |
65 | / 4 / USBTV_CHUNK; | |
66 | usbtv->norm = params->norm; | |
67 | } else | |
68 | ret = -EINVAL; | |
69 | ||
70 | return ret; | |
71 | } | |
72 | ||
2206112b LR |
73 | static int usbtv_select_input(struct usbtv *usbtv, int input) |
74 | { | |
75 | int ret; | |
76 | ||
77 | static const u16 composite[][2] = { | |
78 | { USBTV_BASE + 0x0105, 0x0060 }, | |
79 | { USBTV_BASE + 0x011f, 0x00f2 }, | |
80 | { USBTV_BASE + 0x0127, 0x0060 }, | |
81 | { USBTV_BASE + 0x00ae, 0x0010 }, | |
2206112b LR |
82 | { USBTV_BASE + 0x0239, 0x0060 }, |
83 | }; | |
84 | ||
85 | static const u16 svideo[][2] = { | |
86 | { USBTV_BASE + 0x0105, 0x0010 }, | |
87 | { USBTV_BASE + 0x011f, 0x00ff }, | |
88 | { USBTV_BASE + 0x0127, 0x0060 }, | |
89 | { USBTV_BASE + 0x00ae, 0x0030 }, | |
2206112b LR |
90 | { USBTV_BASE + 0x0239, 0x0060 }, |
91 | }; | |
92 | ||
93 | switch (input) { | |
94 | case USBTV_COMPOSITE_INPUT: | |
95 | ret = usbtv_set_regs(usbtv, composite, ARRAY_SIZE(composite)); | |
96 | break; | |
97 | case USBTV_SVIDEO_INPUT: | |
98 | ret = usbtv_set_regs(usbtv, svideo, ARRAY_SIZE(svideo)); | |
99 | break; | |
100 | default: | |
101 | ret = -EINVAL; | |
102 | } | |
103 | ||
104 | if (!ret) | |
105 | usbtv->input = input; | |
106 | ||
107 | return ret; | |
108 | } | |
109 | ||
0e0fe395 GK |
110 | static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm) |
111 | { | |
112 | int ret; | |
113 | static const u16 pal[][2] = { | |
114 | { USBTV_BASE + 0x001a, 0x0068 }, | |
115 | { USBTV_BASE + 0x010e, 0x0072 }, | |
116 | { USBTV_BASE + 0x010f, 0x00a2 }, | |
117 | { USBTV_BASE + 0x0112, 0x00b0 }, | |
118 | { USBTV_BASE + 0x0117, 0x0001 }, | |
119 | { USBTV_BASE + 0x0118, 0x002c }, | |
120 | { USBTV_BASE + 0x012d, 0x0010 }, | |
121 | { USBTV_BASE + 0x012f, 0x0020 }, | |
122 | { USBTV_BASE + 0x024f, 0x0002 }, | |
123 | { USBTV_BASE + 0x0254, 0x0059 }, | |
124 | { USBTV_BASE + 0x025a, 0x0016 }, | |
125 | { USBTV_BASE + 0x025b, 0x0035 }, | |
126 | { USBTV_BASE + 0x0263, 0x0017 }, | |
127 | { USBTV_BASE + 0x0266, 0x0016 }, | |
128 | { USBTV_BASE + 0x0267, 0x0036 } | |
129 | }; | |
130 | ||
131 | static const u16 ntsc[][2] = { | |
132 | { USBTV_BASE + 0x001a, 0x0079 }, | |
133 | { USBTV_BASE + 0x010e, 0x0068 }, | |
134 | { USBTV_BASE + 0x010f, 0x009c }, | |
135 | { USBTV_BASE + 0x0112, 0x00f0 }, | |
136 | { USBTV_BASE + 0x0117, 0x0000 }, | |
137 | { USBTV_BASE + 0x0118, 0x00fc }, | |
138 | { USBTV_BASE + 0x012d, 0x0004 }, | |
139 | { USBTV_BASE + 0x012f, 0x0008 }, | |
140 | { USBTV_BASE + 0x024f, 0x0001 }, | |
141 | { USBTV_BASE + 0x0254, 0x005f }, | |
142 | { USBTV_BASE + 0x025a, 0x0012 }, | |
143 | { USBTV_BASE + 0x025b, 0x0001 }, | |
144 | { USBTV_BASE + 0x0263, 0x001c }, | |
145 | { USBTV_BASE + 0x0266, 0x0011 }, | |
146 | { USBTV_BASE + 0x0267, 0x0005 } | |
147 | }; | |
148 | ||
149 | ret = usbtv_configure_for_norm(usbtv, norm); | |
150 | ||
151 | if (!ret) { | |
152 | if (norm & V4L2_STD_525_60) | |
153 | ret = usbtv_set_regs(usbtv, ntsc, ARRAY_SIZE(ntsc)); | |
154 | else if (norm & V4L2_STD_PAL) | |
155 | ret = usbtv_set_regs(usbtv, pal, ARRAY_SIZE(pal)); | |
156 | } | |
157 | ||
158 | return ret; | |
159 | } | |
160 | ||
2206112b LR |
161 | static int usbtv_setup_capture(struct usbtv *usbtv) |
162 | { | |
163 | int ret; | |
164 | static const u16 setup[][2] = { | |
f3d27f34 LR |
165 | /* These seem to enable the device. */ |
166 | { USBTV_BASE + 0x0008, 0x0001 }, | |
167 | { USBTV_BASE + 0x01d0, 0x00ff }, | |
168 | { USBTV_BASE + 0x01d9, 0x0002 }, | |
169 | ||
170 | /* These seem to influence color parameters, such as | |
171 | * brightness, etc. */ | |
172 | { USBTV_BASE + 0x0239, 0x0040 }, | |
173 | { USBTV_BASE + 0x0240, 0x0000 }, | |
174 | { USBTV_BASE + 0x0241, 0x0000 }, | |
175 | { USBTV_BASE + 0x0242, 0x0002 }, | |
176 | { USBTV_BASE + 0x0243, 0x0080 }, | |
177 | { USBTV_BASE + 0x0244, 0x0012 }, | |
178 | { USBTV_BASE + 0x0245, 0x0090 }, | |
179 | { USBTV_BASE + 0x0246, 0x0000 }, | |
180 | ||
181 | { USBTV_BASE + 0x0278, 0x002d }, | |
182 | { USBTV_BASE + 0x0279, 0x000a }, | |
183 | { USBTV_BASE + 0x027a, 0x0032 }, | |
184 | { 0xf890, 0x000c }, | |
185 | { 0xf894, 0x0086 }, | |
186 | ||
187 | { USBTV_BASE + 0x00ac, 0x00c0 }, | |
188 | { USBTV_BASE + 0x00ad, 0x0000 }, | |
189 | { USBTV_BASE + 0x00a2, 0x0012 }, | |
190 | { USBTV_BASE + 0x00a3, 0x00e0 }, | |
191 | { USBTV_BASE + 0x00a4, 0x0028 }, | |
192 | { USBTV_BASE + 0x00a5, 0x0082 }, | |
193 | { USBTV_BASE + 0x00a7, 0x0080 }, | |
194 | { USBTV_BASE + 0x0000, 0x0014 }, | |
195 | { USBTV_BASE + 0x0006, 0x0003 }, | |
196 | { USBTV_BASE + 0x0090, 0x0099 }, | |
197 | { USBTV_BASE + 0x0091, 0x0090 }, | |
198 | { USBTV_BASE + 0x0094, 0x0068 }, | |
199 | { USBTV_BASE + 0x0095, 0x0070 }, | |
200 | { USBTV_BASE + 0x009c, 0x0030 }, | |
201 | { USBTV_BASE + 0x009d, 0x00c0 }, | |
202 | { USBTV_BASE + 0x009e, 0x00e0 }, | |
203 | { USBTV_BASE + 0x0019, 0x0006 }, | |
204 | { USBTV_BASE + 0x008c, 0x00ba }, | |
205 | { USBTV_BASE + 0x0101, 0x00ff }, | |
206 | { USBTV_BASE + 0x010c, 0x00b3 }, | |
207 | { USBTV_BASE + 0x01b2, 0x0080 }, | |
208 | { USBTV_BASE + 0x01b4, 0x00a0 }, | |
209 | { USBTV_BASE + 0x014c, 0x00ff }, | |
210 | { USBTV_BASE + 0x014d, 0x00ca }, | |
211 | { USBTV_BASE + 0x0113, 0x0053 }, | |
212 | { USBTV_BASE + 0x0119, 0x008a }, | |
213 | { USBTV_BASE + 0x013c, 0x0003 }, | |
214 | { USBTV_BASE + 0x0150, 0x009c }, | |
215 | { USBTV_BASE + 0x0151, 0x0071 }, | |
216 | { USBTV_BASE + 0x0152, 0x00c6 }, | |
217 | { USBTV_BASE + 0x0153, 0x0084 }, | |
218 | { USBTV_BASE + 0x0154, 0x00bc }, | |
219 | { USBTV_BASE + 0x0155, 0x00a0 }, | |
220 | { USBTV_BASE + 0x0156, 0x00a0 }, | |
221 | { USBTV_BASE + 0x0157, 0x009c }, | |
222 | { USBTV_BASE + 0x0158, 0x001f }, | |
223 | { USBTV_BASE + 0x0159, 0x0006 }, | |
224 | { USBTV_BASE + 0x015d, 0x0000 }, | |
225 | ||
f3d27f34 | 226 | { USBTV_BASE + 0x0003, 0x0004 }, |
f3d27f34 | 227 | { USBTV_BASE + 0x0100, 0x00d3 }, |
f3d27f34 | 228 | { USBTV_BASE + 0x0115, 0x0015 }, |
f3d27f34 LR |
229 | { USBTV_BASE + 0x0220, 0x002e }, |
230 | { USBTV_BASE + 0x0225, 0x0008 }, | |
231 | { USBTV_BASE + 0x024e, 0x0002 }, | |
f3d27f34 LR |
232 | { USBTV_BASE + 0x024e, 0x0002 }, |
233 | { USBTV_BASE + 0x024f, 0x0002 }, | |
234 | }; | |
235 | ||
2206112b LR |
236 | ret = usbtv_set_regs(usbtv, setup, ARRAY_SIZE(setup)); |
237 | if (ret) | |
238 | return ret; | |
f3d27f34 | 239 | |
0e0fe395 GK |
240 | ret = usbtv_select_norm(usbtv, usbtv->norm); |
241 | if (ret) | |
242 | return ret; | |
243 | ||
2206112b LR |
244 | ret = usbtv_select_input(usbtv, usbtv->input); |
245 | if (ret) | |
246 | return ret; | |
f3d27f34 LR |
247 | |
248 | return 0; | |
249 | } | |
250 | ||
30800724 LR |
251 | /* Copy data from chunk into a frame buffer, deinterlacing the data |
252 | * into every second line. Unfortunately, they don't align nicely into | |
253 | * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels. | |
254 | * Therefore, we break down the chunk into two halves before copyting, | |
255 | * so that we can interleave a line if needed. */ | |
6fbf4d04 | 256 | static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd) |
30800724 LR |
257 | { |
258 | int half; | |
259 | ||
260 | for (half = 0; half < 2; half++) { | |
261 | int part_no = chunk_no * 2 + half; | |
262 | int line = part_no / 3; | |
263 | int part_index = (line * 2 + !odd) * 3 + (part_no % 3); | |
264 | ||
265 | u32 *dst = &frame[part_index * USBTV_CHUNK/2]; | |
146af9cb | 266 | |
30800724 LR |
267 | memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src)); |
268 | src += USBTV_CHUNK/2; | |
269 | } | |
270 | } | |
271 | ||
f3d27f34 LR |
272 | /* Called for each 256-byte image chunk. |
273 | * First word identifies the chunk, followed by 240 words of image | |
274 | * data and padding. */ | |
6fbf4d04 | 275 | static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk) |
f3d27f34 LR |
276 | { |
277 | int frame_id, odd, chunk_no; | |
278 | u32 *frame; | |
279 | struct usbtv_buf *buf; | |
280 | unsigned long flags; | |
281 | ||
282 | /* Ignore corrupted lines. */ | |
283 | if (!USBTV_MAGIC_OK(chunk)) | |
284 | return; | |
285 | frame_id = USBTV_FRAME_ID(chunk); | |
286 | odd = USBTV_ODD(chunk); | |
287 | chunk_no = USBTV_CHUNK_NO(chunk); | |
0e0fe395 | 288 | if (chunk_no >= usbtv->n_chunks) |
f3d27f34 LR |
289 | return; |
290 | ||
291 | /* Beginning of a frame. */ | |
6ee0faa5 | 292 | if (chunk_no == 0) { |
f3d27f34 | 293 | usbtv->frame_id = frame_id; |
6ee0faa5 LR |
294 | usbtv->chunks_done = 0; |
295 | } | |
296 | ||
297 | if (usbtv->frame_id != frame_id) | |
298 | return; | |
f3d27f34 LR |
299 | |
300 | spin_lock_irqsave(&usbtv->buflock, flags); | |
301 | if (list_empty(&usbtv->bufs)) { | |
302 | /* No free buffers. Userspace likely too slow. */ | |
303 | spin_unlock_irqrestore(&usbtv->buflock, flags); | |
304 | return; | |
305 | } | |
306 | ||
307 | /* First available buffer. */ | |
308 | buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); | |
309 | frame = vb2_plane_vaddr(&buf->vb, 0); | |
310 | ||
30800724 LR |
311 | /* Copy the chunk data. */ |
312 | usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd); | |
6ee0faa5 | 313 | usbtv->chunks_done++; |
f3d27f34 LR |
314 | |
315 | /* Last chunk in a frame, signalling an end */ | |
0e0fe395 | 316 | if (odd && chunk_no == usbtv->n_chunks-1) { |
f3d27f34 | 317 | int size = vb2_plane_size(&buf->vb, 0); |
6ee0faa5 | 318 | enum vb2_buffer_state state = usbtv->chunks_done == |
0e0fe395 | 319 | usbtv->n_chunks ? |
6ee0faa5 LR |
320 | VB2_BUF_STATE_DONE : |
321 | VB2_BUF_STATE_ERROR; | |
f3d27f34 LR |
322 | |
323 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; | |
324 | buf->vb.v4l2_buf.sequence = usbtv->sequence++; | |
325 | v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); | |
326 | vb2_set_plane_payload(&buf->vb, 0, size); | |
6ee0faa5 | 327 | vb2_buffer_done(&buf->vb, state); |
f3d27f34 LR |
328 | list_del(&buf->list); |
329 | } | |
330 | ||
331 | spin_unlock_irqrestore(&usbtv->buflock, flags); | |
332 | } | |
333 | ||
334 | /* Got image data. Each packet contains a number of 256-word chunks we | |
335 | * compose the image from. */ | |
336 | static void usbtv_iso_cb(struct urb *ip) | |
337 | { | |
338 | int ret; | |
339 | int i; | |
340 | struct usbtv *usbtv = (struct usbtv *)ip->context; | |
341 | ||
342 | switch (ip->status) { | |
343 | /* All fine. */ | |
344 | case 0: | |
345 | break; | |
346 | /* Device disconnected or capture stopped? */ | |
347 | case -ENODEV: | |
348 | case -ENOENT: | |
349 | case -ECONNRESET: | |
350 | case -ESHUTDOWN: | |
351 | return; | |
352 | /* Unknown error. Retry. */ | |
353 | default: | |
354 | dev_warn(usbtv->dev, "Bad response for ISO request.\n"); | |
355 | goto resubmit; | |
356 | } | |
357 | ||
358 | for (i = 0; i < ip->number_of_packets; i++) { | |
359 | int size = ip->iso_frame_desc[i].actual_length; | |
360 | unsigned char *data = ip->transfer_buffer + | |
361 | ip->iso_frame_desc[i].offset; | |
362 | int offset; | |
363 | ||
364 | for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++) | |
365 | usbtv_image_chunk(usbtv, | |
6fbf4d04 | 366 | (__be32 *)&data[USBTV_CHUNK_SIZE * offset]); |
f3d27f34 LR |
367 | } |
368 | ||
369 | resubmit: | |
370 | ret = usb_submit_urb(ip, GFP_ATOMIC); | |
371 | if (ret < 0) | |
372 | dev_warn(usbtv->dev, "Could not resubmit ISO URB\n"); | |
373 | } | |
374 | ||
375 | static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv) | |
376 | { | |
377 | struct urb *ip; | |
378 | int size = usbtv->iso_size; | |
379 | int i; | |
380 | ||
381 | ip = usb_alloc_urb(USBTV_ISOC_PACKETS, GFP_KERNEL); | |
382 | if (ip == NULL) | |
383 | return NULL; | |
384 | ||
385 | ip->dev = usbtv->udev; | |
386 | ip->context = usbtv; | |
387 | ip->pipe = usb_rcvisocpipe(usbtv->udev, USBTV_VIDEO_ENDP); | |
388 | ip->interval = 1; | |
389 | ip->transfer_flags = URB_ISO_ASAP; | |
390 | ip->transfer_buffer = kzalloc(size * USBTV_ISOC_PACKETS, | |
391 | GFP_KERNEL); | |
392 | ip->complete = usbtv_iso_cb; | |
393 | ip->number_of_packets = USBTV_ISOC_PACKETS; | |
394 | ip->transfer_buffer_length = size * USBTV_ISOC_PACKETS; | |
395 | for (i = 0; i < USBTV_ISOC_PACKETS; i++) { | |
396 | ip->iso_frame_desc[i].offset = size * i; | |
397 | ip->iso_frame_desc[i].length = size; | |
398 | } | |
399 | ||
400 | return ip; | |
401 | } | |
402 | ||
403 | static void usbtv_stop(struct usbtv *usbtv) | |
404 | { | |
405 | int i; | |
406 | unsigned long flags; | |
407 | ||
408 | /* Cancel running transfers. */ | |
409 | for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { | |
410 | struct urb *ip = usbtv->isoc_urbs[i]; | |
146af9cb | 411 | |
f3d27f34 LR |
412 | if (ip == NULL) |
413 | continue; | |
414 | usb_kill_urb(ip); | |
415 | kfree(ip->transfer_buffer); | |
416 | usb_free_urb(ip); | |
417 | usbtv->isoc_urbs[i] = NULL; | |
418 | } | |
419 | ||
420 | /* Return buffers to userspace. */ | |
421 | spin_lock_irqsave(&usbtv->buflock, flags); | |
422 | while (!list_empty(&usbtv->bufs)) { | |
423 | struct usbtv_buf *buf = list_first_entry(&usbtv->bufs, | |
424 | struct usbtv_buf, list); | |
425 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | |
426 | list_del(&buf->list); | |
427 | } | |
428 | spin_unlock_irqrestore(&usbtv->buflock, flags); | |
429 | } | |
430 | ||
431 | static int usbtv_start(struct usbtv *usbtv) | |
432 | { | |
433 | int i; | |
434 | int ret; | |
435 | ||
63ddf68d FS |
436 | usbtv_audio_suspend(usbtv); |
437 | ||
f3d27f34 LR |
438 | ret = usb_set_interface(usbtv->udev, 0, 0); |
439 | if (ret < 0) | |
440 | return ret; | |
441 | ||
442 | ret = usbtv_setup_capture(usbtv); | |
443 | if (ret < 0) | |
444 | return ret; | |
445 | ||
446 | ret = usb_set_interface(usbtv->udev, 0, 1); | |
447 | if (ret < 0) | |
448 | return ret; | |
449 | ||
63ddf68d FS |
450 | usbtv_audio_resume(usbtv); |
451 | ||
f3d27f34 LR |
452 | for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { |
453 | struct urb *ip; | |
454 | ||
455 | ip = usbtv_setup_iso_transfer(usbtv); | |
456 | if (ip == NULL) { | |
457 | ret = -ENOMEM; | |
458 | goto start_fail; | |
459 | } | |
460 | usbtv->isoc_urbs[i] = ip; | |
461 | ||
462 | ret = usb_submit_urb(ip, GFP_KERNEL); | |
463 | if (ret < 0) | |
464 | goto start_fail; | |
465 | } | |
466 | ||
467 | return 0; | |
468 | ||
469 | start_fail: | |
470 | usbtv_stop(usbtv); | |
471 | return ret; | |
472 | } | |
473 | ||
f3d27f34 LR |
474 | static int usbtv_querycap(struct file *file, void *priv, |
475 | struct v4l2_capability *cap) | |
476 | { | |
477 | struct usbtv *dev = video_drvdata(file); | |
478 | ||
479 | strlcpy(cap->driver, "usbtv", sizeof(cap->driver)); | |
480 | strlcpy(cap->card, "usbtv", sizeof(cap->card)); | |
481 | usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); | |
482 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE; | |
483 | cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; | |
484 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | |
485 | return 0; | |
486 | } | |
487 | ||
488 | static int usbtv_enum_input(struct file *file, void *priv, | |
489 | struct v4l2_input *i) | |
490 | { | |
0e0fe395 GK |
491 | struct usbtv *dev = video_drvdata(file); |
492 | ||
2206112b LR |
493 | switch (i->index) { |
494 | case USBTV_COMPOSITE_INPUT: | |
495 | strlcpy(i->name, "Composite", sizeof(i->name)); | |
496 | break; | |
497 | case USBTV_SVIDEO_INPUT: | |
498 | strlcpy(i->name, "S-Video", sizeof(i->name)); | |
499 | break; | |
500 | default: | |
f3d27f34 | 501 | return -EINVAL; |
2206112b | 502 | } |
f3d27f34 | 503 | |
f3d27f34 | 504 | i->type = V4L2_INPUT_TYPE_CAMERA; |
0e0fe395 | 505 | i->std = dev->vdev.tvnorms; |
f3d27f34 LR |
506 | return 0; |
507 | } | |
508 | ||
509 | static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv, | |
510 | struct v4l2_fmtdesc *f) | |
511 | { | |
512 | if (f->index > 0) | |
513 | return -EINVAL; | |
514 | ||
515 | strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed", | |
516 | sizeof(f->description)); | |
517 | f->pixelformat = V4L2_PIX_FMT_YUYV; | |
518 | return 0; | |
519 | } | |
520 | ||
521 | static int usbtv_fmt_vid_cap(struct file *file, void *priv, | |
522 | struct v4l2_format *f) | |
523 | { | |
0e0fe395 GK |
524 | struct usbtv *usbtv = video_drvdata(file); |
525 | ||
526 | f->fmt.pix.width = usbtv->width; | |
527 | f->fmt.pix.height = usbtv->height; | |
f3d27f34 LR |
528 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; |
529 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | |
0e0fe395 | 530 | f->fmt.pix.bytesperline = usbtv->width * 2; |
f3d27f34 LR |
531 | f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height); |
532 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | |
0e0fe395 | 533 | |
f3d27f34 LR |
534 | return 0; |
535 | } | |
536 | ||
537 | static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm) | |
538 | { | |
0e0fe395 GK |
539 | struct usbtv *usbtv = video_drvdata(file); |
540 | *norm = usbtv->norm; | |
f3d27f34 LR |
541 | return 0; |
542 | } | |
543 | ||
0e0fe395 GK |
544 | static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm) |
545 | { | |
546 | int ret = -EINVAL; | |
547 | struct usbtv *usbtv = video_drvdata(file); | |
548 | ||
549 | if ((norm & V4L2_STD_525_60) || (norm & V4L2_STD_PAL)) | |
550 | ret = usbtv_select_norm(usbtv, norm); | |
551 | ||
552 | return ret; | |
553 | } | |
554 | ||
f3d27f34 LR |
555 | static int usbtv_g_input(struct file *file, void *priv, unsigned int *i) |
556 | { | |
2206112b LR |
557 | struct usbtv *usbtv = video_drvdata(file); |
558 | *i = usbtv->input; | |
f3d27f34 LR |
559 | return 0; |
560 | } | |
561 | ||
562 | static int usbtv_s_input(struct file *file, void *priv, unsigned int i) | |
563 | { | |
2206112b | 564 | struct usbtv *usbtv = video_drvdata(file); |
146af9cb | 565 | |
2206112b | 566 | return usbtv_select_input(usbtv, i); |
f3d27f34 LR |
567 | } |
568 | ||
9b058373 | 569 | static struct v4l2_ioctl_ops usbtv_ioctl_ops = { |
f3d27f34 LR |
570 | .vidioc_querycap = usbtv_querycap, |
571 | .vidioc_enum_input = usbtv_enum_input, | |
572 | .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap, | |
573 | .vidioc_g_fmt_vid_cap = usbtv_fmt_vid_cap, | |
574 | .vidioc_try_fmt_vid_cap = usbtv_fmt_vid_cap, | |
575 | .vidioc_s_fmt_vid_cap = usbtv_fmt_vid_cap, | |
576 | .vidioc_g_std = usbtv_g_std, | |
577 | .vidioc_s_std = usbtv_s_std, | |
578 | .vidioc_g_input = usbtv_g_input, | |
579 | .vidioc_s_input = usbtv_s_input, | |
580 | ||
581 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
582 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | |
583 | .vidioc_querybuf = vb2_ioctl_querybuf, | |
584 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
585 | .vidioc_qbuf = vb2_ioctl_qbuf, | |
586 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
587 | .vidioc_streamon = vb2_ioctl_streamon, | |
588 | .vidioc_streamoff = vb2_ioctl_streamoff, | |
589 | }; | |
590 | ||
9b058373 | 591 | static struct v4l2_file_operations usbtv_fops = { |
f3d27f34 LR |
592 | .owner = THIS_MODULE, |
593 | .unlocked_ioctl = video_ioctl2, | |
594 | .mmap = vb2_fop_mmap, | |
595 | .open = v4l2_fh_open, | |
596 | .release = vb2_fop_release, | |
597 | .read = vb2_fop_read, | |
598 | .poll = vb2_fop_poll, | |
599 | }; | |
600 | ||
601 | static int usbtv_queue_setup(struct vb2_queue *vq, | |
a988410a | 602 | const struct v4l2_format *fmt, unsigned int *nbuffers, |
f3d27f34 LR |
603 | unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) |
604 | { | |
0e0fe395 | 605 | struct usbtv *usbtv = vb2_get_drv_priv(vq); |
a988410a | 606 | unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); |
0e0fe395 | 607 | |
a988410a HV |
608 | if (vq->num_buffers + *nbuffers < 2) |
609 | *nbuffers = 2 - vq->num_buffers; | |
f3d27f34 | 610 | *nplanes = 1; |
a988410a HV |
611 | if (fmt && fmt->fmt.pix.sizeimage < size) |
612 | return -EINVAL; | |
613 | sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; | |
f3d27f34 LR |
614 | |
615 | return 0; | |
616 | } | |
617 | ||
618 | static void usbtv_buf_queue(struct vb2_buffer *vb) | |
619 | { | |
620 | struct usbtv *usbtv = vb2_get_drv_priv(vb->vb2_queue); | |
621 | struct usbtv_buf *buf = container_of(vb, struct usbtv_buf, vb); | |
622 | unsigned long flags; | |
623 | ||
624 | if (usbtv->udev == NULL) { | |
625 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | |
626 | return; | |
627 | } | |
628 | ||
629 | spin_lock_irqsave(&usbtv->buflock, flags); | |
630 | list_add_tail(&buf->list, &usbtv->bufs); | |
631 | spin_unlock_irqrestore(&usbtv->buflock, flags); | |
632 | } | |
633 | ||
634 | static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count) | |
635 | { | |
636 | struct usbtv *usbtv = vb2_get_drv_priv(vq); | |
637 | ||
638 | if (usbtv->udev == NULL) | |
639 | return -ENODEV; | |
640 | ||
a988410a | 641 | usbtv->sequence = 0; |
f3d27f34 LR |
642 | return usbtv_start(usbtv); |
643 | } | |
644 | ||
e37559b2 | 645 | static void usbtv_stop_streaming(struct vb2_queue *vq) |
f3d27f34 LR |
646 | { |
647 | struct usbtv *usbtv = vb2_get_drv_priv(vq); | |
648 | ||
e37559b2 HV |
649 | if (usbtv->udev) |
650 | usbtv_stop(usbtv); | |
f3d27f34 LR |
651 | } |
652 | ||
9b058373 | 653 | static struct vb2_ops usbtv_vb2_ops = { |
f3d27f34 LR |
654 | .queue_setup = usbtv_queue_setup, |
655 | .buf_queue = usbtv_buf_queue, | |
656 | .start_streaming = usbtv_start_streaming, | |
657 | .stop_streaming = usbtv_stop_streaming, | |
658 | }; | |
659 | ||
660 | static void usbtv_release(struct v4l2_device *v4l2_dev) | |
661 | { | |
662 | struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev); | |
663 | ||
664 | v4l2_device_unregister(&usbtv->v4l2_dev); | |
665 | vb2_queue_release(&usbtv->vb2q); | |
666 | kfree(usbtv); | |
667 | } | |
668 | ||
a3550ea6 | 669 | int usbtv_video_init(struct usbtv *usbtv) |
f3d27f34 LR |
670 | { |
671 | int ret; | |
0e0fe395 GK |
672 | |
673 | (void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60); | |
674 | ||
f3d27f34 LR |
675 | spin_lock_init(&usbtv->buflock); |
676 | mutex_init(&usbtv->v4l2_lock); | |
677 | mutex_init(&usbtv->vb2q_lock); | |
678 | INIT_LIST_HEAD(&usbtv->bufs); | |
679 | ||
680 | /* videobuf2 structure */ | |
681 | usbtv->vb2q.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
682 | usbtv->vb2q.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | |
683 | usbtv->vb2q.drv_priv = usbtv; | |
684 | usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf); | |
685 | usbtv->vb2q.ops = &usbtv_vb2_ops; | |
686 | usbtv->vb2q.mem_ops = &vb2_vmalloc_memops; | |
ade48681 | 687 | usbtv->vb2q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
f3d27f34 LR |
688 | usbtv->vb2q.lock = &usbtv->vb2q_lock; |
689 | ret = vb2_queue_init(&usbtv->vb2q); | |
690 | if (ret < 0) { | |
a3550ea6 FS |
691 | dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n"); |
692 | return ret; | |
f3d27f34 LR |
693 | } |
694 | ||
695 | /* v4l2 structure */ | |
696 | usbtv->v4l2_dev.release = usbtv_release; | |
a3550ea6 | 697 | ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev); |
f3d27f34 | 698 | if (ret < 0) { |
a3550ea6 | 699 | dev_warn(usbtv->dev, "Could not register v4l2 device\n"); |
f3d27f34 LR |
700 | goto v4l2_fail; |
701 | } | |
702 | ||
f3d27f34 LR |
703 | /* Video structure */ |
704 | strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name)); | |
705 | usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev; | |
706 | usbtv->vdev.release = video_device_release_empty; | |
707 | usbtv->vdev.fops = &usbtv_fops; | |
708 | usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops; | |
0e0fe395 | 709 | usbtv->vdev.tvnorms = USBTV_TV_STD; |
f3d27f34 LR |
710 | usbtv->vdev.queue = &usbtv->vb2q; |
711 | usbtv->vdev.lock = &usbtv->v4l2_lock; | |
f3d27f34 LR |
712 | video_set_drvdata(&usbtv->vdev, usbtv); |
713 | ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); | |
714 | if (ret < 0) { | |
a3550ea6 | 715 | dev_warn(usbtv->dev, "Could not register video device\n"); |
f3d27f34 LR |
716 | goto vdev_fail; |
717 | } | |
718 | ||
f3d27f34 LR |
719 | return 0; |
720 | ||
721 | vdev_fail: | |
722 | v4l2_device_unregister(&usbtv->v4l2_dev); | |
723 | v4l2_fail: | |
724 | vb2_queue_release(&usbtv->vb2q); | |
f3d27f34 LR |
725 | |
726 | return ret; | |
727 | } | |
728 | ||
a3550ea6 | 729 | void usbtv_video_free(struct usbtv *usbtv) |
f3d27f34 | 730 | { |
f3d27f34 LR |
731 | mutex_lock(&usbtv->vb2q_lock); |
732 | mutex_lock(&usbtv->v4l2_lock); | |
733 | ||
734 | usbtv_stop(usbtv); | |
f3d27f34 LR |
735 | video_unregister_device(&usbtv->vdev); |
736 | v4l2_device_disconnect(&usbtv->v4l2_dev); | |
f3d27f34 LR |
737 | |
738 | mutex_unlock(&usbtv->v4l2_lock); | |
739 | mutex_unlock(&usbtv->vb2q_lock); | |
740 | ||
741 | v4l2_device_put(&usbtv->v4l2_dev); | |
742 | } |