blob: cdaf44806e3e72a7565f7be69af600a299be4588 [file] [log] [blame]
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001/*
2 tm6000-video.c - driver for TM5600/TM6000 USB video capture devices
3
4 Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03006 Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7 - Fixed module load/unload
8
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03009 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation version 2
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22#include <linux/module.h>
23#include <linux/delay.h>
24#include <linux/errno.h>
25#include <linux/fs.h>
26#include <linux/kernel.h>
27#include <linux/slab.h>
28#include <linux/mm.h>
29#include <linux/ioport.h>
30#include <linux/init.h>
31#include <linux/sched.h>
32#include <linux/random.h>
33#include <linux/version.h>
34#include <linux/usb.h>
35#include <linux/videodev2.h>
36#ifdef CONFIG_VIDEO_V4L1_COMPAT
37#include <linux/videodev.h>
38#endif
39#include <linux/interrupt.h>
40#include <linux/kthread.h>
41#include <linux/highmem.h>
42#include <linux/freezer.h>
43
44#include "tm6000-regs.h"
45#include "tm6000.h"
46
47#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
48
Michel Ludwig95a83822007-07-24 08:06:45 -030049/* Limits minimum and default number of buffers */
50#define TM6000_MIN_BUF 4
51#define TM6000_DEF_BUF 8
52
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -030053/* Declare static vars that will be used as parameters */
54static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
55static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
56
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -030057/* Debug level */
58int tm6000_debug;
59
60/* supported controls */
61static struct v4l2_queryctrl tm6000_qctrl[] = {
62 {
63 .id = V4L2_CID_BRIGHTNESS,
64 .type = V4L2_CTRL_TYPE_INTEGER,
65 .name = "Brightness",
66 .minimum = 0,
67 .maximum = 255,
68 .step = 1,
69 .default_value = 54,
70 .flags = 0,
71 }, {
72 .id = V4L2_CID_CONTRAST,
73 .type = V4L2_CTRL_TYPE_INTEGER,
74 .name = "Contrast",
75 .minimum = 0,
76 .maximum = 255,
77 .step = 0x1,
78 .default_value = 119,
79 .flags = 0,
80 }, {
81 .id = V4L2_CID_SATURATION,
82 .type = V4L2_CTRL_TYPE_INTEGER,
83 .name = "Saturation",
84 .minimum = 0,
85 .maximum = 255,
86 .step = 0x1,
87 .default_value = 112,
88 .flags = 0,
89 }, {
90 .id = V4L2_CID_HUE,
91 .type = V4L2_CTRL_TYPE_INTEGER,
92 .name = "Hue",
93 .minimum = -128,
94 .maximum = 127,
95 .step = 0x1,
96 .default_value = 0, //4 ?
97 .flags = 0,
98 }
99};
100
101static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
102
103static struct tm6000_fmt format[] = {
104 {
105 .name = "4:2:2, packed, YVY2",
106 .fourcc = V4L2_PIX_FMT_YUYV,
107 .depth = 16,
108 },{
109 .name = "4:2:2, packed, UYVY",
110 .fourcc = V4L2_PIX_FMT_UYVY,
111 .depth = 16,
112 },{
113 .name = "A/V + VBI mux packet",
114 .fourcc = V4L2_PIX_FMT_TM6000,
115 .depth = 16,
116 }
117};
118
119static LIST_HEAD(tm6000_corelist);
120
121/* ------------------------------------------------------------------
122 DMA and thread functions
123 ------------------------------------------------------------------*/
124
125#define norm_maxw(a) 720
Mauro Carvalho Chehab4475c042007-09-03 21:51:45 -0300126#define norm_maxh(a) 576
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300127
128//#define norm_minw(a) norm_maxw(a)
129#define norm_minw(a) norm_maxw(a)
130#define norm_minh(a) norm_maxh(a)
131
132/*
133 * video-buf generic routine to get the next available buffer
134 */
135static int inline get_next_buf (struct tm6000_dmaqueue *dma_q,
136 struct tm6000_buffer **buf)
137{
138 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
139
140 if (list_empty(&dma_q->active)) {
141 dprintk(dev, V4L2_DEBUG_QUEUE,"No active queue to serve\n");
142 return 0;
143 }
144
145 *buf = list_entry(dma_q->active.next,
146 struct tm6000_buffer, vb.queue);
147
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300148 return 1;
149}
150
151/*
152 * Announces that a buffer were filled and request the next
153 */
154static void inline buffer_filled (struct tm6000_core *dev,
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300155 struct tm6000_dmaqueue *dma_q,
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300156 struct tm6000_buffer *buf)
157{
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300158 /* Nobody is waiting something to be done, just return */
159 if (!waitqueue_active(&buf->vb.done)) {
160 mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
161
162 printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
163 jiffies);
164
165 return;
166 }
167
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300168 /* Advice that buffer was filled */
Mauro Carvalho Chehab5f796752007-08-27 07:55:05 -0300169 dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n",buf,buf->vb.i);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300170 buf->vb.state = STATE_DONE;
171 buf->vb.field_count++;
172 do_gettimeofday(&buf->vb.ts);
173
174 list_del(&buf->vb.queue);
175 wake_up(&buf->vb.done);
176}
177
178/*
179 * Macro to allow copying data into the proper memory type
180 */
181
182#define bufcpy(buf,out_ptr,in_ptr,size) \
183 { \
184 if (__copy_to_user(out_ptr,in_ptr,size)!=0) \
185 tm6000_err("copy_to_user failed.\n"); \
186 }
187
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300188
189const char *tm6000_msg_type[]= {
190 "unknown(0)", //0
191 "video", //1
192 "audio", //2
193 "vbi", //3
194 "pts", //4
195 "err", //5
196 "unknown(6)", //6
197 "unknown(7)", //7
198};
199
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300200/*
201 * Identify the tm5600/6000 buffer header type and properly handles
202 */
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300203static int copy_packet (struct urb *urb, u32 header, u8 **ptr, u8 *endp,
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300204 u8 *out_p, struct tm6000_buffer **buf)
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300205{
206 struct tm6000_dmaqueue *dma_q = urb->context;
207 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300208 u8 c;
209 unsigned int cmd, cpysize, pktsize, size, field, block, line, pos=0;
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300210 int rc=0;
211 /* FIXME: move to tm6000-isoc */
212 static int last_line=-2, start_line=-2, last_field=-2;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300213
214 /* FIXME: this is the hardcoded window size
215 */
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300216 unsigned int linewidth=(*buf)->vb.width<<1;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300217
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300218
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300219 if (!dev->isoc_ctl.cmd) {
220 c=(header>>24) & 0xff;
221
222 /* split the header fields */
223 size = (((header & 0x7e)<<1) -1) *4;
224 block = (header>>7) & 0xf;
225 field = (header>>11) & 0x1;
226 line = (header>>12) & 0x1ff;
227 cmd = (header>>21) & 0x7;
228
229 /* Validates header fields */
230 if(size>TM6000_URB_MSG_LEN)
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300231 size = TM6000_URB_MSG_LEN;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300232
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300233 if (cmd == TM6000_URB_MSG_VIDEO) {
234 if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
235 cmd = TM6000_URB_MSG_ERR;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300236
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300237 /* FIXME: Mounts the image as field0+field1
238 * It should, instead, check if the user selected
239 * entrelaced or non-entrelaced mode
240 */
241 pos= ((line<<1)+field)*linewidth +
242 block*TM6000_URB_MSG_LEN;
243
244 /* Don't allow to write out of the buffer */
245 if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
246 dprintk(dev, V4L2_DEBUG_ISOC,
247 "ERR: size=%d, num=%d, line=%d, "
248 "field=%d\n",
249 size, block, line, field);
250
251 cmd = TM6000_URB_MSG_ERR;
252 }
253 } else {
254 pos=0;
255 }
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300256
257 /* Prints debug info */
258 dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
259 " line=%d, field=%d\n",
260 size, block, line, field);
261
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300262 if ((last_line!=line)&&(last_line+1!=line) &&
263 (cmd != TM6000_URB_MSG_ERR) ) {
264 if (cmd != TM6000_URB_MSG_VIDEO) {
265 dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, "
266 "size=%d, num=%d, line=%d, field=%d\n",
267 cmd, size, block, line, field);
268 }
269 if (start_line<0)
270 start_line=last_line;
271 /* Prints debug info */
272 dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
273 "field=%d\n",
274 start_line, last_line, field);
275
276 if ((start_line<6 && last_line>200) &&
277 (last_field != field) ) {
278
279 dev->isoc_ctl.nfields++;
280 if (dev->isoc_ctl.nfields>=2) {
281 dev->isoc_ctl.nfields=0;
282
283 /* Announces that a new buffer were filled */
284 buffer_filled (dev, dma_q, *buf);
285 dprintk(dev, V4L2_DEBUG_ISOC,
286 "new buffer filled\n");
287 rc=get_next_buf (dma_q, buf);
288 }
289 }
290
291 start_line=line;
292 last_field=field;
293 }
294 last_line=line;
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300295
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300296 pktsize = TM6000_URB_MSG_LEN;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300297 } else {
298 /* Continue the last copy */
299 cmd = dev->isoc_ctl.cmd;
300 size= dev->isoc_ctl.size;
301 pos = dev->isoc_ctl.pos;
302 pktsize = dev->isoc_ctl.pktsize;
303 }
304
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300305 cpysize=(endp-(*ptr)>size)?size:endp-(*ptr);
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300306
307 if (cpysize) {
308 /* handles each different URB message */
309 switch(cmd) {
310 case TM6000_URB_MSG_VIDEO:
311 /* Fills video buffer */
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300312 if (__copy_to_user(&out_p[pos],*ptr,cpysize)!=0)
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300313 tm6000_err("copy_to_user failed.\n");
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300314
315 break;
316 case TM6000_URB_MSG_PTS:
317 break;
318 case TM6000_URB_MSG_AUDIO:
319/* Need some code to process audio */
320printk ("%ld: cmd=%s, size=%d\n", jiffies,
321 tm6000_msg_type[cmd],size);
322 break;
323 default:
324 dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
325 tm6000_msg_type[cmd],size);
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300326 }
327 }
328 if (cpysize<size) {
329 /* End of URB packet, but cmd processing is not
330 * complete. Preserve the state for a next packet
331 */
332 dev->isoc_ctl.pos = pos+cpysize;
333 dev->isoc_ctl.size= size-cpysize;
334 dev->isoc_ctl.cmd = cmd;
335 dev->isoc_ctl.pktsize = pktsize-cpysize;
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300336 (*ptr)+=cpysize;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300337 } else {
338 dev->isoc_ctl.cmd = 0;
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300339 (*ptr)+=pktsize;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300340 }
341
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300342 return rc;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300343}
344
345static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
346 struct urb *urb, struct tm6000_buffer **buf)
347{
348 struct tm6000_dmaqueue *dma_q = urb->context;
349 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
350 u8 *ptr=data, *endp=data+len;
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300351 unsigned long header=0;
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300352 int rc=0;
353
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300354 for (ptr=data; ptr<endp;) {
355 if (!dev->isoc_ctl.cmd) {
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300356 u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
357 /* FIXME: This seems very complex
358 * It just recovers up to 3 bytes of the header that
359 * might be at the previous packet
360 */
361 if (dev->isoc_ctl.tmp_buf_len) {
362 while (dev->isoc_ctl.tmp_buf_len) {
363 if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
364 break;
365 }
366 p++;
367 dev->isoc_ctl.tmp_buf_len--;
368 }
369 if (dev->isoc_ctl.tmp_buf_len) {
370 memcpy (&header,p,
371 dev->isoc_ctl.tmp_buf_len);
372 memcpy (((u8 *)header)+
373 dev->isoc_ctl.tmp_buf,
374 ptr,
375 4-dev->isoc_ctl.tmp_buf_len);
376 ptr+=4-dev->isoc_ctl.tmp_buf_len;
377 goto HEADER;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300378 }
379 }
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300380 /* Seek for sync */
381 for (;ptr<endp-3;ptr++) {
382 if (*(ptr+3)==0x47)
383 break;
384 }
385
386 if (ptr+3>=endp) {
387 dev->isoc_ctl.tmp_buf_len=endp-ptr;
388 memcpy (&dev->isoc_ctl.tmp_buf,ptr,
389 dev->isoc_ctl.tmp_buf_len);
390 dev->isoc_ctl.cmd=0;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300391 return rc;
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300392 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300393
394 /* Get message header */
395 header=*(unsigned long *)ptr;
396 ptr+=4;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300397 }
Mauro Carvalho Chehabcc6c60d2007-09-19 16:24:05 -0300398HEADER:
Mauro Carvalho Chehabe2c95002007-09-19 15:39:22 -0300399 /* Copy or continue last copy */
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300400 rc=copy_packet(urb,header,&ptr,endp,out_p,buf);
401 if (rc<0) {
402 buf=NULL;
403 printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
404 jiffies);
405 return rc;
406 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300407 }
408
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300409 return 0;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300410}
411/*
412 * Identify the tm5600/6000 buffer header type and properly handles
413 */
414static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
415 struct urb *urb, struct tm6000_buffer **buf)
416{
417 struct tm6000_dmaqueue *dma_q = urb->context;
418 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
419 unsigned int pos=dev->isoc_ctl.pos,cpysize;
420 int rc=1;
421
422 while (len>0) {
423 cpysize=min(len,(*buf)->vb.size-pos);
424//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
425 bufcpy(*buf,&out_p[pos],ptr,cpysize);
426 pos+=cpysize;
427 ptr+=cpysize;
428 len-=cpysize;
429 if (pos >= (*buf)->vb.size) {
430 pos=0;
431 /* Announces that a new buffer were filled */
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300432 buffer_filled (dev, dma_q, *buf);
Mauro Carvalho Chehab5f796752007-08-27 07:55:05 -0300433 dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300434 rc=get_next_buf (dma_q, buf);
435 if (rc<=0) {
436 *buf=NULL;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300437 break;
438 }
439 }
440 }
441
442 dev->isoc_ctl.pos=pos;
443 return rc;
444}
445
Mauro Carvalho Chehab5f796752007-08-27 07:55:05 -0300446static void inline print_err_status (struct tm6000_core *dev,
447 int packet, int status)
448{
449 char *errmsg = "Unknown";
450
451 switch(status) {
452 case -ENOENT:
453 errmsg = "unlinked synchronuously";
454 break;
455 case -ECONNRESET:
456 errmsg = "unlinked asynchronuously";
457 break;
458 case -ENOSR:
459 errmsg = "Buffer error (overrun)";
460 break;
461 case -EPIPE:
462 errmsg = "Stalled (device not responding)";
463 break;
464 case -EOVERFLOW:
465 errmsg = "Babble (bad cable?)";
466 break;
467 case -EPROTO:
468 errmsg = "Bit-stuff error (bad cable?)";
469 break;
470 case -EILSEQ:
471 errmsg = "CRC/Timeout (could be anything)";
472 break;
473 case -ETIME:
474 errmsg = "Device does not respond";
475 break;
476 }
477 if (packet<0) {
478 dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
479 status, errmsg);
480 } else {
481 dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
482 packet, status, errmsg);
483 }
484}
485
486
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300487/*
488 * Controls the isoc copy of each urb packet
489 */
490static inline int tm6000_isoc_copy(struct urb *urb, struct tm6000_buffer **buf)
491{
492 struct tm6000_dmaqueue *dma_q = urb->context;
493 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
494 void *outp=videobuf_to_vmalloc (&((*buf)->vb));
495 int i, len=0, rc=1;
496 int size=(*buf)->vb.size;
497 char *p;
498 unsigned long copied;
499
500 copied=0;
501
Mauro Carvalho Chehab5f796752007-08-27 07:55:05 -0300502 if (urb->status<0) {
503 print_err_status (dev,-1,urb->status);
504 return 0;
505 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300506
507 for (i = 0; i < urb->number_of_packets; i++) {
508 int status = urb->iso_frame_desc[i].status;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300509
Mauro Carvalho Chehab5f796752007-08-27 07:55:05 -0300510 if (status<0) {
511 print_err_status (dev,i,status);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300512 continue;
Mauro Carvalho Chehab5f796752007-08-27 07:55:05 -0300513 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300514
515 len=urb->iso_frame_desc[i].actual_length;
516
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300517// if (len>=TM6000_URB_MSG_LEN) {
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300518 p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
519 if (!urb->iso_frame_desc[i].status) {
520 if (((*buf)->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
521 rc=copy_multiplexed(p,outp,len,urb,buf);
522 if (rc<=0)
523 return rc;
524 } else {
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300525 copy_streams(p,outp,len,urb,buf);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300526 }
527 }
528 copied += len;
529 if (copied>=size)
530 break;
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300531// }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300532 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300533 return rc;
534}
535
536/* ------------------------------------------------------------------
537 URB control
538 ------------------------------------------------------------------*/
539
540/*
541 * IRQ callback, called by URB callback
542 */
543static void tm6000_irq_callback(struct urb *urb)
544{
545 struct tm6000_buffer *buf;
546 struct tm6000_dmaqueue *dma_q = urb->context;
547 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
548 int rc,i;
549 unsigned long flags;
550
551 spin_lock_irqsave(&dev->slock,flags);
552
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300553 buf=dev->isoc_ctl.buf;
554
555 if (!buf) {
556 rc=get_next_buf (dma_q, &buf);
557 if (rc<=0)
558 goto ret;
559 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300560
561 /* Copy data from URB */
562 rc=tm6000_isoc_copy(urb, &buf);
563
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300564 dev->isoc_ctl.buf=buf;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300565ret:
566 /* Reset urb buffers */
567 for (i = 0; i < urb->number_of_packets; i++) {
568 urb->iso_frame_desc[i].status = 0;
569 urb->iso_frame_desc[i].actual_length = 0;
570 }
571 urb->status = 0;
572
573 if ((urb->status = usb_submit_urb(urb, GFP_ATOMIC))) {
574 tm6000_err("urb resubmit failed (error=%i)\n",
575 urb->status);
576 }
577
578 if (rc>=0) {
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300579 /* Data filled, reset watchdog */
580 mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300581// }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300582 }
583 spin_unlock_irqrestore(&dev->slock,flags);
584}
585
586/*
587 * Stop and Deallocate URBs
588 */
589static void tm6000_uninit_isoc(struct tm6000_core *dev)
590{
591 struct urb *urb;
592 int i;
593
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300594 dev->isoc_ctl.nfields=-1;
595 dev->isoc_ctl.buf=NULL;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300596 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
597 urb=dev->isoc_ctl.urb[i];
598 if (urb) {
599 usb_kill_urb(urb);
600 usb_unlink_urb(urb);
601 if (dev->isoc_ctl.transfer_buffer[i]) {
602 usb_buffer_free(dev->udev,
603 urb->transfer_buffer_length,
604 dev->isoc_ctl.transfer_buffer[i],
605 urb->transfer_dma);
606 }
607 usb_free_urb(urb);
608 dev->isoc_ctl.urb[i] = NULL;
609 }
610 dev->isoc_ctl.transfer_buffer[i] = NULL;
611 }
612
613 kfree (dev->isoc_ctl.urb);
614 kfree (dev->isoc_ctl.transfer_buffer);
615 dev->isoc_ctl.urb=NULL;
616 dev->isoc_ctl.transfer_buffer=NULL;
617
618 dev->isoc_ctl.num_bufs=0;
619}
620
621/*
622 * Stop video thread - FIXME: Can be easily removed
623 */
624static void tm6000_stop_thread(struct tm6000_dmaqueue *dma_q)
625{
626 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
627
628 tm6000_uninit_isoc(dev);
629}
630
631
632/*
633 * Allocate URBs and start IRQ
634 */
635static int tm6000_prepare_isoc(struct tm6000_core *dev,
636 int max_packets, int num_bufs)
637{
638 struct tm6000_dmaqueue *dma_q = &dev->vidq;
639 int i;
640 int sb_size, pipe;
641 struct urb *urb;
642 int j, k;
643
644 /* De-allocates all pending stuff */
645 tm6000_uninit_isoc(dev);
646
647 dev->isoc_ctl.num_bufs=num_bufs;
648
649 dev->isoc_ctl.urb=kmalloc(sizeof(void *)*num_bufs,
650 GFP_KERNEL);
651 if (!dev->isoc_ctl.urb) {
652 tm6000_err("cannot alloc memory for usb buffers\n");
653 return -ENOMEM;
654 }
655
656 dev->isoc_ctl.transfer_buffer=kmalloc(sizeof(void *)*num_bufs,
657 GFP_KERNEL);
658 if (!dev->isoc_ctl.urb) {
659 tm6000_err("cannot allocate memory for usbtransfer\n");
660 kfree(dev->isoc_ctl.urb);
661 return -ENOMEM;
662 }
663
664 dev->isoc_ctl.max_pkt_size=dev->max_isoc_in;
665
666 sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
667
668
669 /* allocate urbs and transfer buffers */
670 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
671 urb = usb_alloc_urb(max_packets, GFP_KERNEL);
672 if (!urb) {
673 tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
674 tm6000_uninit_isoc(dev);
Mauro Carvalho Chehabc1a16412007-10-15 15:43:50 -0300675 usb_free_urb(urb);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300676 return -ENOMEM;
677 }
678 dev->isoc_ctl.urb[i] = urb;
679
680 dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
Mauro Carvalho Chehabc13dd702007-09-19 07:36:34 -0300681 sb_size, GFP_KERNEL, &urb->transfer_dma);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300682 if (!dev->isoc_ctl.transfer_buffer[i]) {
683 tm6000_err ("unable to allocate %i bytes for transfer"
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300684 " buffer %i%s\n",
685 sb_size, i,
686 in_interrupt()?" while in int":"");
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300687 tm6000_uninit_isoc(dev);
688 return -ENOMEM;
689 }
690 memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
691
692 pipe=usb_rcvisocpipe(dev->udev,
693 dev->isoc_in->desc.bEndpointAddress &
694 USB_ENDPOINT_NUMBER_MASK);
695 usb_fill_int_urb(urb, dev->udev, pipe,
696 dev->isoc_ctl.transfer_buffer[i],sb_size,
697 tm6000_irq_callback, dma_q,
698 dev->isoc_in->desc.bInterval);
699
700 urb->number_of_packets = max_packets;
701 urb->transfer_flags = URB_ISO_ASAP;
702
703 k = 0;
704 for (j = 0; j < max_packets; j++) {
705 urb->iso_frame_desc[j].offset = k;
706 urb->iso_frame_desc[j].length =
707 dev->isoc_ctl.max_pkt_size;
708 k += dev->isoc_ctl.max_pkt_size;
709 }
710 }
711
712 return 0;
713}
714
715static int tm6000_start_thread( struct tm6000_dmaqueue *dma_q,
716 struct tm6000_buffer *buf)
717{
718 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
719 int i,rc;
720
721 dma_q->frame=0;
722 dma_q->ini_jiffies=jiffies;
723
724 init_waitqueue_head(&dma_q->wq);
725
726 /* submit urbs and enables IRQ */
727 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
Michel Ludwig2cd4fd12007-06-17 17:12:32 -0300728 rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300729 if (rc) {
730 tm6000_err("submit of urb %i failed (error=%i)\n", i,
731 rc);
732 tm6000_uninit_isoc(dev);
733 return rc;
734 }
735 }
736
737 if (rc<0)
738 return rc;
739
740 return 0;
741}
742
743static int restart_video_queue(struct tm6000_dmaqueue *dma_q)
744{
745 struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
746
747 struct tm6000_buffer *buf, *prev;
748 struct list_head *item;
749
750 dprintk(dev, V4L2_DEBUG_QUEUE, "%s dma_q=0x%08lx\n",
751 __FUNCTION__,(unsigned long)dma_q);
752
753 if (!list_empty(&dma_q->active)) {
754 buf = list_entry(dma_q->active.next, struct tm6000_buffer, vb.queue);
755 dprintk(dev, V4L2_DEBUG_QUEUE,
756 "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i);
757
758 dprintk(dev, V4L2_DEBUG_QUEUE, "Restarting video dma\n");
759 tm6000_stop_thread(dma_q);
760 tm6000_start_thread(dma_q, buf);
761
762 /* cancel all outstanding capture / vbi requests */
763 list_for_each(item,&dma_q->active) {
764 buf = list_entry(item, struct tm6000_buffer, vb.queue);
765
766 list_del(&buf->vb.queue);
767 buf->vb.state = STATE_ERROR;
768 wake_up(&buf->vb.done);
769 }
770 mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
771
772 return 0;
773 }
774
775 prev = NULL;
776 for (;;) {
777 if (list_empty(&dma_q->queued))
778 return 0;
779 buf = list_entry(dma_q->queued.next, struct tm6000_buffer, vb.queue);
780 if (NULL == prev) {
781 list_del(&buf->vb.queue);
782 list_add_tail(&buf->vb.queue,&dma_q->active);
783
784 dprintk(dev, V4L2_DEBUG_QUEUE, "Restarting video dma\n");
785 tm6000_stop_thread(dma_q);
786 tm6000_start_thread(dma_q, buf);
787
788 buf->vb.state = STATE_ACTIVE;
789 mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
790 dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] restart_queue -"
791 " first active\n", buf, buf->vb.i);
792
793 } else if (prev->vb.width == buf->vb.width &&
794 prev->vb.height == buf->vb.height &&
795 prev->fmt == buf->fmt) {
796 list_del(&buf->vb.queue);
797 list_add_tail(&buf->vb.queue,&dma_q->active);
798 buf->vb.state = STATE_ACTIVE;
799 dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] restart_queue -"
800 " move to active\n",buf,buf->vb.i);
801 } else {
802 return 0;
803 }
804 prev = buf;
805 }
806}
807
808static void tm6000_vid_timeout(unsigned long data)
809{
810 struct tm6000_core *dev = (struct tm6000_core*)data;
811 struct tm6000_dmaqueue *vidq = &dev->vidq;
812 struct tm6000_buffer *buf;
813 unsigned long flags;
814
815 spin_lock_irqsave(&dev->slock,flags);
816 while (!list_empty(&vidq->active)) {
817 buf = list_entry(vidq->active.next, struct tm6000_buffer,
818 vb.queue);
819 list_del(&buf->vb.queue);
820 buf->vb.state = STATE_ERROR;
821 wake_up(&buf->vb.done);
822 dprintk(dev, V4L2_DEBUG_QUEUE, "tm6000/0: [%p/%d] timeout\n",
823 buf, buf->vb.i);
824 }
825
826 restart_video_queue(vidq);
827 spin_unlock_irqrestore(&dev->slock,flags);
828}
829
830/* ------------------------------------------------------------------
831 Videobuf operations
832 ------------------------------------------------------------------*/
Michel Ludwig95a83822007-07-24 08:06:45 -0300833
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300834static int
835buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
836{
837 struct tm6000_fh *fh = vq->priv_data;
838
839 *size = fh->fmt->depth * fh->width * fh->height >> 3;
840 if (0 == *count)
Michel Ludwig95a83822007-07-24 08:06:45 -0300841 *count = TM6000_DEF_BUF;
842
843 if (*count < TM6000_MIN_BUF) {
844 *count=TM6000_MIN_BUF;
845 }
846
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300847 while (*size * *count > vid_limit * 1024 * 1024)
848 (*count)--;
Michel Ludwig95a83822007-07-24 08:06:45 -0300849
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300850 return 0;
851}
852
853static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
854{
855 if (in_interrupt())
856 BUG();
857
858 videobuf_waiton(&buf->vb,0,0);
859 videobuf_vmalloc_free(&buf->vb);
860 buf->vb.state = STATE_NEEDS_INIT;
861}
862
863static int
864buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
865 enum v4l2_field field)
866{
867 struct tm6000_fh *fh = vq->priv_data;
868 struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
869 struct tm6000_core *dev = fh->dev;
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300870 int rc=0, urbsize, urb_init=0, npackets=1;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300871
872 BUG_ON(NULL == fh->fmt);
873
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300874
875 /* FIXME: It assumes depth=2 */
876 /* The only currently supported format is 16 bits/pixel */
877 buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
878 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
879 return -EINVAL;
880
881 if (buf->fmt != fh->fmt ||
882 buf->vb.width != fh->width ||
883 buf->vb.height != fh->height ||
884 buf->vb.field != field) {
885 buf->fmt = fh->fmt;
886 buf->vb.width = fh->width;
887 buf->vb.height = fh->height;
888 buf->vb.field = field;
889 buf->vb.state = STATE_NEEDS_INIT;
890 }
891
892 if (STATE_NEEDS_INIT == buf->vb.state) {
893 if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
894 goto fail;
895 urb_init=1;
896 }
897
898
899 if (!dev->isoc_ctl.num_bufs)
900 urb_init=1;
901
902 if (urb_init) {
Mauro Carvalho Chehabc13dd702007-09-19 07:36:34 -0300903 /* memory for video
904 Should be at least
905 Vres x Vres x 2 bytes/pixel by frame */
906 urbsize=buf->vb.size;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300907
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300908 /* Need also one PTS */
909 urbsize+=180;
910
Mauro Carvalho Chehabc13dd702007-09-19 07:36:34 -0300911 /* memory for audio
912 Should be at least
913 bitrate * 2 channels * 2 bytes / frame rate */
914 if (dev->norm & V4L2_STD_525_60) {
915 urbsize+=(dev->audio_bitrate*4+29)/30;
916 } else {
917 urbsize+=(dev->audio_bitrate*4+24)/25;
918 }
919
920 /* each audio frame seeems to have a frame number
921 with 2 bytes */
922 urbsize+=2;
923
924 /* Add 4 bytes by each 180 bytes frame */
925 urbsize+=((urbsize+179)/180)*4;
926
927 /* Round to an enough number of URBs */
928 urbsize=(urbsize+dev->max_isoc_in-1)/dev->max_isoc_in;
929
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300930 /* Avoids allocating big memory areas for URB */
931 while ((urbsize*dev->max_isoc_in)/npackets>65535) {
932 npackets++;
933 }
934 urbsize/=(urbsize+npackets-1)/npackets;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300935
Mauro Carvalho Chehaba2286182007-09-22 02:06:25 -0300936 dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %dx%d packets"
937 " of %d bytes each to handle %lu size\n",
938 npackets,urbsize,dev->max_isoc_in,buf->vb.size);
939
940 rc = tm6000_prepare_isoc(dev, urbsize, npackets);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -0300941
942 if (rc<0)
943 goto fail;
944 }
945
946 buf->vb.state = STATE_PREPARED;
947 return 0;
948
949fail:
950 free_buffer(vq,buf);
951 return rc;
952}
953
954static void
955buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
956{
957 struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
958 struct tm6000_fh *fh = vq->priv_data;
959 struct tm6000_core *dev = fh->dev;
960 struct tm6000_dmaqueue *vidq = &dev->vidq;
961 struct tm6000_buffer *prev;
962
963 if (!list_empty(&vidq->queued)) {
964 list_add_tail(&buf->vb.queue,&vidq->queued);
965 buf->vb.state = STATE_QUEUED;
966 dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] buffer_queue - "
967 "append to queued\n", buf, buf->vb.i);
968 } else if (list_empty(&vidq->active)) {
969 list_add_tail(&buf->vb.queue,&vidq->active);
970 buf->vb.state = STATE_ACTIVE;
971 mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
972 dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] buffer_queue - "
973 "first active\n", buf, buf->vb.i);
974 tm6000_start_thread(vidq, buf);
975 } else {
976 prev = list_entry(vidq->active.prev, struct tm6000_buffer, vb.queue);
977 if (prev->vb.width == buf->vb.width &&
978 prev->vb.height == buf->vb.height &&
979 prev->fmt == buf->fmt) {
980 list_add_tail(&buf->vb.queue,&vidq->active);
981 buf->vb.state = STATE_ACTIVE;
982 dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] buffer_queue -"
983 " append to active\n", buf, buf->vb.i);
984 } else {
985 list_add_tail(&buf->vb.queue,&vidq->queued);
986 buf->vb.state = STATE_QUEUED;
987 dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] buffer_queue -"
988 " first queued\n", buf, buf->vb.i);
989 }
990 }
991}
992
993static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
994{
995 struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
996 struct tm6000_fh *fh = vq->priv_data;
997 struct tm6000_core *dev = (struct tm6000_core*)fh->dev;
998 struct tm6000_dmaqueue *vidq = &dev->vidq;
999
1000 tm6000_stop_thread(vidq);
1001
1002 free_buffer(vq,buf);
1003}
1004
1005static struct videobuf_queue_ops tm6000_video_qops = {
1006 .buf_setup = buffer_setup,
1007 .buf_prepare = buffer_prepare,
1008 .buf_queue = buffer_queue,
1009 .buf_release = buffer_release,
1010};
1011
1012/* ------------------------------------------------------------------
1013 IOCTL handling
1014 ------------------------------------------------------------------*/
1015
1016static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh)
1017{
1018 /* is it free? */
1019 mutex_lock(&dev->lock);
1020 if (dev->resources) {
1021 /* no, someone else uses it */
1022 mutex_unlock(&dev->lock);
1023 return 0;
1024 }
1025 /* it's free, grab it */
1026 dev->resources =1;
1027 dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
1028 mutex_unlock(&dev->lock);
1029 return 1;
1030}
1031
1032static int res_locked(struct tm6000_core *dev)
1033{
1034 return (dev->resources);
1035}
1036
1037static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
1038{
1039 mutex_lock(&dev->lock);
1040 dev->resources = 0;
1041 dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
1042 mutex_unlock(&dev->lock);
1043}
1044
1045/* ------------------------------------------------------------------
1046 IOCTL vidioc handling
1047 ------------------------------------------------------------------*/
1048static int vidioc_querycap (struct file *file, void *priv,
1049 struct v4l2_capability *cap)
1050{
1051 // struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
1052
1053 strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
1054 strlcpy(cap->card,"Trident TVMaster TM5600/6000", sizeof(cap->card));
1055 // strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
1056 cap->version = TM6000_VERSION;
1057 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
1058 V4L2_CAP_STREAMING |
1059 V4L2_CAP_TUNER |
1060 V4L2_CAP_READWRITE;
1061 return 0;
1062}
1063
1064static int vidioc_enum_fmt_cap (struct file *file, void *priv,
1065 struct v4l2_fmtdesc *f)
1066{
1067 if (unlikely(f->index >= ARRAY_SIZE(format)))
1068 return -EINVAL;
1069
1070 strlcpy(f->description,format[f->index].name,sizeof(f->description));
1071 f->pixelformat = format[f->index].fourcc;
1072 return 0;
1073}
1074
1075static int vidioc_g_fmt_cap (struct file *file, void *priv,
1076 struct v4l2_format *f)
1077{
1078 struct tm6000_fh *fh=priv;
1079
1080 f->fmt.pix.width = fh->width;
1081 f->fmt.pix.height = fh->height;
1082 f->fmt.pix.field = fh->vb_vidq.field;
1083 f->fmt.pix.pixelformat = fh->fmt->fourcc;
1084 f->fmt.pix.bytesperline =
1085 (f->fmt.pix.width * fh->fmt->depth) >> 3;
1086 f->fmt.pix.sizeimage =
1087 f->fmt.pix.height * f->fmt.pix.bytesperline;
1088
1089 return (0);
1090}
1091
1092static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc)
1093{
1094 unsigned int i;
1095
1096 for (i = 0; i < ARRAY_SIZE(format); i++)
1097 if (format[i].fourcc == fourcc)
1098 return format+i;
1099 return NULL;
1100}
1101
1102static int vidioc_try_fmt_cap (struct file *file, void *priv,
1103 struct v4l2_format *f)
1104{
1105 struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
1106 struct tm6000_fmt *fmt;
1107 enum v4l2_field field;
1108
1109 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
1110 if (NULL == fmt) {
1111 dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
1112 " invalid.\n", f->fmt.pix.pixelformat);
1113 return -EINVAL;
1114 }
1115
1116 field = f->fmt.pix.field;
1117
1118 if (field == V4L2_FIELD_ANY) {
1119// field=V4L2_FIELD_INTERLACED;
1120 field=V4L2_FIELD_SEQ_TB;
1121 } else if (V4L2_FIELD_INTERLACED != field) {
1122 dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
1123 return -EINVAL;
1124 }
1125
Mauro Carvalho Chehab4475c042007-09-03 21:51:45 -03001126 tm6000_get_std_res (dev);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001127
Mauro Carvalho Chehab4475c042007-09-03 21:51:45 -03001128 f->fmt.pix.width = dev->width;
1129 f->fmt.pix.height = dev->height;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001130
1131 f->fmt.pix.width &= ~0x01;
1132
1133 f->fmt.pix.field = field;
1134
1135 f->fmt.pix.bytesperline =
1136 (f->fmt.pix.width * fmt->depth) >> 3;
1137 f->fmt.pix.sizeimage =
1138 f->fmt.pix.height * f->fmt.pix.bytesperline;
1139
1140 return 0;
1141}
1142
1143/*FIXME: This seems to be generic enough to be at videodev2 */
1144static int vidioc_s_fmt_cap (struct file *file, void *priv,
1145 struct v4l2_format *f)
1146{
1147 struct tm6000_fh *fh=priv;
1148 struct tm6000_core *dev = fh->dev;
1149 int ret = vidioc_try_fmt_cap(file,fh,f);
1150 if (ret < 0)
1151 return (ret);
1152
1153 fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
1154 fh->width = f->fmt.pix.width;
1155 fh->height = f->fmt.pix.height;
1156 fh->vb_vidq.field = f->fmt.pix.field;
1157 fh->type = f->type;
1158
1159 dev->fourcc = f->fmt.pix.pixelformat;
1160
1161 tm6000_set_fourcc_format(dev);
1162
1163 return (0);
1164}
1165
1166static int vidioc_reqbufs (struct file *file, void *priv,
1167 struct v4l2_requestbuffers *p)
1168{
1169 struct tm6000_fh *fh=priv;
1170
1171 return (videobuf_reqbufs(&fh->vb_vidq, p));
1172}
1173
1174static int vidioc_querybuf (struct file *file, void *priv,
1175 struct v4l2_buffer *p)
1176{
1177 struct tm6000_fh *fh=priv;
1178
1179 return (videobuf_querybuf(&fh->vb_vidq, p));
1180}
1181
1182static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
1183{
1184 struct tm6000_fh *fh=priv;
1185
1186 return (videobuf_qbuf(&fh->vb_vidq, p));
1187}
1188
1189static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
1190{
1191 struct tm6000_fh *fh=priv;
1192
1193 return (videobuf_dqbuf(&fh->vb_vidq, p,
1194 file->f_flags & O_NONBLOCK));
1195}
1196
1197#ifdef CONFIG_VIDEO_V4L1_COMPAT
1198static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
1199{
1200 struct tm6000_fh *fh=priv;
1201
1202 return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
1203}
1204#endif
1205
1206static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
1207{
1208 struct tm6000_fh *fh=priv;
1209 struct tm6000_core *dev = fh->dev;
1210
1211 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1212 return -EINVAL;
1213 if (i != fh->type)
1214 return -EINVAL;
1215
1216 if (!res_get(dev,fh))
1217 return -EBUSY;
1218 return (videobuf_streamon(&fh->vb_vidq));
1219}
1220
1221static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
1222{
1223 struct tm6000_fh *fh=priv;
1224 struct tm6000_core *dev = fh->dev;
1225
1226 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1227 return -EINVAL;
1228 if (i != fh->type)
1229 return -EINVAL;
1230
1231 videobuf_streamoff(&fh->vb_vidq);
1232 res_free(dev,fh);
1233
1234 return (0);
1235}
1236
1237static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
1238{
1239 int rc=0;
1240 struct tm6000_fh *fh=priv;
1241 struct tm6000_core *dev = fh->dev;
1242
1243 rc=tm6000_set_standard (dev, norm);
Mauro Carvalho Chehab71e7cfa2007-09-06 20:12:10 -03001244
1245 fh->width = dev->width;
1246 fh->height = dev->height;
1247
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001248 if (rc<0)
1249 return rc;
1250
1251 tm6000_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
1252
1253 return 0;
1254}
1255
1256static int vidioc_enum_input (struct file *file, void *priv,
1257 struct v4l2_input *inp)
1258{
1259 switch (inp->index) {
1260 case TM6000_INPUT_TV:
1261 inp->type = V4L2_INPUT_TYPE_TUNER;
1262 strcpy(inp->name,"Television");
1263 break;
1264 case TM6000_INPUT_COMPOSITE:
1265 inp->type = V4L2_INPUT_TYPE_CAMERA;
1266 strcpy(inp->name,"Composite");
1267 break;
1268 case TM6000_INPUT_SVIDEO:
1269 inp->type = V4L2_INPUT_TYPE_CAMERA;
1270 strcpy(inp->name,"S-Video");
1271 break;
1272 default:
1273 return -EINVAL;
1274 }
1275 inp->std = TM6000_STD;
1276
1277 return 0;
1278}
1279
1280static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
1281{
1282 struct tm6000_fh *fh=priv;
1283 struct tm6000_core *dev = fh->dev;
1284
1285 *i=dev->input;
1286
1287 return 0;
1288}
1289static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
1290{
1291 struct tm6000_fh *fh=priv;
1292 struct tm6000_core *dev = fh->dev;
1293 int rc=0;
1294 char buf[1];
1295
1296 switch (i) {
1297 case TM6000_INPUT_TV:
1298 dev->input=i;
1299 *buf=0;
1300 break;
1301 case TM6000_INPUT_COMPOSITE:
1302 case TM6000_INPUT_SVIDEO:
1303 dev->input=i;
1304 *buf=1;
1305 break;
1306 default:
1307 return -EINVAL;
1308 }
1309 rc=tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
1310 REQ_03_SET_GET_MCU_PIN, 0x03, 1, buf, 1);
1311
1312 if (!rc) {
1313 dev->input=i;
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001314 rc=vidioc_s_std (file, priv, &dev->vfd->current_norm);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001315 }
1316
1317 return (rc);
1318}
1319
1320 /* --- controls ---------------------------------------------- */
1321static int vidioc_queryctrl (struct file *file, void *priv,
1322 struct v4l2_queryctrl *qc)
1323{
1324 int i;
1325
1326 for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
1327 if (qc->id && qc->id == tm6000_qctrl[i].id) {
1328 memcpy(qc, &(tm6000_qctrl[i]),
1329 sizeof(*qc));
1330 return (0);
1331 }
1332
1333 return -EINVAL;
1334}
1335
1336static int vidioc_g_ctrl (struct file *file, void *priv,
1337 struct v4l2_control *ctrl)
1338{
1339 struct tm6000_fh *fh=priv;
1340 struct tm6000_core *dev = fh->dev;
1341 int val;
1342
1343 /* FIXME: Probably, those won't work! Maybe we need shadow regs */
1344 switch (ctrl->id) {
1345 case V4L2_CID_CONTRAST:
1346 val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x08, 0);
1347 break;
1348 case V4L2_CID_BRIGHTNESS:
1349 val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x09, 0);
1350 return 0;
1351 case V4L2_CID_SATURATION:
1352 val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x0a, 0);
1353 return 0;
1354 case V4L2_CID_HUE:
1355 val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x0b, 0);
1356 return 0;
1357 default:
1358 return -EINVAL;
1359 }
1360
1361 if (val<0)
1362 return val;
1363
1364 ctrl->value=val;
1365
1366 return 0;
1367}
1368static int vidioc_s_ctrl (struct file *file, void *priv,
1369 struct v4l2_control *ctrl)
1370{
1371 struct tm6000_fh *fh =priv;
1372 struct tm6000_core *dev = fh->dev;
1373 u8 val=ctrl->value;
1374
1375 switch (ctrl->id) {
1376 case V4L2_CID_CONTRAST:
1377 tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x08, val);
1378 return 0;
1379 case V4L2_CID_BRIGHTNESS:
1380 tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x09, val);
1381 return 0;
1382 case V4L2_CID_SATURATION:
1383 tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0a, val);
1384 return 0;
1385 case V4L2_CID_HUE:
1386 tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0b, val);
1387 return 0;
1388 }
1389 return -EINVAL;
1390}
1391
1392static int vidioc_g_tuner (struct file *file, void *priv,
1393 struct v4l2_tuner *t)
1394{
1395 struct tm6000_fh *fh =priv;
1396 struct tm6000_core *dev = fh->dev;
1397
1398 if (unlikely(UNSET == dev->tuner_type))
1399 return -EINVAL;
1400 if (0 != t->index)
1401 return -EINVAL;
1402
1403 strcpy(t->name, "Television");
1404 t->type = V4L2_TUNER_ANALOG_TV;
1405 t->capability = V4L2_TUNER_CAP_NORM;
1406 t->rangehigh = 0xffffffffUL;
1407 t->rxsubchans = V4L2_TUNER_SUB_MONO;
1408
1409 return 0;
1410}
1411
1412static int vidioc_s_tuner (struct file *file, void *priv,
1413 struct v4l2_tuner *t)
1414{
1415 struct tm6000_fh *fh =priv;
1416 struct tm6000_core *dev = fh->dev;
1417
1418 if (UNSET == dev->tuner_type)
1419 return -EINVAL;
1420 if (0 != t->index)
1421 return -EINVAL;
1422
1423 return 0;
1424}
1425
1426static int vidioc_g_frequency (struct file *file, void *priv,
1427 struct v4l2_frequency *f)
1428{
1429 struct tm6000_fh *fh =priv;
1430 struct tm6000_core *dev = fh->dev;
1431
1432 if (unlikely(UNSET == dev->tuner_type))
1433 return -EINVAL;
1434
1435 f->type = V4L2_TUNER_ANALOG_TV;
1436 f->frequency = dev->freq;
1437
1438 tm6000_i2c_call_clients(dev,VIDIOC_G_FREQUENCY,f);
1439
1440 return 0;
1441}
1442
1443static int vidioc_s_frequency (struct file *file, void *priv,
1444 struct v4l2_frequency *f)
1445{
1446 struct tm6000_fh *fh =priv;
1447 struct tm6000_core *dev = fh->dev;
1448
1449 if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
1450 return -EINVAL;
1451
1452 if (unlikely(UNSET == dev->tuner_type))
1453 return -EINVAL;
1454 if (unlikely(f->tuner != 0))
1455 return -EINVAL;
1456
1457// mutex_lock(&dev->lock);
1458 dev->freq = f->frequency;
1459 tm6000_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
1460// mutex_unlock(&dev->lock);
1461
1462 return 0;
1463}
1464
1465/* ------------------------------------------------------------------
1466 File operations for the device
1467 ------------------------------------------------------------------*/
1468
1469static int tm6000_open(struct inode *inode, struct file *file)
1470{
1471 int minor = iminor(inode);
1472 struct tm6000_core *h,*dev = NULL;
1473 struct tm6000_fh *fh;
1474 struct list_head *list;
1475 enum v4l2_buf_type type = 0;
1476 int i,rc;
1477
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001478 printk(KERN_INFO "tm6000: open called (minor=%d)\n",minor);
1479
1480
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001481 dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called "
1482 "(minor=%d)\n",minor);
1483
1484 list_for_each(list,&tm6000_corelist) {
1485 h = list_entry(list, struct tm6000_core, tm6000_corelist);
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001486 if (h->vfd->minor == minor) {
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001487 dev = h;
1488 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1489 }
1490 }
1491 if (NULL == dev)
1492 return -ENODEV;
1493
1494
1495 /* If more than one user, mutex should be added */
1496 dev->users++;
1497
1498 dprintk(dev, V4L2_DEBUG_OPEN, "open minor=%d type=%s users=%d\n",
1499 minor,v4l2_type_names[type],dev->users);
1500
1501 /* allocate + initialize per filehandle data */
1502 fh = kzalloc(sizeof(*fh),GFP_KERNEL);
1503 if (NULL == fh) {
1504 dev->users--;
1505 return -ENOMEM;
1506 }
1507
1508 file->private_data = fh;
1509 fh->dev = dev;
1510
1511 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1512 dev->fourcc = format[0].fourcc;
1513
1514 fh->fmt = format_by_fourcc(dev->fourcc);
Mauro Carvalho Chehab4475c042007-09-03 21:51:45 -03001515
1516 tm6000_get_std_res (dev);
1517
1518 fh->width = dev->width;
1519 fh->height = dev->height;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001520
1521 dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
1522 "dev->vidq=0x%08lx\n",
1523 (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
1524 dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
1525 "queued=%d\n",list_empty(&dev->vidq.queued));
1526 dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
1527 "active=%d\n",list_empty(&dev->vidq.active));
1528
1529 /* initialize hardware on analog mode */
1530 if (dev->mode!=TM6000_MODE_ANALOG) {
1531 rc=tm6000_init_analog_mode (dev);
1532 if (rc<0)
1533 return rc;
1534
1535 /* Put all controls at a sane state */
1536 for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
1537 qctl_regs[i] =tm6000_qctrl[i].default_value;
1538
1539 dev->mode=TM6000_MODE_ANALOG;
1540 }
1541
1542 videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
1543 NULL, &dev->slock,
1544 fh->type,
1545 V4L2_FIELD_INTERLACED,
1546 sizeof(struct tm6000_buffer),fh);
1547
1548 return 0;
1549}
1550
1551static ssize_t
1552tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
1553{
1554 struct tm6000_fh *fh = file->private_data;
1555
1556 if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1557 if (res_locked(fh->dev))
1558 return -EBUSY;
1559
1560 return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
1561 file->f_flags & O_NONBLOCK);
1562 }
1563 return 0;
1564}
1565
1566static unsigned int
1567tm6000_poll(struct file *file, struct poll_table_struct *wait)
1568{
1569 struct tm6000_fh *fh = file->private_data;
1570 struct tm6000_buffer *buf;
1571
1572 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1573 return POLLERR;
1574
1575 if (res_get(fh->dev,fh)) {
1576 /* streaming capture */
1577 if (list_empty(&fh->vb_vidq.stream))
1578 return POLLERR;
1579 buf = list_entry(fh->vb_vidq.stream.next,struct tm6000_buffer,vb.stream);
1580 } else {
1581 /* read() capture */
Mauro Carvalho Chehabdc6a02a2007-08-27 07:55:38 -03001582 return videobuf_poll_stream(file, &fh->vb_vidq,
1583 wait);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001584 }
1585 poll_wait(file, &buf->vb.done, wait);
1586 if (buf->vb.state == STATE_DONE ||
1587 buf->vb.state == STATE_ERROR)
1588 return POLLIN|POLLRDNORM;
1589 return 0;
1590}
1591
1592static int tm6000_release(struct inode *inode, struct file *file)
1593{
1594 struct tm6000_fh *fh = file->private_data;
1595 struct tm6000_core *dev = fh->dev;
1596 struct tm6000_dmaqueue *vidq = &dev->vidq;
1597 int minor = iminor(inode);
1598
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001599 dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (minor=%d, users=%d)\n",minor,dev->users);
1600
Mauro Carvalho Chehaba58d35c2007-06-17 17:14:12 -03001601 dev->users--;
1602
1603 if (!dev->users) {
1604 tm6000_stop_thread(vidq);
1605 videobuf_mmap_free(&fh->vb_vidq);
1606 }
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001607
1608 kfree (fh);
1609
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001610 return 0;
1611}
1612
1613static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
1614{
1615 struct tm6000_fh *fh = file->private_data;
1616 int ret;
1617
1618 ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
1619
1620 return ret;
1621}
1622
1623static struct file_operations tm6000_fops = {
1624 .owner = THIS_MODULE,
1625 .open = tm6000_open,
1626 .release = tm6000_release,
1627 .ioctl = video_ioctl2, /* V4L2 ioctl handler */
1628 .read = tm6000_read,
1629 .poll = tm6000_poll,
1630 .mmap = tm6000_mmap,
1631 .llseek = no_llseek,
1632};
1633
1634static struct video_device tm6000_template = {
1635 .name = "tm6000",
1636 .type = VID_TYPE_CAPTURE,
1637 .fops = &tm6000_fops,
1638 .minor = -1,
1639 .release = video_device_release,
1640
1641 .vidioc_querycap = vidioc_querycap,
1642 .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
1643 .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
1644 .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
1645 .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
1646 .vidioc_s_std = vidioc_s_std,
1647 .vidioc_enum_input = vidioc_enum_input,
1648 .vidioc_g_input = vidioc_g_input,
1649 .vidioc_s_input = vidioc_s_input,
1650 .vidioc_queryctrl = vidioc_queryctrl,
1651 .vidioc_g_ctrl = vidioc_g_ctrl,
1652 .vidioc_s_ctrl = vidioc_s_ctrl,
1653 .vidioc_g_tuner = vidioc_g_tuner,
1654 .vidioc_s_tuner = vidioc_s_tuner,
1655 .vidioc_g_frequency = vidioc_g_frequency,
1656 .vidioc_s_frequency = vidioc_s_frequency,
1657 .vidioc_streamon = vidioc_streamon,
1658 .vidioc_streamoff = vidioc_streamoff,
1659 .vidioc_reqbufs = vidioc_reqbufs,
1660 .vidioc_querybuf = vidioc_querybuf,
1661 .vidioc_qbuf = vidioc_qbuf,
1662 .vidioc_dqbuf = vidioc_dqbuf,
1663#ifdef CONFIG_VIDEO_V4L1_COMPAT
1664 .vidiocgmbuf = vidiocgmbuf,
1665#endif
1666 .tvnorms = TM6000_STD,
1667 .current_norm = V4L2_STD_NTSC_M,
1668};
1669/* -----------------------------------------------------------------
1670 Initialization and module stuff
1671 ------------------------------------------------------------------*/
1672
1673int tm6000_v4l2_register(struct tm6000_core *dev)
1674{
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001675 int ret = -1;
1676 struct video_device *vfd;
1677
1678 vfd = video_device_alloc();
1679 if(!vfd) {
1680 return -ENOMEM;
1681 }
1682 dev->vfd = vfd;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001683
1684 list_add_tail(&dev->tm6000_corelist,&tm6000_corelist);
1685
1686 /* init video dma queues */
1687 INIT_LIST_HEAD(&dev->vidq.active);
1688 INIT_LIST_HEAD(&dev->vidq.queued);
1689
1690 dev->vidq.timeout.function = tm6000_vid_timeout;
1691 dev->vidq.timeout.data = (unsigned long)dev;
1692 init_timer(&dev->vidq.timeout);
1693
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001694 memcpy (dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
1695 dev->vfd->debug=tm6000_debug;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001696
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001697 ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001698 printk(KERN_INFO "Trident TVMaster TM5600/TM6000 USB2 board (Load status: %d)\n", ret);
1699 return ret;
1700}
1701
1702int tm6000_v4l2_unregister(struct tm6000_core *dev)
1703{
1704 struct tm6000_core *h;
Michel Ludwig22927e82007-06-14 17:19:59 -03001705 struct list_head *pos, *tmp;
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001706
Michel Ludwig7c3f53e2007-06-16 23:21:48 -03001707 video_unregister_device(dev->vfd);
Michel Ludwig22927e82007-06-14 17:19:59 -03001708
1709 list_for_each_safe(pos, tmp, &tm6000_corelist) {
1710 h = list_entry(pos, struct tm6000_core, tm6000_corelist);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001711 if (h == dev) {
Michel Ludwig8c9d26f2007-06-15 11:02:56 -03001712 list_del(pos);
Mauro Carvalho Chehab9701dc92009-09-14 09:42:41 -03001713 }
1714 }
1715
1716 return 0;
1717}
1718
1719int tm6000_v4l2_exit(void)
1720{
1721 return 0;
1722}
1723
1724module_param(video_nr, int, 0);
1725MODULE_PARM_DESC(video_nr,"Allow changing video device number");
1726
1727module_param_named (debug, tm6000_debug, int, 0444);
1728MODULE_PARM_DESC(debug,"activates debug info");
1729
1730module_param(vid_limit,int,0644);
1731MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
1732