diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2013-06-17 09:29:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-06-21 10:32:35 -0400 |
commit | f3d27f34fdd7701e499617d2c1d94480a98f6d07 (patch) | |
tree | 8bb0303f301212e21ba21bc9f4aadcd8bf1d8d28 /drivers/media/usb/usbtv | |
parent | 8fc350abc64f26f84c7f6af40e535edb754f942d (diff) |
[media] usbtv: Add driver for Fushicai USBTV007 video frame grabber
Reverse-engineered driver for cheapo video digitizer, made from observations of
Windows XP driver. The protocol is not yet completely understood, so far we
don't provide any controls, only support a single format out of three and don't
support the audio device.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/usbtv')
-rw-r--r-- | drivers/media/usb/usbtv/Kconfig | 10 | ||||
-rw-r--r-- | drivers/media/usb/usbtv/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/usb/usbtv/usbtv.c | 696 |
3 files changed, 707 insertions, 0 deletions
diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig new file mode 100644 index 000000000000..8864436464bf --- /dev/null +++ b/drivers/media/usb/usbtv/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | config VIDEO_USBTV | ||
2 | tristate "USBTV007 video capture support" | ||
3 | depends on VIDEO_DEV | ||
4 | select VIDEOBUF2_VMALLOC | ||
5 | |||
6 | ---help--- | ||
7 | This is a video4linux2 driver for USBTV007 based video capture devices. | ||
8 | |||
9 | To compile this driver as a module, choose M here: the | ||
10 | module will be called usbtv | ||
diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile new file mode 100644 index 000000000000..28b872fa94e1 --- /dev/null +++ b/drivers/media/usb/usbtv/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_VIDEO_USBTV) += usbtv.o | |||
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c new file mode 100644 index 000000000000..bf43f874685e --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv.c | |||
@@ -0,0 +1,696 @@ | |||
1 | /* | ||
2 | * Fushicai USBTV007 Video Grabber Driver | ||
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 | |||
31 | #include <linux/init.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/usb.h> | ||
36 | #include <linux/version.h> | ||
37 | #include <linux/videodev2.h> | ||
38 | |||
39 | #include <media/v4l2-device.h> | ||
40 | #include <media/v4l2-ioctl.h> | ||
41 | #include <media/videobuf2-core.h> | ||
42 | #include <media/videobuf2-vmalloc.h> | ||
43 | |||
44 | /* Hardware. */ | ||
45 | #define USBTV_VIDEO_ENDP 0x81 | ||
46 | #define USBTV_BASE 0xc000 | ||
47 | #define USBTV_REQUEST_REG 12 | ||
48 | |||
49 | /* Number of concurrent isochronous urbs submitted. | ||
50 | * Higher numbers was seen to overly saturate the USB bus. */ | ||
51 | #define USBTV_ISOC_TRANSFERS 16 | ||
52 | #define USBTV_ISOC_PACKETS 8 | ||
53 | |||
54 | #define USBTV_WIDTH 720 | ||
55 | #define USBTV_HEIGHT 480 | ||
56 | |||
57 | #define USBTV_CHUNK_SIZE 256 | ||
58 | #define USBTV_CHUNK 240 | ||
59 | #define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ | ||
60 | / 2 / USBTV_CHUNK) | ||
61 | |||
62 | /* Chunk header. */ | ||
63 | #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ | ||
64 | == 0x88000000) | ||
65 | #define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16) | ||
66 | #define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15) | ||
67 | #define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff) | ||
68 | |||
69 | /* A single videobuf2 frame buffer. */ | ||
70 | struct usbtv_buf { | ||
71 | struct vb2_buffer vb; | ||
72 | struct list_head list; | ||
73 | }; | ||
74 | |||
75 | /* Per-device structure. */ | ||
76 | struct usbtv { | ||
77 | struct device *dev; | ||
78 | struct usb_device *udev; | ||
79 | struct v4l2_device v4l2_dev; | ||
80 | struct video_device vdev; | ||
81 | struct vb2_queue vb2q; | ||
82 | struct mutex v4l2_lock; | ||
83 | struct mutex vb2q_lock; | ||
84 | |||
85 | /* List of videobuf2 buffers protected by a lock. */ | ||
86 | spinlock_t buflock; | ||
87 | struct list_head bufs; | ||
88 | |||
89 | /* Number of currently processed frame, useful find | ||
90 | * out when a new one begins. */ | ||
91 | u32 frame_id; | ||
92 | |||
93 | int iso_size; | ||
94 | unsigned int sequence; | ||
95 | struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; | ||
96 | }; | ||
97 | |||
98 | static int usbtv_setup_capture(struct usbtv *usbtv) | ||
99 | { | ||
100 | int ret; | ||
101 | int pipe = usb_rcvctrlpipe(usbtv->udev, 0); | ||
102 | int i; | ||
103 | static const u16 protoregs[][2] = { | ||
104 | /* These seem to enable the device. */ | ||
105 | { USBTV_BASE + 0x0008, 0x0001 }, | ||
106 | { USBTV_BASE + 0x01d0, 0x00ff }, | ||
107 | { USBTV_BASE + 0x01d9, 0x0002 }, | ||
108 | |||
109 | /* These seem to influence color parameters, such as | ||
110 | * brightness, etc. */ | ||
111 | { USBTV_BASE + 0x0239, 0x0040 }, | ||
112 | { USBTV_BASE + 0x0240, 0x0000 }, | ||
113 | { USBTV_BASE + 0x0241, 0x0000 }, | ||
114 | { USBTV_BASE + 0x0242, 0x0002 }, | ||
115 | { USBTV_BASE + 0x0243, 0x0080 }, | ||
116 | { USBTV_BASE + 0x0244, 0x0012 }, | ||
117 | { USBTV_BASE + 0x0245, 0x0090 }, | ||
118 | { USBTV_BASE + 0x0246, 0x0000 }, | ||
119 | |||
120 | { USBTV_BASE + 0x0278, 0x002d }, | ||
121 | { USBTV_BASE + 0x0279, 0x000a }, | ||
122 | { USBTV_BASE + 0x027a, 0x0032 }, | ||
123 | { 0xf890, 0x000c }, | ||
124 | { 0xf894, 0x0086 }, | ||
125 | |||
126 | { USBTV_BASE + 0x00ac, 0x00c0 }, | ||
127 | { USBTV_BASE + 0x00ad, 0x0000 }, | ||
128 | { USBTV_BASE + 0x00a2, 0x0012 }, | ||
129 | { USBTV_BASE + 0x00a3, 0x00e0 }, | ||
130 | { USBTV_BASE + 0x00a4, 0x0028 }, | ||
131 | { USBTV_BASE + 0x00a5, 0x0082 }, | ||
132 | { USBTV_BASE + 0x00a7, 0x0080 }, | ||
133 | { USBTV_BASE + 0x0000, 0x0014 }, | ||
134 | { USBTV_BASE + 0x0006, 0x0003 }, | ||
135 | { USBTV_BASE + 0x0090, 0x0099 }, | ||
136 | { USBTV_BASE + 0x0091, 0x0090 }, | ||
137 | { USBTV_BASE + 0x0094, 0x0068 }, | ||
138 | { USBTV_BASE + 0x0095, 0x0070 }, | ||
139 | { USBTV_BASE + 0x009c, 0x0030 }, | ||
140 | { USBTV_BASE + 0x009d, 0x00c0 }, | ||
141 | { USBTV_BASE + 0x009e, 0x00e0 }, | ||
142 | { USBTV_BASE + 0x0019, 0x0006 }, | ||
143 | { USBTV_BASE + 0x008c, 0x00ba }, | ||
144 | { USBTV_BASE + 0x0101, 0x00ff }, | ||
145 | { USBTV_BASE + 0x010c, 0x00b3 }, | ||
146 | { USBTV_BASE + 0x01b2, 0x0080 }, | ||
147 | { USBTV_BASE + 0x01b4, 0x00a0 }, | ||
148 | { USBTV_BASE + 0x014c, 0x00ff }, | ||
149 | { USBTV_BASE + 0x014d, 0x00ca }, | ||
150 | { USBTV_BASE + 0x0113, 0x0053 }, | ||
151 | { USBTV_BASE + 0x0119, 0x008a }, | ||
152 | { USBTV_BASE + 0x013c, 0x0003 }, | ||
153 | { USBTV_BASE + 0x0150, 0x009c }, | ||
154 | { USBTV_BASE + 0x0151, 0x0071 }, | ||
155 | { USBTV_BASE + 0x0152, 0x00c6 }, | ||
156 | { USBTV_BASE + 0x0153, 0x0084 }, | ||
157 | { USBTV_BASE + 0x0154, 0x00bc }, | ||
158 | { USBTV_BASE + 0x0155, 0x00a0 }, | ||
159 | { USBTV_BASE + 0x0156, 0x00a0 }, | ||
160 | { USBTV_BASE + 0x0157, 0x009c }, | ||
161 | { USBTV_BASE + 0x0158, 0x001f }, | ||
162 | { USBTV_BASE + 0x0159, 0x0006 }, | ||
163 | { USBTV_BASE + 0x015d, 0x0000 }, | ||
164 | |||
165 | { USBTV_BASE + 0x0284, 0x0088 }, | ||
166 | { USBTV_BASE + 0x0003, 0x0004 }, | ||
167 | { USBTV_BASE + 0x001a, 0x0079 }, | ||
168 | { USBTV_BASE + 0x0100, 0x00d3 }, | ||
169 | { USBTV_BASE + 0x010e, 0x0068 }, | ||
170 | { USBTV_BASE + 0x010f, 0x009c }, | ||
171 | { USBTV_BASE + 0x0112, 0x00f0 }, | ||
172 | { USBTV_BASE + 0x0115, 0x0015 }, | ||
173 | { USBTV_BASE + 0x0117, 0x0000 }, | ||
174 | { USBTV_BASE + 0x0118, 0x00fc }, | ||
175 | { USBTV_BASE + 0x012d, 0x0004 }, | ||
176 | { USBTV_BASE + 0x012f, 0x0008 }, | ||
177 | { USBTV_BASE + 0x0220, 0x002e }, | ||
178 | { USBTV_BASE + 0x0225, 0x0008 }, | ||
179 | { USBTV_BASE + 0x024e, 0x0002 }, | ||
180 | { USBTV_BASE + 0x024f, 0x0001 }, | ||
181 | { USBTV_BASE + 0x0254, 0x005f }, | ||
182 | { USBTV_BASE + 0x025a, 0x0012 }, | ||
183 | { USBTV_BASE + 0x025b, 0x0001 }, | ||
184 | { USBTV_BASE + 0x0263, 0x001c }, | ||
185 | { USBTV_BASE + 0x0266, 0x0011 }, | ||
186 | { USBTV_BASE + 0x0267, 0x0005 }, | ||
187 | { USBTV_BASE + 0x024e, 0x0002 }, | ||
188 | { USBTV_BASE + 0x024f, 0x0002 }, | ||
189 | }; | ||
190 | |||
191 | for (i = 0; i < ARRAY_SIZE(protoregs); i++) { | ||
192 | u16 index = protoregs[i][0]; | ||
193 | u16 value = protoregs[i][1]; | ||
194 | |||
195 | ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, | ||
196 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
197 | value, index, NULL, 0, 0); | ||
198 | if (ret < 0) | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /* Called for each 256-byte image chunk. | ||
206 | * First word identifies the chunk, followed by 240 words of image | ||
207 | * data and padding. */ | ||
208 | static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) | ||
209 | { | ||
210 | int frame_id, odd, chunk_no; | ||
211 | u32 *frame; | ||
212 | struct usbtv_buf *buf; | ||
213 | unsigned long flags; | ||
214 | |||
215 | /* Ignore corrupted lines. */ | ||
216 | if (!USBTV_MAGIC_OK(chunk)) | ||
217 | return; | ||
218 | frame_id = USBTV_FRAME_ID(chunk); | ||
219 | odd = USBTV_ODD(chunk); | ||
220 | chunk_no = USBTV_CHUNK_NO(chunk); | ||
221 | |||
222 | /* Deinterlace. TODO: Use interlaced frame format. */ | ||
223 | chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3; | ||
224 | chunk_no += !odd * 3; | ||
225 | |||
226 | if (chunk_no >= USBTV_CHUNKS) | ||
227 | return; | ||
228 | |||
229 | /* Beginning of a frame. */ | ||
230 | if (chunk_no == 0) | ||
231 | usbtv->frame_id = frame_id; | ||
232 | |||
233 | spin_lock_irqsave(&usbtv->buflock, flags); | ||
234 | if (list_empty(&usbtv->bufs)) { | ||
235 | /* No free buffers. Userspace likely too slow. */ | ||
236 | spin_unlock_irqrestore(&usbtv->buflock, flags); | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | /* First available buffer. */ | ||
241 | buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); | ||
242 | frame = vb2_plane_vaddr(&buf->vb, 0); | ||
243 | |||
244 | /* Copy the chunk. */ | ||
245 | memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1], | ||
246 | USBTV_CHUNK * sizeof(chunk[1])); | ||
247 | |||
248 | /* Last chunk in a frame, signalling an end */ | ||
249 | if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) { | ||
250 | int size = vb2_plane_size(&buf->vb, 0); | ||
251 | |||
252 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; | ||
253 | buf->vb.v4l2_buf.sequence = usbtv->sequence++; | ||
254 | v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); | ||
255 | vb2_set_plane_payload(&buf->vb, 0, size); | ||
256 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); | ||
257 | list_del(&buf->list); | ||
258 | } | ||
259 | |||
260 | spin_unlock_irqrestore(&usbtv->buflock, flags); | ||
261 | } | ||
262 | |||
263 | /* Got image data. Each packet contains a number of 256-word chunks we | ||
264 | * compose the image from. */ | ||
265 | static void usbtv_iso_cb(struct urb *ip) | ||
266 | { | ||
267 | int ret; | ||
268 | int i; | ||
269 | struct usbtv *usbtv = (struct usbtv *)ip->context; | ||
270 | |||
271 | switch (ip->status) { | ||
272 | /* All fine. */ | ||
273 | case 0: | ||
274 | break; | ||
275 | /* Device disconnected or capture stopped? */ | ||
276 | case -ENODEV: | ||
277 | case -ENOENT: | ||
278 | case -ECONNRESET: | ||
279 | case -ESHUTDOWN: | ||
280 | return; | ||
281 | /* Unknown error. Retry. */ | ||
282 | default: | ||
283 | dev_warn(usbtv->dev, "Bad response for ISO request.\n"); | ||
284 | goto resubmit; | ||
285 | } | ||
286 | |||
287 | for (i = 0; i < ip->number_of_packets; i++) { | ||
288 | int size = ip->iso_frame_desc[i].actual_length; | ||
289 | unsigned char *data = ip->transfer_buffer + | ||
290 | ip->iso_frame_desc[i].offset; | ||
291 | int offset; | ||
292 | |||
293 | for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++) | ||
294 | usbtv_image_chunk(usbtv, | ||
295 | (u32 *)&data[USBTV_CHUNK_SIZE * offset]); | ||
296 | } | ||
297 | |||
298 | resubmit: | ||
299 | ret = usb_submit_urb(ip, GFP_ATOMIC); | ||
300 | if (ret < 0) | ||
301 | dev_warn(usbtv->dev, "Could not resubmit ISO URB\n"); | ||
302 | } | ||
303 | |||
304 | static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv) | ||
305 | { | ||
306 | struct urb *ip; | ||
307 | int size = usbtv->iso_size; | ||
308 | int i; | ||
309 | |||
310 | ip = usb_alloc_urb(USBTV_ISOC_PACKETS, GFP_KERNEL); | ||
311 | if (ip == NULL) | ||
312 | return NULL; | ||
313 | |||
314 | ip->dev = usbtv->udev; | ||
315 | ip->context = usbtv; | ||
316 | ip->pipe = usb_rcvisocpipe(usbtv->udev, USBTV_VIDEO_ENDP); | ||
317 | ip->interval = 1; | ||
318 | ip->transfer_flags = URB_ISO_ASAP; | ||
319 | ip->transfer_buffer = kzalloc(size * USBTV_ISOC_PACKETS, | ||
320 | GFP_KERNEL); | ||
321 | ip->complete = usbtv_iso_cb; | ||
322 | ip->number_of_packets = USBTV_ISOC_PACKETS; | ||
323 | ip->transfer_buffer_length = size * USBTV_ISOC_PACKETS; | ||
324 | for (i = 0; i < USBTV_ISOC_PACKETS; i++) { | ||
325 | ip->iso_frame_desc[i].offset = size * i; | ||
326 | ip->iso_frame_desc[i].length = size; | ||
327 | } | ||
328 | |||
329 | return ip; | ||
330 | } | ||
331 | |||
332 | static void usbtv_stop(struct usbtv *usbtv) | ||
333 | { | ||
334 | int i; | ||
335 | unsigned long flags; | ||
336 | |||
337 | /* Cancel running transfers. */ | ||
338 | for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { | ||
339 | struct urb *ip = usbtv->isoc_urbs[i]; | ||
340 | if (ip == NULL) | ||
341 | continue; | ||
342 | usb_kill_urb(ip); | ||
343 | kfree(ip->transfer_buffer); | ||
344 | usb_free_urb(ip); | ||
345 | usbtv->isoc_urbs[i] = NULL; | ||
346 | } | ||
347 | |||
348 | /* Return buffers to userspace. */ | ||
349 | spin_lock_irqsave(&usbtv->buflock, flags); | ||
350 | while (!list_empty(&usbtv->bufs)) { | ||
351 | struct usbtv_buf *buf = list_first_entry(&usbtv->bufs, | ||
352 | struct usbtv_buf, list); | ||
353 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
354 | list_del(&buf->list); | ||
355 | } | ||
356 | spin_unlock_irqrestore(&usbtv->buflock, flags); | ||
357 | } | ||
358 | |||
359 | static int usbtv_start(struct usbtv *usbtv) | ||
360 | { | ||
361 | int i; | ||
362 | int ret; | ||
363 | |||
364 | ret = usb_set_interface(usbtv->udev, 0, 0); | ||
365 | if (ret < 0) | ||
366 | return ret; | ||
367 | |||
368 | ret = usbtv_setup_capture(usbtv); | ||
369 | if (ret < 0) | ||
370 | return ret; | ||
371 | |||
372 | ret = usb_set_interface(usbtv->udev, 0, 1); | ||
373 | if (ret < 0) | ||
374 | return ret; | ||
375 | |||
376 | for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { | ||
377 | struct urb *ip; | ||
378 | |||
379 | ip = usbtv_setup_iso_transfer(usbtv); | ||
380 | if (ip == NULL) { | ||
381 | ret = -ENOMEM; | ||
382 | goto start_fail; | ||
383 | } | ||
384 | usbtv->isoc_urbs[i] = ip; | ||
385 | |||
386 | ret = usb_submit_urb(ip, GFP_KERNEL); | ||
387 | if (ret < 0) | ||
388 | goto start_fail; | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | |||
393 | start_fail: | ||
394 | usbtv_stop(usbtv); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | struct usb_device_id usbtv_id_table[] = { | ||
399 | { USB_DEVICE(0x1b71, 0x3002) }, | ||
400 | {} | ||
401 | }; | ||
402 | MODULE_DEVICE_TABLE(usb, usbtv_id_table); | ||
403 | |||
404 | static int usbtv_querycap(struct file *file, void *priv, | ||
405 | struct v4l2_capability *cap) | ||
406 | { | ||
407 | struct usbtv *dev = video_drvdata(file); | ||
408 | |||
409 | strlcpy(cap->driver, "usbtv", sizeof(cap->driver)); | ||
410 | strlcpy(cap->card, "usbtv", sizeof(cap->card)); | ||
411 | usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); | ||
412 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE; | ||
413 | cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; | ||
414 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int usbtv_enum_input(struct file *file, void *priv, | ||
419 | struct v4l2_input *i) | ||
420 | { | ||
421 | if (i->index > 0) | ||
422 | return -EINVAL; | ||
423 | |||
424 | strlcpy(i->name, "Composite", sizeof(i->name)); | ||
425 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
426 | i->std = V4L2_STD_525_60; | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv, | ||
431 | struct v4l2_fmtdesc *f) | ||
432 | { | ||
433 | if (f->index > 0) | ||
434 | return -EINVAL; | ||
435 | |||
436 | strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed", | ||
437 | sizeof(f->description)); | ||
438 | f->pixelformat = V4L2_PIX_FMT_YUYV; | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int usbtv_fmt_vid_cap(struct file *file, void *priv, | ||
443 | struct v4l2_format *f) | ||
444 | { | ||
445 | f->fmt.pix.width = USBTV_WIDTH; | ||
446 | f->fmt.pix.height = USBTV_HEIGHT; | ||
447 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; | ||
448 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
449 | f->fmt.pix.bytesperline = USBTV_WIDTH * 2; | ||
450 | f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height); | ||
451 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
452 | f->fmt.pix.priv = 0; | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm) | ||
457 | { | ||
458 | *norm = V4L2_STD_525_60; | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int usbtv_g_input(struct file *file, void *priv, unsigned int *i) | ||
463 | { | ||
464 | *i = 0; | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int usbtv_s_input(struct file *file, void *priv, unsigned int i) | ||
469 | { | ||
470 | if (i > 0) | ||
471 | return -EINVAL; | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm) | ||
476 | { | ||
477 | if (norm & V4L2_STD_525_60) | ||
478 | return 0; | ||
479 | return -EINVAL; | ||
480 | } | ||
481 | |||
482 | struct v4l2_ioctl_ops usbtv_ioctl_ops = { | ||
483 | .vidioc_querycap = usbtv_querycap, | ||
484 | .vidioc_enum_input = usbtv_enum_input, | ||
485 | .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap, | ||
486 | .vidioc_g_fmt_vid_cap = usbtv_fmt_vid_cap, | ||
487 | .vidioc_try_fmt_vid_cap = usbtv_fmt_vid_cap, | ||
488 | .vidioc_s_fmt_vid_cap = usbtv_fmt_vid_cap, | ||
489 | .vidioc_g_std = usbtv_g_std, | ||
490 | .vidioc_s_std = usbtv_s_std, | ||
491 | .vidioc_g_input = usbtv_g_input, | ||
492 | .vidioc_s_input = usbtv_s_input, | ||
493 | |||
494 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
495 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
496 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
497 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
498 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
499 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
500 | .vidioc_streamon = vb2_ioctl_streamon, | ||
501 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
502 | }; | ||
503 | |||
504 | struct v4l2_file_operations usbtv_fops = { | ||
505 | .owner = THIS_MODULE, | ||
506 | .unlocked_ioctl = video_ioctl2, | ||
507 | .mmap = vb2_fop_mmap, | ||
508 | .open = v4l2_fh_open, | ||
509 | .release = vb2_fop_release, | ||
510 | .read = vb2_fop_read, | ||
511 | .poll = vb2_fop_poll, | ||
512 | }; | ||
513 | |||
514 | static int usbtv_queue_setup(struct vb2_queue *vq, | ||
515 | const struct v4l2_format *v4l_fmt, unsigned int *nbuffers, | ||
516 | unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) | ||
517 | { | ||
518 | if (*nbuffers < 2) | ||
519 | *nbuffers = 2; | ||
520 | *nplanes = 1; | ||
521 | sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32); | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static void usbtv_buf_queue(struct vb2_buffer *vb) | ||
527 | { | ||
528 | struct usbtv *usbtv = vb2_get_drv_priv(vb->vb2_queue); | ||
529 | struct usbtv_buf *buf = container_of(vb, struct usbtv_buf, vb); | ||
530 | unsigned long flags; | ||
531 | |||
532 | if (usbtv->udev == NULL) { | ||
533 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
534 | return; | ||
535 | } | ||
536 | |||
537 | spin_lock_irqsave(&usbtv->buflock, flags); | ||
538 | list_add_tail(&buf->list, &usbtv->bufs); | ||
539 | spin_unlock_irqrestore(&usbtv->buflock, flags); | ||
540 | } | ||
541 | |||
542 | static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
543 | { | ||
544 | struct usbtv *usbtv = vb2_get_drv_priv(vq); | ||
545 | |||
546 | if (usbtv->udev == NULL) | ||
547 | return -ENODEV; | ||
548 | |||
549 | return usbtv_start(usbtv); | ||
550 | } | ||
551 | |||
552 | static int usbtv_stop_streaming(struct vb2_queue *vq) | ||
553 | { | ||
554 | struct usbtv *usbtv = vb2_get_drv_priv(vq); | ||
555 | |||
556 | if (usbtv->udev == NULL) | ||
557 | return -ENODEV; | ||
558 | |||
559 | usbtv_stop(usbtv); | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | struct vb2_ops usbtv_vb2_ops = { | ||
564 | .queue_setup = usbtv_queue_setup, | ||
565 | .buf_queue = usbtv_buf_queue, | ||
566 | .start_streaming = usbtv_start_streaming, | ||
567 | .stop_streaming = usbtv_stop_streaming, | ||
568 | }; | ||
569 | |||
570 | static void usbtv_release(struct v4l2_device *v4l2_dev) | ||
571 | { | ||
572 | struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev); | ||
573 | |||
574 | v4l2_device_unregister(&usbtv->v4l2_dev); | ||
575 | vb2_queue_release(&usbtv->vb2q); | ||
576 | kfree(usbtv); | ||
577 | } | ||
578 | |||
579 | static int usbtv_probe(struct usb_interface *intf, | ||
580 | const struct usb_device_id *id) | ||
581 | { | ||
582 | int ret; | ||
583 | int size; | ||
584 | struct device *dev = &intf->dev; | ||
585 | struct usbtv *usbtv; | ||
586 | |||
587 | /* Checks that the device is what we think it is. */ | ||
588 | if (intf->num_altsetting != 2) | ||
589 | return -ENODEV; | ||
590 | if (intf->altsetting[1].desc.bNumEndpoints != 4) | ||
591 | return -ENODEV; | ||
592 | |||
593 | /* Packet size is split into 11 bits of base size and count of | ||
594 | * extra multiplies of it.*/ | ||
595 | size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); | ||
596 | size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); | ||
597 | |||
598 | /* Device structure */ | ||
599 | usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); | ||
600 | if (usbtv == NULL) | ||
601 | return -ENOMEM; | ||
602 | usbtv->dev = dev; | ||
603 | usbtv->udev = usb_get_dev(interface_to_usbdev(intf)); | ||
604 | usbtv->iso_size = size; | ||
605 | spin_lock_init(&usbtv->buflock); | ||
606 | mutex_init(&usbtv->v4l2_lock); | ||
607 | mutex_init(&usbtv->vb2q_lock); | ||
608 | INIT_LIST_HEAD(&usbtv->bufs); | ||
609 | |||
610 | /* videobuf2 structure */ | ||
611 | usbtv->vb2q.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
612 | usbtv->vb2q.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | ||
613 | usbtv->vb2q.drv_priv = usbtv; | ||
614 | usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf); | ||
615 | usbtv->vb2q.ops = &usbtv_vb2_ops; | ||
616 | usbtv->vb2q.mem_ops = &vb2_vmalloc_memops; | ||
617 | usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
618 | usbtv->vb2q.lock = &usbtv->vb2q_lock; | ||
619 | ret = vb2_queue_init(&usbtv->vb2q); | ||
620 | if (ret < 0) { | ||
621 | dev_warn(dev, "Could not initialize videobuf2 queue\n"); | ||
622 | goto usbtv_fail; | ||
623 | } | ||
624 | |||
625 | /* v4l2 structure */ | ||
626 | usbtv->v4l2_dev.release = usbtv_release; | ||
627 | ret = v4l2_device_register(dev, &usbtv->v4l2_dev); | ||
628 | if (ret < 0) { | ||
629 | dev_warn(dev, "Could not register v4l2 device\n"); | ||
630 | goto v4l2_fail; | ||
631 | } | ||
632 | |||
633 | usb_set_intfdata(intf, usbtv); | ||
634 | |||
635 | /* Video structure */ | ||
636 | strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name)); | ||
637 | usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev; | ||
638 | usbtv->vdev.release = video_device_release_empty; | ||
639 | usbtv->vdev.fops = &usbtv_fops; | ||
640 | usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops; | ||
641 | usbtv->vdev.tvnorms = V4L2_STD_525_60; | ||
642 | usbtv->vdev.queue = &usbtv->vb2q; | ||
643 | usbtv->vdev.lock = &usbtv->v4l2_lock; | ||
644 | set_bit(V4L2_FL_USE_FH_PRIO, &usbtv->vdev.flags); | ||
645 | video_set_drvdata(&usbtv->vdev, usbtv); | ||
646 | ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); | ||
647 | if (ret < 0) { | ||
648 | dev_warn(dev, "Could not register video device\n"); | ||
649 | goto vdev_fail; | ||
650 | } | ||
651 | |||
652 | dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); | ||
653 | return 0; | ||
654 | |||
655 | vdev_fail: | ||
656 | v4l2_device_unregister(&usbtv->v4l2_dev); | ||
657 | v4l2_fail: | ||
658 | vb2_queue_release(&usbtv->vb2q); | ||
659 | usbtv_fail: | ||
660 | kfree(usbtv); | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | static void usbtv_disconnect(struct usb_interface *intf) | ||
666 | { | ||
667 | struct usbtv *usbtv = usb_get_intfdata(intf); | ||
668 | |||
669 | mutex_lock(&usbtv->vb2q_lock); | ||
670 | mutex_lock(&usbtv->v4l2_lock); | ||
671 | |||
672 | usbtv_stop(usbtv); | ||
673 | usb_set_intfdata(intf, NULL); | ||
674 | video_unregister_device(&usbtv->vdev); | ||
675 | v4l2_device_disconnect(&usbtv->v4l2_dev); | ||
676 | usb_put_dev(usbtv->udev); | ||
677 | usbtv->udev = NULL; | ||
678 | |||
679 | mutex_unlock(&usbtv->v4l2_lock); | ||
680 | mutex_unlock(&usbtv->vb2q_lock); | ||
681 | |||
682 | v4l2_device_put(&usbtv->v4l2_dev); | ||
683 | } | ||
684 | |||
685 | MODULE_AUTHOR("Lubomir Rintel"); | ||
686 | MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); | ||
687 | MODULE_LICENSE("Dual BSD/GPL"); | ||
688 | |||
689 | struct usb_driver usbtv_usb_driver = { | ||
690 | .name = "usbtv", | ||
691 | .id_table = usbtv_id_table, | ||
692 | .probe = usbtv_probe, | ||
693 | .disconnect = usbtv_disconnect, | ||
694 | }; | ||
695 | |||
696 | module_usb_driver(usbtv_usb_driver); | ||