diff options
Diffstat (limited to 'drivers/media/video/vivi.c')
-rw-r--r-- | drivers/media/video/vivi.c | 1454 |
1 files changed, 1454 insertions, 0 deletions
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c new file mode 100644 index 000000000000..5e813404d068 --- /dev/null +++ b/drivers/media/video/vivi.c | |||
@@ -0,0 +1,1454 @@ | |||
1 | /* | ||
2 | * Virtual Video driver - This code emulates a real video device with v4l2 api | ||
3 | * | ||
4 | * Copyright (c) 2006 by: | ||
5 | * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> | ||
6 | * Ted Walther <ted--a.t--enumera.com> | ||
7 | * John Sokol <sokol--a.t--videotechnology.com> | ||
8 | * http://v4l.videotechnology.com/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the BSD Licence, GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version 2 of the | ||
13 | * License, or (at your option) any later version | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/random.h> | ||
27 | #include <linux/version.h> | ||
28 | #include <linux/videodev2.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <media/video-buf.h> | ||
31 | #include <media/v4l2-common.h> | ||
32 | #include <linux/kthread.h> | ||
33 | #include <linux/highmem.h> | ||
34 | |||
35 | /* Wake up at about 30 fps */ | ||
36 | #define WAKE_NUMERATOR 30 | ||
37 | #define WAKE_DENOMINATOR 1001 | ||
38 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ | ||
39 | |||
40 | /* These timers are for 1 fps - used only for testing */ | ||
41 | //#define WAKE_DENOMINATOR 30 /* hack for testing purposes */ | ||
42 | //#define BUFFER_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ | ||
43 | |||
44 | #include "font.h" | ||
45 | |||
46 | #ifndef kzalloc | ||
47 | #define kzalloc(size, flags) \ | ||
48 | ({ \ | ||
49 | void *__ret = kmalloc(size, flags); \ | ||
50 | if (__ret) \ | ||
51 | memset(__ret, 0, size); \ | ||
52 | __ret; \ | ||
53 | }) | ||
54 | #endif | ||
55 | |||
56 | MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); | ||
57 | MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); | ||
58 | MODULE_LICENSE("Dual BSD/GPL"); | ||
59 | |||
60 | #define VIVI_MAJOR_VERSION 0 | ||
61 | #define VIVI_MINOR_VERSION 4 | ||
62 | #define VIVI_RELEASE 0 | ||
63 | #define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) | ||
64 | |||
65 | static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ | ||
66 | module_param(video_nr, int, 0); | ||
67 | |||
68 | static int debug = 0; | ||
69 | module_param(debug, int, 0); | ||
70 | |||
71 | static unsigned int vid_limit = 16; | ||
72 | module_param(vid_limit,int,0644); | ||
73 | MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); | ||
74 | |||
75 | /* supported controls */ | ||
76 | static struct v4l2_queryctrl vivi_qctrl[] = { | ||
77 | { | ||
78 | .id = V4L2_CID_AUDIO_VOLUME, | ||
79 | .name = "Volume", | ||
80 | .minimum = 0, | ||
81 | .maximum = 65535, | ||
82 | .step = 65535/100, | ||
83 | .default_value = 65535, | ||
84 | .flags = 0, | ||
85 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
86 | },{ | ||
87 | .id = V4L2_CID_BRIGHTNESS, | ||
88 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
89 | .name = "Brightness", | ||
90 | .minimum = 0, | ||
91 | .maximum = 255, | ||
92 | .step = 1, | ||
93 | .default_value = 127, | ||
94 | .flags = 0, | ||
95 | }, { | ||
96 | .id = V4L2_CID_CONTRAST, | ||
97 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
98 | .name = "Contrast", | ||
99 | .minimum = 0, | ||
100 | .maximum = 255, | ||
101 | .step = 0x1, | ||
102 | .default_value = 0x10, | ||
103 | .flags = 0, | ||
104 | }, { | ||
105 | .id = V4L2_CID_SATURATION, | ||
106 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
107 | .name = "Saturation", | ||
108 | .minimum = 0, | ||
109 | .maximum = 255, | ||
110 | .step = 0x1, | ||
111 | .default_value = 127, | ||
112 | .flags = 0, | ||
113 | }, { | ||
114 | .id = V4L2_CID_HUE, | ||
115 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
116 | .name = "Hue", | ||
117 | .minimum = -128, | ||
118 | .maximum = 127, | ||
119 | .step = 0x1, | ||
120 | .default_value = 0, | ||
121 | .flags = 0, | ||
122 | } | ||
123 | }; | ||
124 | |||
125 | static int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; | ||
126 | |||
127 | #define dprintk(level,fmt, arg...) \ | ||
128 | do { \ | ||
129 | if (debug >= (level)) \ | ||
130 | printk(KERN_DEBUG "vivi: " fmt , ## arg); \ | ||
131 | } while (0) | ||
132 | |||
133 | /* ------------------------------------------------------------------ | ||
134 | Basic structures | ||
135 | ------------------------------------------------------------------*/ | ||
136 | |||
137 | struct vivi_fmt { | ||
138 | char *name; | ||
139 | u32 fourcc; /* v4l2 format id */ | ||
140 | int depth; | ||
141 | }; | ||
142 | |||
143 | static struct vivi_fmt format = { | ||
144 | .name = "4:2:2, packed, YUYV", | ||
145 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
146 | .depth = 16, | ||
147 | }; | ||
148 | |||
149 | struct sg_to_addr { | ||
150 | int pos; | ||
151 | struct scatterlist *sg; | ||
152 | }; | ||
153 | |||
154 | /* buffer for one video frame */ | ||
155 | struct vivi_buffer { | ||
156 | /* common v4l buffer stuff -- must be first */ | ||
157 | struct videobuf_buffer vb; | ||
158 | |||
159 | struct vivi_fmt *fmt; | ||
160 | |||
161 | struct sg_to_addr *to_addr; | ||
162 | }; | ||
163 | |||
164 | struct vivi_dmaqueue { | ||
165 | struct list_head active; | ||
166 | struct list_head queued; | ||
167 | struct timer_list timeout; | ||
168 | |||
169 | /* thread for generating video stream*/ | ||
170 | struct task_struct *kthread; | ||
171 | wait_queue_head_t wq; | ||
172 | /* Counters to control fps rate */ | ||
173 | int frame; | ||
174 | int ini_jiffies; | ||
175 | }; | ||
176 | |||
177 | static LIST_HEAD(vivi_devlist); | ||
178 | |||
179 | struct vivi_dev { | ||
180 | struct list_head vivi_devlist; | ||
181 | |||
182 | struct semaphore lock; | ||
183 | |||
184 | int users; | ||
185 | |||
186 | /* various device info */ | ||
187 | unsigned int resources; | ||
188 | struct video_device video_dev; | ||
189 | |||
190 | struct vivi_dmaqueue vidq; | ||
191 | |||
192 | /* Several counters */ | ||
193 | int h,m,s,us,jiffies; | ||
194 | char timestr[13]; | ||
195 | }; | ||
196 | |||
197 | struct vivi_fh { | ||
198 | struct vivi_dev *dev; | ||
199 | |||
200 | /* video capture */ | ||
201 | struct vivi_fmt *fmt; | ||
202 | unsigned int width,height; | ||
203 | struct videobuf_queue vb_vidq; | ||
204 | |||
205 | enum v4l2_buf_type type; | ||
206 | }; | ||
207 | |||
208 | /* ------------------------------------------------------------------ | ||
209 | DMA and thread functions | ||
210 | ------------------------------------------------------------------*/ | ||
211 | |||
212 | /* Bars and Colors should match positions */ | ||
213 | |||
214 | enum colors { | ||
215 | WHITE, | ||
216 | AMBAR, | ||
217 | CYAN, | ||
218 | GREEN, | ||
219 | MAGENTA, | ||
220 | RED, | ||
221 | BLUE | ||
222 | }; | ||
223 | |||
224 | static u8 bars[8][3] = { | ||
225 | /* R G B */ | ||
226 | {204,204,204}, /* white */ | ||
227 | {208,208, 0}, /* ambar */ | ||
228 | { 0,206,206}, /* cyan */ | ||
229 | { 0,239, 0}, /* green */ | ||
230 | {239, 0,239}, /* magenta */ | ||
231 | {205, 0, 0}, /* red */ | ||
232 | { 0, 0,255}, /* blue */ | ||
233 | { 0, 0, 0} | ||
234 | }; | ||
235 | |||
236 | #define TO_Y(r,g,b) (((16829*r +33039*g +6416*b + 32768)>>16)+16) | ||
237 | /* RGB to V(Cr) Color transform */ | ||
238 | #define TO_V(r,g,b) (((28784*r -24103*g -4681*b + 32768)>>16)+128) | ||
239 | /* RGB to U(Cb) Color transform */ | ||
240 | #define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128) | ||
241 | |||
242 | #define TSTAMP_MIN_Y 24 | ||
243 | #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 | ||
244 | #define TSTAMP_MIN_X 64 | ||
245 | |||
246 | void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb) | ||
247 | { | ||
248 | int i, pos=0; | ||
249 | |||
250 | for (i=0;i<vb->dma.nr_pages;i++) { | ||
251 | to_addr[i].sg=&vb->dma.sglist[i]; | ||
252 | to_addr[i].pos=pos; | ||
253 | pos += vb->dma.sglist[i].length; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[]) | ||
258 | { | ||
259 | int p1=0,p2=pages-1,p3=pages/2; | ||
260 | |||
261 | /* Sanity test */ | ||
262 | BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length); | ||
263 | |||
264 | while (p1+1<p2) { | ||
265 | if (pos < to_addr[p3].pos) { | ||
266 | p2=p3; | ||
267 | } else { | ||
268 | p1=p3; | ||
269 | } | ||
270 | p3=(p1+p2)/2; | ||
271 | } | ||
272 | if (pos >= to_addr[p2].pos) | ||
273 | p1=p2; | ||
274 | |||
275 | return (p1); | ||
276 | } | ||
277 | |||
278 | void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | ||
279 | int hmax, int line, char *timestr) | ||
280 | { | ||
281 | int w,i,j,pos=inipos,pgpos,oldpg,y; | ||
282 | char *p,*s,*basep; | ||
283 | struct page *pg; | ||
284 | u8 chr,r,g,b,color; | ||
285 | |||
286 | /* Get first addr pointed to pixel position */ | ||
287 | oldpg=get_addr_pos(pos,pages,to_addr); | ||
288 | pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT); | ||
289 | basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; | ||
290 | |||
291 | /* We will just duplicate the second pixel at the packet */ | ||
292 | wmax/=2; | ||
293 | |||
294 | /* Generate a standard color bar pattern */ | ||
295 | for (w=0;w<wmax;w++) { | ||
296 | r=bars[w*7/wmax][0]; | ||
297 | g=bars[w*7/wmax][1]; | ||
298 | b=bars[w*7/wmax][2]; | ||
299 | |||
300 | for (color=0;color<4;color++) { | ||
301 | pgpos=get_addr_pos(pos,pages,to_addr); | ||
302 | if (pgpos!=oldpg) { | ||
303 | pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT); | ||
304 | kunmap_atomic(basep, KM_BOUNCE_READ); | ||
305 | basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset; | ||
306 | oldpg=pgpos; | ||
307 | } | ||
308 | p=basep+pos-to_addr[pgpos].pos; | ||
309 | |||
310 | switch (color) { | ||
311 | case 0: | ||
312 | case 2: | ||
313 | *p=TO_Y(r,g,b); /* Luminance */ | ||
314 | break; | ||
315 | case 1: | ||
316 | *p=TO_U(r,g,b); /* Cb */ | ||
317 | break; | ||
318 | case 3: | ||
319 | *p=TO_V(r,g,b); /* Cr */ | ||
320 | break; | ||
321 | } | ||
322 | pos++; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | /* Checks if it is possible to show timestamp */ | ||
327 | if (TSTAMP_MAX_Y>=hmax) | ||
328 | goto end; | ||
329 | if (TSTAMP_MIN_X+strlen(timestr)>=wmax) | ||
330 | goto end; | ||
331 | |||
332 | /* Print stream time */ | ||
333 | if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) { | ||
334 | j=TSTAMP_MIN_X; | ||
335 | for (s=timestr;*s;s++) { | ||
336 | chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; | ||
337 | for (i=0;i<7;i++) { | ||
338 | if (chr&1<<(7-i)) { /* Font color*/ | ||
339 | r=bars[BLUE][0]; | ||
340 | g=bars[BLUE][1]; | ||
341 | b=bars[BLUE][2]; | ||
342 | r=g=b=0; | ||
343 | g=198; | ||
344 | } else { /* Background color */ | ||
345 | r=bars[WHITE][0]; | ||
346 | g=bars[WHITE][1]; | ||
347 | b=bars[WHITE][2]; | ||
348 | r=g=b=0; | ||
349 | } | ||
350 | |||
351 | pos=inipos+j*2; | ||
352 | for (color=0;color<4;color++) { | ||
353 | pgpos=get_addr_pos(pos,pages,to_addr); | ||
354 | if (pgpos!=oldpg) { | ||
355 | pg=pfn_to_page(to_addr[pgpos]. | ||
356 | sg->dma_address | ||
357 | >> PAGE_SHIFT); | ||
358 | kunmap_atomic(basep, | ||
359 | KM_BOUNCE_READ); | ||
360 | basep= kmap_atomic(pg, | ||
361 | KM_BOUNCE_READ)+ | ||
362 | to_addr[pgpos].sg->offset; | ||
363 | oldpg=pgpos; | ||
364 | } | ||
365 | p=basep+pos-to_addr[pgpos].pos; | ||
366 | |||
367 | y=TO_Y(r,g,b); | ||
368 | |||
369 | switch (color) { | ||
370 | case 0: | ||
371 | case 2: | ||
372 | *p=TO_Y(r,g,b); /* Luminance */ | ||
373 | break; | ||
374 | case 1: | ||
375 | *p=TO_U(r,g,b); /* Cb */ | ||
376 | break; | ||
377 | case 3: | ||
378 | *p=TO_V(r,g,b); /* Cr */ | ||
379 | break; | ||
380 | } | ||
381 | pos++; | ||
382 | } | ||
383 | j++; | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | |||
388 | |||
389 | end: | ||
390 | kunmap_atomic(basep, KM_BOUNCE_READ); | ||
391 | } | ||
392 | static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) | ||
393 | { | ||
394 | int h,pos=0; | ||
395 | int hmax = buf->vb.height; | ||
396 | int wmax = buf->vb.width; | ||
397 | struct videobuf_buffer *vb=&buf->vb; | ||
398 | struct sg_to_addr *to_addr=buf->to_addr; | ||
399 | struct timeval ts; | ||
400 | |||
401 | /* Test if DMA mapping is ready */ | ||
402 | if (!vb->dma.sglist[0].dma_address) | ||
403 | return; | ||
404 | |||
405 | prep_to_addr(to_addr,vb); | ||
406 | |||
407 | /* Check if there is enough memory */ | ||
408 | BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); | ||
409 | |||
410 | for (h=0;h<hmax;h++) { | ||
411 | gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); | ||
412 | pos += wmax*2; | ||
413 | } | ||
414 | |||
415 | /* Updates stream time */ | ||
416 | |||
417 | dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); | ||
418 | dev->jiffies=jiffies; | ||
419 | if (dev->us>=1000000) { | ||
420 | dev->us-=1000000; | ||
421 | dev->s++; | ||
422 | if (dev->s>=60) { | ||
423 | dev->s-=60; | ||
424 | dev->m++; | ||
425 | if (dev->m>60) { | ||
426 | dev->m-=60; | ||
427 | dev->h++; | ||
428 | if (dev->h>24) | ||
429 | dev->h-=24; | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | sprintf(dev->timestr,"%02d:%02d:%02d:%03d", | ||
434 | dev->h,dev->m,dev->s,(dev->us+500)/1000); | ||
435 | |||
436 | dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, | ||
437 | (unsigned long)buf->vb.dma.vmalloc,pos); | ||
438 | |||
439 | /* Advice that buffer was filled */ | ||
440 | buf->vb.state = STATE_DONE; | ||
441 | buf->vb.field_count++; | ||
442 | do_gettimeofday(&ts); | ||
443 | buf->vb.ts = ts; | ||
444 | |||
445 | list_del(&buf->vb.queue); | ||
446 | wake_up(&buf->vb.done); | ||
447 | } | ||
448 | |||
449 | static int restart_video_queue(struct vivi_dmaqueue *dma_q); | ||
450 | |||
451 | static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) | ||
452 | { | ||
453 | struct vivi_buffer *buf; | ||
454 | struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq); | ||
455 | |||
456 | int bc; | ||
457 | |||
458 | /* Announces videobuf that all went ok */ | ||
459 | for (bc = 0;; bc++) { | ||
460 | if (list_empty(&dma_q->active)) { | ||
461 | dprintk(1,"No active queue to serve\n"); | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | buf = list_entry(dma_q->active.next, | ||
466 | struct vivi_buffer, vb.queue); | ||
467 | |||
468 | /* Nobody is waiting something to be done, just return */ | ||
469 | if (!waitqueue_active(&buf->vb.done)) { | ||
470 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | do_gettimeofday(&buf->vb.ts); | ||
475 | dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i); | ||
476 | |||
477 | /* Fill buffer */ | ||
478 | vivi_fillbuff(dev,buf); | ||
479 | } | ||
480 | if (list_empty(&dma_q->active)) { | ||
481 | del_timer(&dma_q->timeout); | ||
482 | } else { | ||
483 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
484 | } | ||
485 | if (bc != 1) | ||
486 | dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); | ||
487 | } | ||
488 | |||
489 | void vivi_sleep(struct vivi_dmaqueue *dma_q) | ||
490 | { | ||
491 | int timeout; | ||
492 | DECLARE_WAITQUEUE(wait, current); | ||
493 | |||
494 | dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); | ||
495 | |||
496 | add_wait_queue(&dma_q->wq, &wait); | ||
497 | if (!kthread_should_stop()) { | ||
498 | dma_q->frame++; | ||
499 | |||
500 | /* Calculate time to wake up */ | ||
501 | timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; | ||
502 | |||
503 | if (timeout <= 0) { | ||
504 | int old=dma_q->frame; | ||
505 | dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1; | ||
506 | |||
507 | timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; | ||
508 | |||
509 | dprintk(1,"underrun, losed %d frames. " | ||
510 | "Now, frame is %d. Waking on %d jiffies\n", | ||
511 | dma_q->frame-old,dma_q->frame,timeout); | ||
512 | } else | ||
513 | dprintk(1,"will sleep for %i jiffies\n",timeout); | ||
514 | |||
515 | vivi_thread_tick(dma_q); | ||
516 | |||
517 | schedule_timeout_interruptible (timeout); | ||
518 | } | ||
519 | |||
520 | remove_wait_queue(&dma_q->wq, &wait); | ||
521 | try_to_freeze(); | ||
522 | } | ||
523 | |||
524 | int vivi_thread(void *data) | ||
525 | { | ||
526 | struct vivi_dmaqueue *dma_q=data; | ||
527 | |||
528 | dprintk(1,"thread started\n"); | ||
529 | |||
530 | for (;;) { | ||
531 | vivi_sleep(dma_q); | ||
532 | |||
533 | if (kthread_should_stop()) | ||
534 | break; | ||
535 | } | ||
536 | dprintk(1, "thread: exit\n"); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | int vivi_start_thread(struct vivi_dmaqueue *dma_q) | ||
541 | { | ||
542 | dma_q->frame=0; | ||
543 | dma_q->ini_jiffies=jiffies; | ||
544 | |||
545 | dprintk(1,"%s\n",__FUNCTION__); | ||
546 | init_waitqueue_head(&dma_q->wq); | ||
547 | |||
548 | dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); | ||
549 | |||
550 | if (dma_q->kthread == NULL) { | ||
551 | printk(KERN_ERR "vivi: kernel_thread() failed\n"); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | dprintk(1,"returning from %s\n",__FUNCTION__); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | void vivi_stop_thread(struct vivi_dmaqueue *dma_q) | ||
559 | { | ||
560 | dprintk(1,"%s\n",__FUNCTION__); | ||
561 | /* shutdown control thread */ | ||
562 | if (dma_q->kthread) { | ||
563 | kthread_stop(dma_q->kthread); | ||
564 | dma_q->kthread=NULL; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | static int restart_video_queue(struct vivi_dmaqueue *dma_q) | ||
569 | { | ||
570 | struct vivi_buffer *buf, *prev; | ||
571 | struct list_head *item; | ||
572 | |||
573 | dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); | ||
574 | |||
575 | if (!list_empty(&dma_q->active)) { | ||
576 | buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue); | ||
577 | dprintk(2,"restart_queue [%p/%d]: restart dma\n", | ||
578 | buf, buf->vb.i); | ||
579 | |||
580 | dprintk(1,"Restarting video dma\n"); | ||
581 | vivi_stop_thread(dma_q); | ||
582 | // vivi_start_thread(dma_q); | ||
583 | |||
584 | /* cancel all outstanding capture / vbi requests */ | ||
585 | list_for_each(item,&dma_q->active) { | ||
586 | buf = list_entry(item, struct vivi_buffer, vb.queue); | ||
587 | |||
588 | list_del(&buf->vb.queue); | ||
589 | buf->vb.state = STATE_ERROR; | ||
590 | wake_up(&buf->vb.done); | ||
591 | } | ||
592 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | prev = NULL; | ||
598 | for (;;) { | ||
599 | if (list_empty(&dma_q->queued)) | ||
600 | return 0; | ||
601 | buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue); | ||
602 | if (NULL == prev) { | ||
603 | list_del(&buf->vb.queue); | ||
604 | list_add_tail(&buf->vb.queue,&dma_q->active); | ||
605 | |||
606 | dprintk(1,"Restarting video dma\n"); | ||
607 | vivi_stop_thread(dma_q); | ||
608 | vivi_start_thread(dma_q); | ||
609 | |||
610 | buf->vb.state = STATE_ACTIVE; | ||
611 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
612 | dprintk(2,"[%p/%d] restart_queue - first active\n", | ||
613 | buf,buf->vb.i); | ||
614 | |||
615 | } else if (prev->vb.width == buf->vb.width && | ||
616 | prev->vb.height == buf->vb.height && | ||
617 | prev->fmt == buf->fmt) { | ||
618 | list_del(&buf->vb.queue); | ||
619 | list_add_tail(&buf->vb.queue,&dma_q->active); | ||
620 | buf->vb.state = STATE_ACTIVE; | ||
621 | dprintk(2,"[%p/%d] restart_queue - move to active\n", | ||
622 | buf,buf->vb.i); | ||
623 | } else { | ||
624 | return 0; | ||
625 | } | ||
626 | prev = buf; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | static void vivi_vid_timeout(unsigned long data) | ||
631 | { | ||
632 | struct vivi_dev *dev = (struct vivi_dev*)data; | ||
633 | struct vivi_dmaqueue *vidq = &dev->vidq; | ||
634 | struct vivi_buffer *buf; | ||
635 | |||
636 | while (!list_empty(&vidq->active)) { | ||
637 | buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); | ||
638 | list_del(&buf->vb.queue); | ||
639 | buf->vb.state = STATE_ERROR; | ||
640 | wake_up(&buf->vb.done); | ||
641 | printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); | ||
642 | } | ||
643 | |||
644 | restart_video_queue(vidq); | ||
645 | } | ||
646 | |||
647 | /* ------------------------------------------------------------------ | ||
648 | Videobuf operations | ||
649 | ------------------------------------------------------------------*/ | ||
650 | static int | ||
651 | buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) | ||
652 | { | ||
653 | struct vivi_fh *fh = vq->priv_data; | ||
654 | |||
655 | *size = fh->width*fh->height*2; | ||
656 | |||
657 | if (0 == *count) | ||
658 | *count = 32; | ||
659 | while (*size * *count > vid_limit * 1024 * 1024) | ||
660 | (*count)--; | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | void | ||
665 | free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) | ||
666 | { | ||
667 | dprintk(1,"%s\n",__FUNCTION__); | ||
668 | |||
669 | if (in_interrupt()) | ||
670 | BUG(); | ||
671 | |||
672 | /*FIXME: Maybe a spinlock is required here */ | ||
673 | kfree(buf->to_addr); | ||
674 | buf->to_addr=NULL; | ||
675 | |||
676 | videobuf_waiton(&buf->vb,0,0); | ||
677 | videobuf_dma_unmap(vq, &buf->vb.dma); | ||
678 | videobuf_dma_free(&buf->vb.dma); | ||
679 | buf->vb.state = STATE_NEEDS_INIT; | ||
680 | } | ||
681 | |||
682 | #define norm_maxw() 1024 | ||
683 | #define norm_maxh() 768 | ||
684 | static int | ||
685 | buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | ||
686 | enum v4l2_field field) | ||
687 | { | ||
688 | struct vivi_fh *fh = vq->priv_data; | ||
689 | struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); | ||
690 | int rc, init_buffer = 0; | ||
691 | |||
692 | // dprintk(1,"%s, field=%d\n",__FUNCTION__,field); | ||
693 | |||
694 | BUG_ON(NULL == fh->fmt); | ||
695 | if (fh->width < 48 || fh->width > norm_maxw() || | ||
696 | fh->height < 32 || fh->height > norm_maxh()) | ||
697 | return -EINVAL; | ||
698 | buf->vb.size = fh->width*fh->height*2; | ||
699 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
700 | return -EINVAL; | ||
701 | |||
702 | if (buf->fmt != fh->fmt || | ||
703 | buf->vb.width != fh->width || | ||
704 | buf->vb.height != fh->height || | ||
705 | buf->vb.field != field) { | ||
706 | buf->fmt = fh->fmt; | ||
707 | buf->vb.width = fh->width; | ||
708 | buf->vb.height = fh->height; | ||
709 | buf->vb.field = field; | ||
710 | init_buffer = 1; | ||
711 | } | ||
712 | |||
713 | if (STATE_NEEDS_INIT == buf->vb.state) { | ||
714 | if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL))) | ||
715 | goto fail; | ||
716 | } | ||
717 | |||
718 | buf->vb.state = STATE_PREPARED; | ||
719 | |||
720 | if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { | ||
721 | rc=-ENOMEM; | ||
722 | goto fail; | ||
723 | } | ||
724 | |||
725 | return 0; | ||
726 | |||
727 | fail: | ||
728 | free_buffer(vq,buf); | ||
729 | return rc; | ||
730 | } | ||
731 | |||
732 | static void | ||
733 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
734 | { | ||
735 | struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); | ||
736 | struct vivi_fh *fh = vq->priv_data; | ||
737 | struct vivi_dev *dev = fh->dev; | ||
738 | struct vivi_dmaqueue *vidq = &dev->vidq; | ||
739 | struct vivi_buffer *prev; | ||
740 | |||
741 | if (!list_empty(&vidq->queued)) { | ||
742 | dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue); | ||
743 | list_add_tail(&buf->vb.queue,&vidq->queued); | ||
744 | buf->vb.state = STATE_QUEUED; | ||
745 | dprintk(2,"[%p/%d] buffer_queue - append to queued\n", | ||
746 | buf, buf->vb.i); | ||
747 | } else if (list_empty(&vidq->active)) { | ||
748 | list_add_tail(&buf->vb.queue,&vidq->active); | ||
749 | |||
750 | buf->vb.state = STATE_ACTIVE; | ||
751 | mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); | ||
752 | dprintk(2,"[%p/%d] buffer_queue - first active\n", | ||
753 | buf, buf->vb.i); | ||
754 | |||
755 | vivi_start_thread(vidq); | ||
756 | } else { | ||
757 | prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue); | ||
758 | if (prev->vb.width == buf->vb.width && | ||
759 | prev->vb.height == buf->vb.height && | ||
760 | prev->fmt == buf->fmt) { | ||
761 | list_add_tail(&buf->vb.queue,&vidq->active); | ||
762 | buf->vb.state = STATE_ACTIVE; | ||
763 | dprintk(2,"[%p/%d] buffer_queue - append to active\n", | ||
764 | buf, buf->vb.i); | ||
765 | |||
766 | } else { | ||
767 | list_add_tail(&buf->vb.queue,&vidq->queued); | ||
768 | buf->vb.state = STATE_QUEUED; | ||
769 | dprintk(2,"[%p/%d] buffer_queue - first queued\n", | ||
770 | buf, buf->vb.i); | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
776 | { | ||
777 | struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); | ||
778 | struct vivi_fh *fh = vq->priv_data; | ||
779 | struct vivi_dev *dev = (struct vivi_dev*)fh->dev; | ||
780 | struct vivi_dmaqueue *vidq = &dev->vidq; | ||
781 | |||
782 | dprintk(1,"%s\n",__FUNCTION__); | ||
783 | |||
784 | vivi_stop_thread(vidq); | ||
785 | |||
786 | free_buffer(vq,buf); | ||
787 | } | ||
788 | |||
789 | int vivi_map_sg (void *dev, struct scatterlist *sg, int nents, | ||
790 | int direction) | ||
791 | { | ||
792 | int i; | ||
793 | |||
794 | dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents); | ||
795 | BUG_ON(direction == DMA_NONE); | ||
796 | |||
797 | for (i = 0; i < nents; i++ ) { | ||
798 | BUG_ON(!sg[i].page); | ||
799 | |||
800 | sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset; | ||
801 | } | ||
802 | |||
803 | return nents; | ||
804 | } | ||
805 | |||
806 | int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages, | ||
807 | int direction) | ||
808 | { | ||
809 | dprintk(1,"%s\n",__FUNCTION__); | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages, | ||
814 | int direction) | ||
815 | { | ||
816 | // dprintk(1,"%s\n",__FUNCTION__); | ||
817 | |||
818 | // flush_write_buffers(); | ||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | static struct videobuf_queue_ops vivi_video_qops = { | ||
823 | .buf_setup = buffer_setup, | ||
824 | .buf_prepare = buffer_prepare, | ||
825 | .buf_queue = buffer_queue, | ||
826 | .buf_release = buffer_release, | ||
827 | |||
828 | /* Non-pci handling routines */ | ||
829 | .vb_map_sg = vivi_map_sg, | ||
830 | .vb_dma_sync_sg = vivi_dma_sync_sg, | ||
831 | .vb_unmap_sg = vivi_unmap_sg, | ||
832 | }; | ||
833 | |||
834 | /* ------------------------------------------------------------------ | ||
835 | IOCTL handling | ||
836 | ------------------------------------------------------------------*/ | ||
837 | |||
838 | static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh, | ||
839 | struct v4l2_format *f) | ||
840 | { | ||
841 | struct vivi_fmt *fmt; | ||
842 | enum v4l2_field field; | ||
843 | unsigned int maxw, maxh; | ||
844 | |||
845 | if (format.fourcc != f->fmt.pix.pixelformat) { | ||
846 | dprintk(1,"Fourcc format invalid.\n"); | ||
847 | return -EINVAL; | ||
848 | } | ||
849 | fmt=&format; | ||
850 | |||
851 | field = f->fmt.pix.field; | ||
852 | |||
853 | if (field == V4L2_FIELD_ANY) { | ||
854 | // field=V4L2_FIELD_INTERLACED; | ||
855 | field=V4L2_FIELD_SEQ_TB; | ||
856 | } else if (V4L2_FIELD_INTERLACED != field) { | ||
857 | dprintk(1,"Field type invalid.\n"); | ||
858 | return -EINVAL; | ||
859 | } | ||
860 | |||
861 | maxw = norm_maxw(); | ||
862 | maxh = norm_maxh(); | ||
863 | |||
864 | f->fmt.pix.field = field; | ||
865 | if (f->fmt.pix.height < 32) | ||
866 | f->fmt.pix.height = 32; | ||
867 | if (f->fmt.pix.height > maxh) | ||
868 | f->fmt.pix.height = maxh; | ||
869 | if (f->fmt.pix.width < 48) | ||
870 | f->fmt.pix.width = 48; | ||
871 | if (f->fmt.pix.width > maxw) | ||
872 | f->fmt.pix.width = maxw; | ||
873 | f->fmt.pix.width &= ~0x03; | ||
874 | f->fmt.pix.bytesperline = | ||
875 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
876 | f->fmt.pix.sizeimage = | ||
877 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
878 | |||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | static int res_get(struct vivi_dev *dev, struct vivi_fh *fh) | ||
883 | { | ||
884 | /* is it free? */ | ||
885 | down(&dev->lock); | ||
886 | if (dev->resources) { | ||
887 | /* no, someone else uses it */ | ||
888 | up(&dev->lock); | ||
889 | return 0; | ||
890 | } | ||
891 | /* it's free, grab it */ | ||
892 | dev->resources =1; | ||
893 | dprintk(1,"res: get\n"); | ||
894 | up(&dev->lock); | ||
895 | return 1; | ||
896 | } | ||
897 | |||
898 | static inline int res_locked(struct vivi_dev *dev) | ||
899 | { | ||
900 | return (dev->resources); | ||
901 | } | ||
902 | |||
903 | static void res_free(struct vivi_dev *dev, struct vivi_fh *fh) | ||
904 | { | ||
905 | down(&dev->lock); | ||
906 | dev->resources = 0; | ||
907 | dprintk(1,"res: put\n"); | ||
908 | up(&dev->lock); | ||
909 | } | ||
910 | |||
911 | static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) | ||
912 | { | ||
913 | struct vivi_fh *fh = file->private_data; | ||
914 | struct vivi_dev *dev = fh->dev; | ||
915 | int ret=0; | ||
916 | |||
917 | if (debug) { | ||
918 | if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
919 | v4l_printk_ioctl_arg("vivi(w)",cmd, arg); | ||
920 | else if (!_IOC_DIR(cmd) & _IOC_READ) { | ||
921 | v4l_print_ioctl("vivi", cmd); | ||
922 | } | ||
923 | } | ||
924 | |||
925 | switch(cmd) { | ||
926 | /* --- capabilities ------------------------------------------ */ | ||
927 | case VIDIOC_QUERYCAP: | ||
928 | { | ||
929 | struct v4l2_capability *cap = (struct v4l2_capability*)arg; | ||
930 | |||
931 | memset(cap, 0, sizeof(*cap)); | ||
932 | |||
933 | strcpy(cap->driver, "vivi"); | ||
934 | strcpy(cap->card, "vivi"); | ||
935 | cap->version = VIVI_VERSION; | ||
936 | cap->capabilities = | ||
937 | V4L2_CAP_VIDEO_CAPTURE | | ||
938 | V4L2_CAP_STREAMING | | ||
939 | V4L2_CAP_READWRITE; | ||
940 | break; | ||
941 | } | ||
942 | /* --- capture ioctls ---------------------------------------- */ | ||
943 | case VIDIOC_ENUM_FMT: | ||
944 | { | ||
945 | struct v4l2_fmtdesc *f = arg; | ||
946 | enum v4l2_buf_type type; | ||
947 | unsigned int index; | ||
948 | |||
949 | index = f->index; | ||
950 | type = f->type; | ||
951 | |||
952 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
953 | ret=-EINVAL; | ||
954 | break; | ||
955 | } | ||
956 | |||
957 | switch (type) { | ||
958 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
959 | if (index > 0){ | ||
960 | ret=-EINVAL; | ||
961 | break; | ||
962 | } | ||
963 | memset(f,0,sizeof(*f)); | ||
964 | |||
965 | f->index = index; | ||
966 | f->type = type; | ||
967 | strlcpy(f->description,format.name,sizeof(f->description)); | ||
968 | f->pixelformat = format.fourcc; | ||
969 | break; | ||
970 | default: | ||
971 | ret=-EINVAL; | ||
972 | } | ||
973 | break; | ||
974 | } | ||
975 | case VIDIOC_G_FMT: | ||
976 | { | ||
977 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
978 | |||
979 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
980 | ret=-EINVAL; | ||
981 | break; | ||
982 | } | ||
983 | |||
984 | memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); | ||
985 | f->fmt.pix.width = fh->width; | ||
986 | f->fmt.pix.height = fh->height; | ||
987 | f->fmt.pix.field = fh->vb_vidq.field; | ||
988 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
989 | f->fmt.pix.bytesperline = | ||
990 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
991 | f->fmt.pix.sizeimage = | ||
992 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
993 | break; | ||
994 | } | ||
995 | case VIDIOC_S_FMT: | ||
996 | { | ||
997 | struct v4l2_format *f = arg; | ||
998 | |||
999 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1000 | dprintk(1,"Only capture supported.\n"); | ||
1001 | ret=-EINVAL; | ||
1002 | break; | ||
1003 | } | ||
1004 | |||
1005 | ret = vivi_try_fmt(dev,fh,f); | ||
1006 | if (ret < 0) | ||
1007 | break; | ||
1008 | |||
1009 | fh->fmt = &format; | ||
1010 | fh->width = f->fmt.pix.width; | ||
1011 | fh->height = f->fmt.pix.height; | ||
1012 | fh->vb_vidq.field = f->fmt.pix.field; | ||
1013 | fh->type = f->type; | ||
1014 | |||
1015 | break; | ||
1016 | } | ||
1017 | case VIDIOC_TRY_FMT: | ||
1018 | { | ||
1019 | struct v4l2_format *f = arg; | ||
1020 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1021 | ret=-EINVAL; | ||
1022 | break; | ||
1023 | } | ||
1024 | |||
1025 | ret=vivi_try_fmt(dev,fh,f); | ||
1026 | break; | ||
1027 | } | ||
1028 | case VIDIOC_REQBUFS: | ||
1029 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1030 | ret=-EINVAL; | ||
1031 | break; | ||
1032 | } | ||
1033 | ret=videobuf_reqbufs(&fh->vb_vidq, arg); | ||
1034 | break; | ||
1035 | case VIDIOC_QUERYBUF: | ||
1036 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1037 | ret=-EINVAL; | ||
1038 | break; | ||
1039 | } | ||
1040 | ret=videobuf_querybuf(&fh->vb_vidq, arg); | ||
1041 | break; | ||
1042 | case VIDIOC_QBUF: | ||
1043 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1044 | ret=-EINVAL; | ||
1045 | break; | ||
1046 | } | ||
1047 | ret=videobuf_qbuf(&fh->vb_vidq, arg); | ||
1048 | break; | ||
1049 | case VIDIOC_DQBUF: | ||
1050 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1051 | ret=-EINVAL; | ||
1052 | break; | ||
1053 | } | ||
1054 | ret=videobuf_dqbuf(&fh->vb_vidq, arg, | ||
1055 | file->f_flags & O_NONBLOCK); | ||
1056 | break; | ||
1057 | #ifdef HAVE_V4L1 | ||
1058 | /* --- streaming capture ------------------------------------- */ | ||
1059 | case VIDIOCGMBUF: | ||
1060 | { | ||
1061 | struct video_mbuf *mbuf = arg; | ||
1062 | struct videobuf_queue *q=&fh->vb_vidq; | ||
1063 | struct v4l2_requestbuffers req; | ||
1064 | unsigned int i; | ||
1065 | |||
1066 | memset(&req,0,sizeof(req)); | ||
1067 | req.type = q->type; | ||
1068 | req.count = 8; | ||
1069 | req.memory = V4L2_MEMORY_MMAP; | ||
1070 | ret = videobuf_reqbufs(q,&req); | ||
1071 | if (ret < 0) | ||
1072 | break; | ||
1073 | memset(mbuf,0,sizeof(*mbuf)); | ||
1074 | mbuf->frames = req.count; | ||
1075 | mbuf->size = 0; | ||
1076 | for (i = 0; i < mbuf->frames; i++) { | ||
1077 | mbuf->offsets[i] = q->bufs[i]->boff; | ||
1078 | mbuf->size += q->bufs[i]->bsize; | ||
1079 | } | ||
1080 | break; | ||
1081 | } | ||
1082 | #endif | ||
1083 | case VIDIOC_STREAMON: | ||
1084 | { | ||
1085 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1086 | return -EINVAL; | ||
1087 | if (!res_get(dev,fh)) | ||
1088 | return -EBUSY; | ||
1089 | ret=videobuf_streamon(&fh->vb_vidq); | ||
1090 | break; | ||
1091 | } | ||
1092 | case VIDIOC_STREAMOFF: | ||
1093 | { | ||
1094 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1095 | ret=-EINVAL; | ||
1096 | break; | ||
1097 | } | ||
1098 | ret = videobuf_streamoff(&fh->vb_vidq); | ||
1099 | if (ret < 0) | ||
1100 | break; | ||
1101 | res_free(dev,fh); | ||
1102 | break; | ||
1103 | } | ||
1104 | /* ---------- tv norms ---------- */ | ||
1105 | case VIDIOC_ENUMSTD: | ||
1106 | { | ||
1107 | struct v4l2_standard *e = arg; | ||
1108 | |||
1109 | if (e->index>0) { | ||
1110 | ret=-EINVAL; | ||
1111 | break; | ||
1112 | } | ||
1113 | ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M"); | ||
1114 | |||
1115 | /* Allows vivi to use different fps from video std */ | ||
1116 | e->frameperiod.numerator = WAKE_NUMERATOR; | ||
1117 | e->frameperiod.denominator = WAKE_DENOMINATOR; | ||
1118 | |||
1119 | break; | ||
1120 | } | ||
1121 | case VIDIOC_G_STD: | ||
1122 | { | ||
1123 | v4l2_std_id *id = arg; | ||
1124 | |||
1125 | *id = V4L2_STD_NTSC_M; | ||
1126 | break; | ||
1127 | } | ||
1128 | case VIDIOC_S_STD: | ||
1129 | { | ||
1130 | break; | ||
1131 | } | ||
1132 | /* ------ input switching ---------- */ | ||
1133 | case VIDIOC_ENUMINPUT: | ||
1134 | { /* only one input in this sample driver */ | ||
1135 | struct v4l2_input *inp = arg; | ||
1136 | |||
1137 | if (inp->index != 0) { | ||
1138 | ret=-EINVAL; | ||
1139 | break; | ||
1140 | } | ||
1141 | memset(inp, 0, sizeof(*inp)); | ||
1142 | |||
1143 | inp->index = 0; | ||
1144 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
1145 | inp->std = V4L2_STD_NTSC_M; | ||
1146 | strcpy(inp->name,"Camera"); | ||
1147 | break; | ||
1148 | } | ||
1149 | case VIDIOC_G_INPUT: | ||
1150 | { | ||
1151 | unsigned int *i = arg; | ||
1152 | |||
1153 | *i = 0; | ||
1154 | break; | ||
1155 | } | ||
1156 | case VIDIOC_S_INPUT: | ||
1157 | { | ||
1158 | unsigned int *i = arg; | ||
1159 | |||
1160 | if (*i > 0) | ||
1161 | ret=-EINVAL; | ||
1162 | break; | ||
1163 | } | ||
1164 | |||
1165 | /* --- controls ---------------------------------------------- */ | ||
1166 | case VIDIOC_QUERYCTRL: | ||
1167 | { | ||
1168 | struct v4l2_queryctrl *qc = arg; | ||
1169 | int i; | ||
1170 | |||
1171 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | ||
1172 | if (qc->id && qc->id == vivi_qctrl[i].id) { | ||
1173 | memcpy(qc, &(vivi_qctrl[i]), | ||
1174 | sizeof(*qc)); | ||
1175 | break; | ||
1176 | } | ||
1177 | |||
1178 | ret=-EINVAL; | ||
1179 | break; | ||
1180 | } | ||
1181 | case VIDIOC_G_CTRL: | ||
1182 | { | ||
1183 | struct v4l2_control *ctrl = arg; | ||
1184 | int i; | ||
1185 | |||
1186 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | ||
1187 | if (ctrl->id == vivi_qctrl[i].id) { | ||
1188 | ctrl->value=qctl_regs[i]; | ||
1189 | break; | ||
1190 | } | ||
1191 | |||
1192 | ret=-EINVAL; | ||
1193 | break; | ||
1194 | } | ||
1195 | case VIDIOC_S_CTRL: | ||
1196 | { | ||
1197 | struct v4l2_control *ctrl = arg; | ||
1198 | int i; | ||
1199 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | ||
1200 | if (ctrl->id == vivi_qctrl[i].id) { | ||
1201 | if (ctrl->value < | ||
1202 | vivi_qctrl[i].minimum | ||
1203 | || ctrl->value > | ||
1204 | vivi_qctrl[i].maximum) { | ||
1205 | ret=-ERANGE; | ||
1206 | break; | ||
1207 | } | ||
1208 | qctl_regs[i]=ctrl->value; | ||
1209 | break; | ||
1210 | } | ||
1211 | ret=-EINVAL; | ||
1212 | break; | ||
1213 | } | ||
1214 | default: | ||
1215 | ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl); | ||
1216 | } | ||
1217 | |||
1218 | if (debug) { | ||
1219 | if (ret<0) { | ||
1220 | v4l_print_ioctl("vivi(err)", cmd); | ||
1221 | dprintk(1,"errcode=%d\n",ret); | ||
1222 | } else if (_IOC_DIR(cmd) & _IOC_READ) | ||
1223 | v4l_printk_ioctl_arg("vivi(r)",cmd, arg); | ||
1224 | } | ||
1225 | |||
1226 | return ret; | ||
1227 | } | ||
1228 | |||
1229 | static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
1230 | { | ||
1231 | return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl); | ||
1232 | } | ||
1233 | |||
1234 | /* ------------------------------------------------------------------ | ||
1235 | File operations for the device | ||
1236 | ------------------------------------------------------------------*/ | ||
1237 | |||
1238 | #define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8) | ||
1239 | |||
1240 | static int vivi_open(struct inode *inode, struct file *file) | ||
1241 | { | ||
1242 | int minor = iminor(inode); | ||
1243 | struct vivi_dev *h,*dev = NULL; | ||
1244 | struct vivi_fh *fh; | ||
1245 | struct list_head *list; | ||
1246 | enum v4l2_buf_type type = 0; | ||
1247 | int i; | ||
1248 | |||
1249 | printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); | ||
1250 | |||
1251 | list_for_each(list,&vivi_devlist) { | ||
1252 | h = list_entry(list, struct vivi_dev, vivi_devlist); | ||
1253 | if (h->video_dev.minor == minor) { | ||
1254 | dev = h; | ||
1255 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1256 | } | ||
1257 | } | ||
1258 | if (NULL == dev) | ||
1259 | return -ENODEV; | ||
1260 | |||
1261 | |||
1262 | /* If more than one user, mutex should be added */ | ||
1263 | dev->users++; | ||
1264 | |||
1265 | dprintk(1,"open minor=%d type=%s users=%d\n", | ||
1266 | minor,v4l2_type_names[type],dev->users); | ||
1267 | |||
1268 | /* allocate + initialize per filehandle data */ | ||
1269 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | ||
1270 | if (NULL == fh) { | ||
1271 | dev->users--; | ||
1272 | return -ENOMEM; | ||
1273 | } | ||
1274 | |||
1275 | file->private_data = fh; | ||
1276 | fh->dev = dev; | ||
1277 | fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1278 | fh->fmt = &format; | ||
1279 | fh->width = 640; | ||
1280 | fh->height = 480; | ||
1281 | |||
1282 | /* Put all controls at a sane state */ | ||
1283 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | ||
1284 | qctl_regs[i] =vivi_qctrl[i].default_value; | ||
1285 | |||
1286 | dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", | ||
1287 | (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq); | ||
1288 | dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued)); | ||
1289 | dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active)); | ||
1290 | |||
1291 | /* Resets frame counters */ | ||
1292 | dev->h=0; | ||
1293 | dev->m=0; | ||
1294 | dev->s=0; | ||
1295 | dev->us=0; | ||
1296 | dev->jiffies=jiffies; | ||
1297 | sprintf(dev->timestr,"%02d:%02d:%02d:%03d", | ||
1298 | dev->h,dev->m,dev->s,(dev->us+500)/1000); | ||
1299 | |||
1300 | videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, | ||
1301 | NULL, NULL, | ||
1302 | fh->type, | ||
1303 | V4L2_FIELD_INTERLACED, | ||
1304 | sizeof(struct vivi_buffer),fh); | ||
1305 | |||
1306 | return 0; | ||
1307 | } | ||
1308 | |||
1309 | static ssize_t | ||
1310 | vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
1311 | { | ||
1312 | struct vivi_fh *fh = file->private_data; | ||
1313 | |||
1314 | if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1315 | if (res_locked(fh->dev)) | ||
1316 | return -EBUSY; | ||
1317 | return videobuf_read_one(&fh->vb_vidq, data, count, ppos, | ||
1318 | file->f_flags & O_NONBLOCK); | ||
1319 | } | ||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | static unsigned int | ||
1324 | vivi_poll(struct file *file, struct poll_table_struct *wait) | ||
1325 | { | ||
1326 | struct vivi_fh *fh = file->private_data; | ||
1327 | struct vivi_buffer *buf; | ||
1328 | |||
1329 | dprintk(1,"%s\n",__FUNCTION__); | ||
1330 | |||
1331 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) | ||
1332 | return POLLERR; | ||
1333 | |||
1334 | if (res_get(fh->dev,fh)) { | ||
1335 | dprintk(1,"poll: mmap interface\n"); | ||
1336 | /* streaming capture */ | ||
1337 | if (list_empty(&fh->vb_vidq.stream)) | ||
1338 | return POLLERR; | ||
1339 | buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream); | ||
1340 | } else { | ||
1341 | dprintk(1,"poll: read() interface\n"); | ||
1342 | /* read() capture */ | ||
1343 | buf = (struct vivi_buffer*)fh->vb_vidq.read_buf; | ||
1344 | if (NULL == buf) | ||
1345 | return POLLERR; | ||
1346 | } | ||
1347 | poll_wait(file, &buf->vb.done, wait); | ||
1348 | if (buf->vb.state == STATE_DONE || | ||
1349 | buf->vb.state == STATE_ERROR) | ||
1350 | return POLLIN|POLLRDNORM; | ||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | static int vivi_release(struct inode *inode, struct file *file) | ||
1355 | { | ||
1356 | struct vivi_fh *fh = file->private_data; | ||
1357 | struct vivi_dev *dev = fh->dev; | ||
1358 | struct vivi_dmaqueue *vidq = &dev->vidq; | ||
1359 | |||
1360 | int minor = iminor(inode); | ||
1361 | |||
1362 | vivi_stop_thread(vidq); | ||
1363 | videobuf_mmap_free(&fh->vb_vidq); | ||
1364 | |||
1365 | kfree (fh); | ||
1366 | |||
1367 | dev->users--; | ||
1368 | |||
1369 | printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users); | ||
1370 | |||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | static int | ||
1375 | vivi_mmap(struct file *file, struct vm_area_struct * vma) | ||
1376 | { | ||
1377 | struct vivi_fh *fh = file->private_data; | ||
1378 | int ret; | ||
1379 | |||
1380 | dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma); | ||
1381 | |||
1382 | ret=videobuf_mmap_mapper(&fh->vb_vidq, vma); | ||
1383 | |||
1384 | dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n", | ||
1385 | (unsigned long)vma->vm_start, | ||
1386 | (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, | ||
1387 | ret); | ||
1388 | |||
1389 | return ret; | ||
1390 | } | ||
1391 | |||
1392 | static struct file_operations vivi_fops = { | ||
1393 | .owner = THIS_MODULE, | ||
1394 | .open = vivi_open, | ||
1395 | .release = vivi_release, | ||
1396 | .read = vivi_read, | ||
1397 | .poll = vivi_poll, | ||
1398 | .ioctl = vivi_ioctl, | ||
1399 | .mmap = vivi_mmap, | ||
1400 | .llseek = no_llseek, | ||
1401 | }; | ||
1402 | |||
1403 | static struct video_device vivi = { | ||
1404 | .name = "VTM Virtual Video Capture Board", | ||
1405 | .type = VID_TYPE_CAPTURE, | ||
1406 | .hardware = 0, | ||
1407 | .fops = &vivi_fops, | ||
1408 | .minor = -1, | ||
1409 | // .release = video_device_release, | ||
1410 | }; | ||
1411 | /* ------------------------------------------------------------------ | ||
1412 | Initialization and module stuff | ||
1413 | ------------------------------------------------------------------*/ | ||
1414 | |||
1415 | static int __init vivi_init(void) | ||
1416 | { | ||
1417 | int ret; | ||
1418 | struct vivi_dev *dev; | ||
1419 | |||
1420 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | ||
1421 | if (NULL == dev) | ||
1422 | return -ENOMEM; | ||
1423 | list_add_tail(&dev->vivi_devlist,&vivi_devlist); | ||
1424 | |||
1425 | /* init video dma queues */ | ||
1426 | INIT_LIST_HEAD(&dev->vidq.active); | ||
1427 | INIT_LIST_HEAD(&dev->vidq.queued); | ||
1428 | |||
1429 | /* initialize locks */ | ||
1430 | init_MUTEX(&dev->lock); | ||
1431 | |||
1432 | dev->vidq.timeout.function = vivi_vid_timeout; | ||
1433 | dev->vidq.timeout.data = (unsigned long)dev; | ||
1434 | init_timer(&dev->vidq.timeout); | ||
1435 | |||
1436 | ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr); | ||
1437 | printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | static void __exit vivi_exit(void) | ||
1442 | { | ||
1443 | struct vivi_dev *h; | ||
1444 | struct list_head *list; | ||
1445 | |||
1446 | list_for_each(list,&vivi_devlist) { | ||
1447 | h = list_entry(list, struct vivi_dev, vivi_devlist); | ||
1448 | kfree (h); | ||
1449 | } | ||
1450 | video_unregister_device(&vivi); | ||
1451 | } | ||
1452 | |||
1453 | module_init(vivi_init); | ||
1454 | module_exit(vivi_exit); | ||