2006-03-10 18:40:10 +03:00
/*
* Virtual Video driver - This code emulates a real video device with v4l2 api
*
* Copyright ( c ) 2006 by :
* Mauro Carvalho Chehab < mchehab - - a . t - - infradead . org >
* Ted Walther < ted - - a . t - - enumera . com >
* John Sokol < sokol - - a . t - - videotechnology . com >
* http : //v4l.videotechnology.com/
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the BSD Licence , GNU General Public License
* as published by the Free Software Foundation ; either version 2 of the
* License , or ( at your option ) any later version
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/sched.h>
# include <linux/pci.h>
# include <linux/random.h>
# include <linux/version.h>
2007-07-02 17:19:38 +04:00
# include <linux/mutex.h>
2006-03-10 18:40:10 +03:00
# include <linux/videodev2.h>
2006-04-27 17:10:58 +04:00
# include <linux/dma-mapping.h>
2006-04-09 22:43:41 +04:00
# ifdef CONFIG_VIDEO_V4L1_COMPAT
/* Include V4L1 specific functions. Should be removed soon */
# include <linux/videodev.h>
# endif
2006-03-24 04:01:44 +03:00
# include <linux/interrupt.h>
2007-08-03 06:31:54 +04:00
# include <media/videobuf-vmalloc.h>
2006-03-10 18:40:10 +03:00
# include <media/v4l2-common.h>
2008-07-20 15:12:02 +04:00
# include <media/v4l2-ioctl.h>
2006-03-10 18:40:10 +03:00
# include <linux/kthread.h>
# include <linux/highmem.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2006-03-10 18:40:10 +03:00
2008-06-10 22:21:49 +04:00
# define VIVI_MODULE_NAME "vivi"
2008-06-10 07:02:32 +04:00
2006-03-10 18:40:10 +03:00
/* Wake up at about 30 fps */
# define WAKE_NUMERATOR 30
# define WAKE_DENOMINATOR 1001
# define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
# include "font.h"
# define VIVI_MAJOR_VERSION 0
2008-06-10 07:02:32 +04:00
# define VIVI_MINOR_VERSION 5
2006-03-10 18:40:10 +03:00
# define VIVI_RELEASE 0
2007-12-10 15:33:52 +03:00
# define VIVI_VERSION \
KERNEL_VERSION ( VIVI_MAJOR_VERSION , VIVI_MINOR_VERSION , VIVI_RELEASE )
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16 ; /* Video memory limit, in Mb */
static int video_nr = - 1 ; /* /dev/videoN, -1 for autodetect */
2007-12-10 10:38:11 +03:00
static int n_devs = 1 ; /* Number of virtual devices */
2006-03-10 18:40:10 +03:00
/* supported controls */
static struct v4l2_queryctrl vivi_qctrl [ ] = {
{
. id = V4L2_CID_AUDIO_VOLUME ,
. name = " Volume " ,
. minimum = 0 ,
. maximum = 65535 ,
. step = 65535 / 100 ,
. default_value = 65535 ,
. flags = 0 ,
. type = V4L2_CTRL_TYPE_INTEGER ,
2007-12-10 15:33:52 +03:00
} , {
2006-03-10 18:40:10 +03:00
. id = V4L2_CID_BRIGHTNESS ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Brightness " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 1 ,
. default_value = 127 ,
. flags = 0 ,
} , {
. id = V4L2_CID_CONTRAST ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Contrast " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
. default_value = 0x10 ,
. flags = 0 ,
} , {
. id = V4L2_CID_SATURATION ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Saturation " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
. default_value = 127 ,
. flags = 0 ,
} , {
. id = V4L2_CID_HUE ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Hue " ,
. minimum = - 128 ,
. maximum = 127 ,
. step = 0x1 ,
. default_value = 0 ,
. flags = 0 ,
}
} ;
static int qctl_regs [ ARRAY_SIZE ( vivi_qctrl ) ] ;
2007-12-13 19:30:14 +03:00
# define dprintk(dev, level, fmt, arg...) \
2006-06-04 17:34:12 +04:00
do { \
2007-12-13 19:30:14 +03:00
if ( dev - > vfd - > debug > = ( level ) ) \
2006-06-04 17:34:12 +04:00
printk ( KERN_DEBUG " vivi: " fmt , # # arg ) ; \
2006-03-10 18:40:10 +03:00
} while ( 0 )
/* ------------------------------------------------------------------
Basic structures
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
struct vivi_fmt {
char * name ;
u32 fourcc ; /* v4l2 format id */
int depth ;
} ;
static struct vivi_fmt format = {
. name = " 4:2:2, packed, YUYV " ,
. fourcc = V4L2_PIX_FMT_YUYV ,
. depth = 16 ,
} ;
struct sg_to_addr {
int pos ;
struct scatterlist * sg ;
} ;
/* buffer for one video frame */
struct vivi_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb ;
struct vivi_fmt * fmt ;
} ;
struct vivi_dmaqueue {
struct list_head active ;
/* thread for generating video stream*/
struct task_struct * kthread ;
wait_queue_head_t wq ;
/* Counters to control fps rate */
int frame ;
int ini_jiffies ;
} ;
static LIST_HEAD ( vivi_devlist ) ;
struct vivi_dev {
struct list_head vivi_devlist ;
2007-12-13 22:13:37 +03:00
spinlock_t slock ;
2008-04-03 01:10:59 +04:00
struct mutex mutex ;
2006-03-10 18:40:10 +03:00
int users ;
/* various device info */
2007-12-10 10:07:03 +03:00
struct video_device * vfd ;
2006-03-10 18:40:10 +03:00
struct vivi_dmaqueue vidq ;
/* Several counters */
2008-01-14 01:36:11 +03:00
int h , m , s , ms ;
unsigned long jiffies ;
2006-03-10 18:40:10 +03:00
char timestr [ 13 ] ;
2007-12-10 10:43:38 +03:00
int mv_count ; /* Controls bars movement */
2006-03-10 18:40:10 +03:00
} ;
struct vivi_fh {
struct vivi_dev * dev ;
/* video capture */
struct vivi_fmt * fmt ;
2007-12-10 15:33:52 +03:00
unsigned int width , height ;
2006-03-10 18:40:10 +03:00
struct videobuf_queue vb_vidq ;
enum v4l2_buf_type type ;
} ;
/* ------------------------------------------------------------------
DMA and thread functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Bars and Colors should match positions */
enum colors {
WHITE ,
AMBAR ,
CYAN ,
GREEN ,
MAGENTA ,
RED ,
2007-12-10 15:33:52 +03:00
BLUE ,
BLACK ,
2006-03-10 18:40:10 +03:00
} ;
static u8 bars [ 8 ] [ 3 ] = {
/* R G B */
2007-12-10 15:33:52 +03:00
{ 204 , 204 , 204 } , /* white */
{ 208 , 208 , 0 } , /* ambar */
{ 0 , 206 , 206 } , /* cyan */
{ 0 , 239 , 0 } , /* green */
{ 239 , 0 , 239 } , /* magenta */
{ 205 , 0 , 0 } , /* red */
{ 0 , 0 , 255 } , /* blue */
{ 0 , 0 , 0 } , /* black */
2006-03-10 18:40:10 +03:00
} ;
2007-12-10 15:33:52 +03:00
# define TO_Y(r, g, b) \
( ( ( 16829 * r + 33039 * g + 6416 * b + 32768 ) > > 16 ) + 16 )
2006-03-10 18:40:10 +03:00
/* RGB to V(Cr) Color transform */
2007-12-10 15:33:52 +03:00
# define TO_V(r, g, b) \
( ( ( 28784 * r - 24103 * g - 4681 * b + 32768 ) > > 16 ) + 128 )
2006-03-10 18:40:10 +03:00
/* RGB to U(Cb) Color transform */
2007-12-10 15:33:52 +03:00
# define TO_U(r, g, b) \
( ( ( - 9714 * r - 19070 * g + 28784 * b + 32768 ) > > 16 ) + 128 )
2006-03-10 18:40:10 +03:00
# define TSTAMP_MIN_Y 24
# define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
# define TSTAMP_MIN_X 64
2007-12-10 15:33:52 +03:00
static void gen_line ( char * basep , int inipos , int wmax ,
int hmax , int line , int count , char * timestr )
2006-03-10 18:40:10 +03:00
{
2007-12-10 15:33:52 +03:00
int w , i , j , y ;
int pos = inipos ;
char * p , * s ;
u8 chr , r , g , b , color ;
2006-03-10 18:40:10 +03:00
/* We will just duplicate the second pixel at the packet */
2007-12-10 15:33:52 +03:00
wmax / = 2 ;
2006-03-10 18:40:10 +03:00
/* Generate a standard color bar pattern */
2007-12-10 15:33:52 +03:00
for ( w = 0 ; w < wmax ; w + + ) {
int colorpos = ( ( w + count ) * 8 / ( wmax + 1 ) ) % 8 ;
r = bars [ colorpos ] [ 0 ] ;
g = bars [ colorpos ] [ 1 ] ;
b = bars [ colorpos ] [ 2 ] ;
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
for ( color = 0 ; color < 4 ; color + + ) {
p = basep + pos ;
2006-03-10 18:40:10 +03:00
switch ( color ) {
2007-12-10 15:33:52 +03:00
case 0 :
case 2 :
* p = TO_Y ( r , g , b ) ; /* Luma */
break ;
case 1 :
* p = TO_U ( r , g , b ) ; /* Cb */
break ;
case 3 :
* p = TO_V ( r , g , b ) ; /* Cr */
break ;
2006-03-10 18:40:10 +03:00
}
pos + + ;
}
}
/* Checks if it is possible to show timestamp */
2007-12-10 15:33:52 +03:00
if ( TSTAMP_MAX_Y > = hmax )
2006-03-10 18:40:10 +03:00
goto end ;
2007-12-10 15:33:52 +03:00
if ( TSTAMP_MIN_X + strlen ( timestr ) > = wmax )
2006-03-10 18:40:10 +03:00
goto end ;
/* Print stream time */
2007-12-10 15:33:52 +03:00
if ( line > = TSTAMP_MIN_Y & & line < = TSTAMP_MAX_Y ) {
j = TSTAMP_MIN_X ;
for ( s = timestr ; * s ; s + + ) {
chr = rom8x16_bits [ ( * s - 0x30 ) * 16 + line - TSTAMP_MIN_Y ] ;
for ( i = 0 ; i < 7 ; i + + ) {
if ( chr & 1 < < ( 7 - i ) ) {
/* Font color*/
r = 0 ;
g = 198 ;
b = 0 ;
} else {
/* Background color */
r = bars [ BLACK ] [ 0 ] ;
g = bars [ BLACK ] [ 1 ] ;
b = bars [ BLACK ] [ 2 ] ;
2006-03-10 18:40:10 +03:00
}
2007-12-10 15:33:52 +03:00
pos = inipos + j * 2 ;
for ( color = 0 ; color < 4 ; color + + ) {
p = basep + pos ;
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
y = TO_Y ( r , g , b ) ;
2006-03-10 18:40:10 +03:00
switch ( color ) {
2007-12-10 15:33:52 +03:00
case 0 :
case 2 :
* p = TO_Y ( r , g , b ) ; /* Luma */
break ;
case 1 :
* p = TO_U ( r , g , b ) ; /* Cb */
break ;
case 3 :
* p = TO_V ( r , g , b ) ; /* Cr */
break ;
2006-03-10 18:40:10 +03:00
}
pos + + ;
}
j + + ;
}
}
}
end :
2007-01-25 11:00:01 +03:00
return ;
2006-03-10 18:40:10 +03:00
}
2008-04-03 01:10:59 +04:00
2007-12-10 15:33:52 +03:00
static void vivi_fillbuff ( struct vivi_dev * dev , struct vivi_buffer * buf )
2006-03-10 18:40:10 +03:00
{
2007-12-10 15:33:52 +03:00
int h , pos = 0 ;
2006-03-10 18:40:10 +03:00
int hmax = buf - > vb . height ;
int wmax = buf - > vb . width ;
struct timeval ts ;
2008-06-22 16:11:40 +04:00
char * tmpbuf ;
2007-12-10 15:33:52 +03:00
void * vbuf = videobuf_to_vmalloc ( & buf - > vb ) ;
2007-01-25 11:00:01 +03:00
2008-06-22 16:11:40 +04:00
if ( ! vbuf )
2007-08-03 06:31:54 +04:00
return ;
2006-03-10 18:40:10 +03:00
2008-06-22 16:11:40 +04:00
tmpbuf = kmalloc ( wmax * 2 , GFP_ATOMIC ) ;
if ( ! tmpbuf )
2008-04-03 01:10:59 +04:00
return ;
2007-12-10 15:33:52 +03:00
for ( h = 0 ; h < hmax ; h + + ) {
2007-12-10 10:43:38 +03:00
gen_line ( tmpbuf , 0 , wmax , hmax , h , dev - > mv_count ,
2007-09-22 09:01:33 +04:00
dev - > timestr ) ;
2008-04-03 01:10:59 +04:00
memcpy ( vbuf + pos , tmpbuf , wmax * 2 ) ;
2006-03-10 18:40:10 +03:00
pos + = wmax * 2 ;
}
2007-12-10 10:43:38 +03:00
dev - > mv_count + + ;
2007-09-22 09:01:33 +04:00
2007-08-03 06:31:54 +04:00
kfree ( tmpbuf ) ;
2006-03-10 18:40:10 +03:00
/* Updates stream time */
2008-01-14 01:36:11 +03:00
dev - > ms + = jiffies_to_msecs ( jiffies - dev - > jiffies ) ;
2007-12-10 15:33:52 +03:00
dev - > jiffies = jiffies ;
2008-01-14 01:36:11 +03:00
if ( dev - > ms > = 1000 ) {
dev - > ms - = 1000 ;
2006-03-10 18:40:10 +03:00
dev - > s + + ;
2007-12-10 15:33:52 +03:00
if ( dev - > s > = 60 ) {
dev - > s - = 60 ;
2006-03-10 18:40:10 +03:00
dev - > m + + ;
2007-12-10 15:33:52 +03:00
if ( dev - > m > 60 ) {
dev - > m - = 60 ;
2006-03-10 18:40:10 +03:00
dev - > h + + ;
2007-12-10 15:33:52 +03:00
if ( dev - > h > 24 )
dev - > h - = 24 ;
2006-03-10 18:40:10 +03:00
}
}
}
2007-12-10 15:33:52 +03:00
sprintf ( dev - > timestr , " %02d:%02d:%02d:%03d " ,
2008-01-14 01:36:11 +03:00
dev - > h , dev - > m , dev - > s , dev - > ms ) ;
2006-03-10 18:40:10 +03:00
2007-12-13 19:30:14 +03:00
dprintk ( dev , 2 , " vivifill at %s: Buffer 0x%08lx size= %d \n " ,
dev - > timestr , ( unsigned long ) tmpbuf , pos ) ;
2006-03-10 18:40:10 +03:00
/* Advice that buffer was filled */
buf - > vb . field_count + + ;
do_gettimeofday ( & ts ) ;
buf - > vb . ts = ts ;
2008-04-03 01:10:59 +04:00
buf - > vb . state = VIDEOBUF_DONE ;
2006-03-10 18:40:10 +03:00
}
2008-04-03 01:10:59 +04:00
static void vivi_thread_tick ( struct vivi_fh * fh )
2006-03-10 18:40:10 +03:00
{
2008-04-03 01:10:59 +04:00
struct vivi_buffer * buf ;
struct vivi_dev * dev = fh - > dev ;
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
unsigned long flags = 0 ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
dprintk ( dev , 1 , " Thread tick \n " ) ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
spin_lock_irqsave ( & dev - > slock , flags ) ;
if ( list_empty ( & dma_q - > active ) ) {
dprintk ( dev , 1 , " No active queue to serve \n " ) ;
goto unlock ;
}
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
buf = list_entry ( dma_q - > active . next ,
struct vivi_buffer , vb . queue ) ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
/* Nobody is waiting on this buffer, return */
if ( ! waitqueue_active ( & buf - > vb . done ) )
goto unlock ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
list_del ( & buf - > vb . queue ) ;
2007-01-14 14:33:24 +03:00
2008-04-03 01:10:59 +04:00
do_gettimeofday ( & buf - > vb . ts ) ;
/* Fill buffer */
vivi_fillbuff ( dev , buf ) ;
dprintk ( dev , 1 , " filled buffer %p \n " , buf ) ;
wake_up ( & buf - > vb . done ) ;
dprintk ( dev , 2 , " [%p/%d] wakeup \n " , buf , buf - > vb . i ) ;
unlock :
spin_unlock_irqrestore ( & dev - > slock , flags ) ;
return ;
2006-03-10 18:40:10 +03:00
}
2007-12-13 22:15:41 +03:00
# define frames_to_ms(frames) \
( ( frames * WAKE_NUMERATOR * 1000 ) / WAKE_DENOMINATOR )
2008-04-03 01:10:59 +04:00
static void vivi_sleep ( struct vivi_fh * fh )
2006-03-10 18:40:10 +03:00
{
2008-04-03 01:10:59 +04:00
struct vivi_dev * dev = fh - > dev ;
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
int timeout ;
2006-03-10 18:40:10 +03:00
DECLARE_WAITQUEUE ( wait , current ) ;
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s dma_q=0x%08lx \n " , __func__ ,
2007-12-13 19:30:14 +03:00
( unsigned long ) dma_q ) ;
2006-03-10 18:40:10 +03:00
add_wait_queue ( & dma_q - > wq , & wait ) ;
2007-12-13 22:15:41 +03:00
if ( kthread_should_stop ( ) )
goto stop_task ;
/* Calculate time to wake up */
2008-04-03 01:10:59 +04:00
timeout = msecs_to_jiffies ( frames_to_ms ( 1 ) ) ;
2007-12-13 22:15:41 +03:00
2008-04-03 01:10:59 +04:00
vivi_thread_tick ( fh ) ;
2007-12-13 22:15:41 +03:00
schedule_timeout_interruptible ( timeout ) ;
2006-03-10 18:40:10 +03:00
2007-12-13 22:15:41 +03:00
stop_task :
2006-03-10 18:40:10 +03:00
remove_wait_queue ( & dma_q - > wq , & wait ) ;
try_to_freeze ( ) ;
}
2006-04-28 04:06:50 +04:00
static int vivi_thread ( void * data )
2006-03-10 18:40:10 +03:00
{
2008-04-03 01:10:59 +04:00
struct vivi_fh * fh = data ;
struct vivi_dev * dev = fh - > dev ;
2006-03-10 18:40:10 +03:00
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " thread started \n " ) ;
2006-03-10 18:40:10 +03:00
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2007-01-14 14:33:24 +03:00
2006-03-10 18:40:10 +03:00
for ( ; ; ) {
2008-04-03 01:10:59 +04:00
vivi_sleep ( fh ) ;
2006-03-10 18:40:10 +03:00
if ( kthread_should_stop ( ) )
break ;
}
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " thread: exit \n " ) ;
2006-03-10 18:40:10 +03:00
return 0 ;
}
2008-04-03 01:10:59 +04:00
static int vivi_start_thread ( struct vivi_fh * fh )
2006-03-10 18:40:10 +03:00
{
2008-04-03 01:10:59 +04:00
struct vivi_dev * dev = fh - > dev ;
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
2007-12-13 19:30:14 +03:00
2007-12-10 15:33:52 +03:00
dma_q - > frame = 0 ;
dma_q - > ini_jiffies = jiffies ;
2006-03-10 18:40:10 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
dma_q - > kthread = kthread_run ( vivi_thread , fh , " vivi " ) ;
2006-03-10 18:40:10 +03:00
2006-12-20 16:04:00 +03:00
if ( IS_ERR ( dma_q - > kthread ) ) {
2006-03-10 18:40:10 +03:00
printk ( KERN_ERR " vivi: kernel_thread() failed \n " ) ;
2006-12-20 16:04:00 +03:00
return PTR_ERR ( dma_q - > kthread ) ;
2006-03-10 18:40:10 +03:00
}
2007-01-14 14:33:24 +03:00
/* Wakes thread */
wake_up_interruptible ( & dma_q - > wq ) ;
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " returning from %s \n " , __func__ ) ;
2006-03-10 18:40:10 +03:00
return 0 ;
}
2006-04-28 04:06:50 +04:00
static void vivi_stop_thread ( struct vivi_dmaqueue * dma_q )
2006-03-10 18:40:10 +03:00
{
2007-12-13 19:30:14 +03:00
struct vivi_dev * dev = container_of ( dma_q , struct vivi_dev , vidq ) ;
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 18:40:10 +03:00
/* shutdown control thread */
if ( dma_q - > kthread ) {
kthread_stop ( dma_q - > kthread ) ;
2007-12-10 15:33:52 +03:00
dma_q - > kthread = NULL ;
2006-03-10 18:40:10 +03:00
}
}
/* ------------------------------------------------------------------
Videobuf operations
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
buffer_setup ( struct videobuf_queue * vq , unsigned int * count , unsigned int * size )
{
2007-12-13 19:30:14 +03:00
struct vivi_fh * fh = vq - > priv_data ;
struct vivi_dev * dev = fh - > dev ;
2006-03-10 18:40:10 +03:00
* size = fh - > width * fh - > height * 2 ;
if ( 0 = = * count )
* count = 32 ;
2007-08-23 23:41:14 +04:00
2006-03-10 18:40:10 +03:00
while ( * size * * count > vid_limit * 1024 * 1024 )
( * count ) - - ;
2007-08-23 23:41:14 +04:00
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s, count=%d, size=%d \n " , __func__ ,
2007-12-13 19:30:14 +03:00
* count , * size ) ;
2007-08-23 23:41:14 +04:00
2006-03-10 18:40:10 +03:00
return 0 ;
}
2006-04-28 04:06:50 +04:00
static void free_buffer ( struct videobuf_queue * vq , struct vivi_buffer * buf )
2006-03-10 18:40:10 +03:00
{
2007-12-13 19:30:14 +03:00
struct vivi_fh * fh = vq - > priv_data ;
struct vivi_dev * dev = fh - > dev ;
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s, state: %i \n " , __func__ , buf - > vb . state ) ;
2006-03-10 18:40:10 +03:00
if ( in_interrupt ( ) )
BUG ( ) ;
2007-08-03 06:31:54 +04:00
videobuf_vmalloc_free ( & buf - > vb ) ;
2008-04-13 21:57:44 +04:00
dprintk ( dev , 1 , " free_buffer: freed \n " ) ;
2007-11-07 02:02:36 +03:00
buf - > vb . state = VIDEOBUF_NEEDS_INIT ;
2006-03-10 18:40:10 +03:00
}
# define norm_maxw() 1024
# define norm_maxh() 768
static int
buffer_prepare ( struct videobuf_queue * vq , struct videobuf_buffer * vb ,
enum v4l2_field field )
{
struct vivi_fh * fh = vq - > priv_data ;
2007-12-13 19:30:14 +03:00
struct vivi_dev * dev = fh - > dev ;
2007-12-10 15:33:52 +03:00
struct vivi_buffer * buf = container_of ( vb , struct vivi_buffer , vb ) ;
2008-04-03 01:10:59 +04:00
int rc ;
2006-03-10 18:40:10 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s, field=%d \n " , __func__ , field ) ;
2006-03-10 18:40:10 +03:00
BUG_ON ( NULL = = fh - > fmt ) ;
2008-04-03 01:10:59 +04:00
2006-03-10 18:40:10 +03:00
if ( fh - > width < 48 | | fh - > width > norm_maxw ( ) | |
fh - > height < 32 | | fh - > height > norm_maxh ( ) )
return - EINVAL ;
2008-04-03 01:10:59 +04:00
2006-03-10 18:40:10 +03:00
buf - > vb . size = fh - > width * fh - > height * 2 ;
if ( 0 ! = buf - > vb . baddr & & buf - > vb . bsize < buf - > vb . size )
return - EINVAL ;
2008-04-03 01:10:59 +04:00
/* These properties only change when queue is idle, see s_fmt */
buf - > fmt = fh - > fmt ;
buf - > vb . width = fh - > width ;
buf - > vb . height = fh - > height ;
buf - > vb . field = field ;
2006-03-10 18:40:10 +03:00
2007-11-07 02:02:36 +03:00
if ( VIDEOBUF_NEEDS_INIT = = buf - > vb . state ) {
2007-12-10 15:33:52 +03:00
rc = videobuf_iolock ( vq , & buf - > vb , NULL ) ;
if ( rc < 0 )
2006-03-10 18:40:10 +03:00
goto fail ;
}
2007-11-07 02:02:36 +03:00
buf - > vb . state = VIDEOBUF_PREPARED ;
2006-03-10 18:40:10 +03:00
return 0 ;
fail :
2007-12-10 15:33:52 +03:00
free_buffer ( vq , buf ) ;
2006-03-10 18:40:10 +03:00
return rc ;
}
static void
buffer_queue ( struct videobuf_queue * vq , struct videobuf_buffer * vb )
{
2007-12-10 15:33:52 +03:00
struct vivi_buffer * buf = container_of ( vb , struct vivi_buffer , vb ) ;
struct vivi_fh * fh = vq - > priv_data ;
struct vivi_dev * dev = fh - > dev ;
2008-04-03 01:10:59 +04:00
struct vivi_dmaqueue * vidq = & dev - > vidq ;
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2008-04-03 01:10:59 +04:00
buf - > vb . state = VIDEOBUF_QUEUED ;
list_add_tail ( & buf - > vb . queue , & vidq - > active ) ;
2006-03-10 18:40:10 +03:00
}
2007-12-10 15:33:52 +03:00
static void buffer_release ( struct videobuf_queue * vq ,
struct videobuf_buffer * vb )
2006-03-10 18:40:10 +03:00
{
2007-12-10 15:33:52 +03:00
struct vivi_buffer * buf = container_of ( vb , struct vivi_buffer , vb ) ;
2006-03-10 18:40:10 +03:00
struct vivi_fh * fh = vq - > priv_data ;
2007-12-10 15:33:52 +03:00
struct vivi_dev * dev = ( struct vivi_dev * ) fh - > dev ;
2006-03-10 18:40:10 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
free_buffer ( vq , buf ) ;
2006-03-10 18:40:10 +03:00
}
static struct videobuf_queue_ops vivi_video_qops = {
. buf_setup = buffer_setup ,
. buf_prepare = buffer_prepare ,
. buf_queue = buffer_queue ,
. buf_release = buffer_release ,
} ;
2006-06-04 17:34:12 +04:00
/* ------------------------------------------------------------------
IOCTL vidioc handling
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-12-10 15:33:52 +03:00
static int vidioc_querycap ( struct file * file , void * priv ,
2006-06-04 17:34:12 +04:00
struct v4l2_capability * cap )
{
strcpy ( cap - > driver , " vivi " ) ;
strcpy ( cap - > card , " vivi " ) ;
cap - > version = VIVI_VERSION ;
cap - > capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE ;
return 0 ;
}
2008-05-28 19:16:41 +04:00
static int vidioc_enum_fmt_vid_cap ( struct file * file , void * priv ,
2006-06-04 17:34:12 +04:00
struct v4l2_fmtdesc * f )
{
if ( f - > index > 0 )
return - EINVAL ;
2007-12-10 15:33:52 +03:00
strlcpy ( f - > description , format . name , sizeof ( f - > description ) ) ;
2006-06-04 17:34:12 +04:00
f - > pixelformat = format . fourcc ;
return 0 ;
}
2008-05-28 19:16:41 +04:00
static int vidioc_g_fmt_vid_cap ( struct file * file , void * priv ,
2006-06-04 17:34:12 +04:00
struct v4l2_format * f )
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-06-04 17:34:12 +04:00
f - > fmt . pix . width = fh - > width ;
f - > fmt . pix . height = fh - > height ;
f - > fmt . pix . field = fh - > vb_vidq . field ;
f - > fmt . pix . pixelformat = fh - > fmt - > fourcc ;
f - > fmt . pix . bytesperline =
( f - > fmt . pix . width * fh - > fmt - > depth ) > > 3 ;
f - > fmt . pix . sizeimage =
f - > fmt . pix . height * f - > fmt . pix . bytesperline ;
return ( 0 ) ;
}
2008-05-28 19:16:41 +04:00
static int vidioc_try_fmt_vid_cap ( struct file * file , void * priv ,
2006-03-10 18:40:10 +03:00
struct v4l2_format * f )
{
2007-12-13 19:30:14 +03:00
struct vivi_fh * fh = priv ;
struct vivi_dev * dev = fh - > dev ;
2006-03-10 18:40:10 +03:00
struct vivi_fmt * fmt ;
enum v4l2_field field ;
unsigned int maxw , maxh ;
if ( format . fourcc ! = f - > fmt . pix . pixelformat ) {
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " Fourcc format (0x%08x) invalid. "
" Driver accepts only 0x%08x \n " ,
f - > fmt . pix . pixelformat , format . fourcc ) ;
2006-03-10 18:40:10 +03:00
return - EINVAL ;
}
2007-12-10 15:33:52 +03:00
fmt = & format ;
2006-03-10 18:40:10 +03:00
field = f - > fmt . pix . field ;
if ( field = = V4L2_FIELD_ANY ) {
2007-12-10 15:33:52 +03:00
field = V4L2_FIELD_INTERLACED ;
2006-03-10 18:40:10 +03:00
} else if ( V4L2_FIELD_INTERLACED ! = field ) {
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " Field type invalid. \n " ) ;
2006-03-10 18:40:10 +03:00
return - EINVAL ;
}
maxw = norm_maxw ( ) ;
maxh = norm_maxh ( ) ;
f - > fmt . pix . field = field ;
if ( f - > fmt . pix . height < 32 )
f - > fmt . pix . height = 32 ;
if ( f - > fmt . pix . height > maxh )
f - > fmt . pix . height = maxh ;
if ( f - > fmt . pix . width < 48 )
f - > fmt . pix . width = 48 ;
if ( f - > fmt . pix . width > maxw )
f - > fmt . pix . width = maxw ;
f - > fmt . pix . width & = ~ 0x03 ;
f - > fmt . pix . bytesperline =
( f - > fmt . pix . width * fmt - > depth ) > > 3 ;
f - > fmt . pix . sizeimage =
f - > fmt . pix . height * f - > fmt . pix . bytesperline ;
return 0 ;
}
2006-06-04 17:34:12 +04:00
/*FIXME: This seems to be generic enough to be at videodev2 */
2008-05-28 19:16:41 +04:00
static int vidioc_s_fmt_vid_cap ( struct file * file , void * priv ,
2006-06-04 17:34:12 +04:00
struct v4l2_format * f )
2006-03-10 18:40:10 +03:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2008-04-03 01:10:59 +04:00
struct videobuf_queue * q = & fh - > vb_vidq ;
2008-05-28 19:16:41 +04:00
int ret = vidioc_try_fmt_vid_cap ( file , fh , f ) ;
2006-06-04 17:34:12 +04:00
if ( ret < 0 )
return ( ret ) ;
2008-04-03 01:10:59 +04:00
mutex_lock ( & q - > vb_lock ) ;
if ( videobuf_queue_is_busy ( & fh - > vb_vidq ) ) {
2008-04-09 06:20:00 +04:00
dprintk ( fh - > dev , 1 , " %s queue busy \n " , __func__ ) ;
2008-04-03 01:10:59 +04:00
ret = - EBUSY ;
goto out ;
}
2006-06-04 17:34:12 +04:00
fh - > fmt = & format ;
fh - > width = f - > fmt . pix . width ;
fh - > height = f - > fmt . pix . height ;
fh - > vb_vidq . field = f - > fmt . pix . field ;
fh - > type = f - > type ;
2008-04-03 01:10:59 +04:00
ret = 0 ;
out :
mutex_unlock ( & q - > vb_lock ) ;
return ( ret ) ;
2006-03-10 18:40:10 +03:00
}
2007-12-10 15:33:52 +03:00
static int vidioc_reqbufs ( struct file * file , void * priv ,
struct v4l2_requestbuffers * p )
2006-03-10 18:40:10 +03:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( videobuf_reqbufs ( & fh - > vb_vidq , p ) ) ;
2006-03-10 18:40:10 +03:00
}
2007-12-10 15:33:52 +03:00
static int vidioc_querybuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2006-03-10 18:40:10 +03:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( videobuf_querybuf ( & fh - > vb_vidq , p ) ) ;
}
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
static int vidioc_qbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2006-06-04 17:34:12 +04:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( videobuf_qbuf ( & fh - > vb_vidq , p ) ) ;
}
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
static int vidioc_dqbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2006-06-04 17:34:12 +04:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( videobuf_dqbuf ( & fh - > vb_vidq , p ,
file - > f_flags & O_NONBLOCK ) ) ;
}
2006-03-10 18:40:10 +03:00
2006-08-08 16:10:10 +04:00
# ifdef CONFIG_VIDEO_V4L1_COMPAT
2007-12-10 15:33:52 +03:00
static int vidiocgmbuf ( struct file * file , void * priv , struct video_mbuf * mbuf )
2006-06-04 17:34:12 +04:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-06-17 15:52:30 +04:00
2007-12-10 15:33:52 +03:00
return videobuf_cgmbuf ( & fh - > vb_vidq , mbuf , 8 ) ;
2006-06-04 17:34:12 +04:00
}
# endif
2006-03-10 18:40:10 +03:00
2006-06-23 13:42:44 +04:00
static int vidioc_streamon ( struct file * file , void * priv , enum v4l2_buf_type i )
2006-06-04 17:34:12 +04:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
if ( fh - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
if ( i ! = fh - > type )
return - EINVAL ;
2006-03-10 18:40:10 +03:00
2007-09-28 03:55:17 +04:00
return videobuf_streamon ( & fh - > vb_vidq ) ;
2006-06-04 17:34:12 +04:00
}
2006-03-10 18:40:10 +03:00
2006-06-23 13:42:44 +04:00
static int vidioc_streamoff ( struct file * file , void * priv , enum v4l2_buf_type i )
2006-06-04 17:34:12 +04:00
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = priv ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
if ( fh - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
if ( i ! = fh - > type )
return - EINVAL ;
2006-03-10 18:40:10 +03:00
2007-09-28 03:55:17 +04:00
return videobuf_streamoff ( & fh - > vb_vidq ) ;
2006-06-04 17:34:12 +04:00
}
2007-12-10 15:33:52 +03:00
static int vidioc_s_std ( struct file * file , void * priv , v4l2_std_id * i )
2006-06-04 17:34:12 +04:00
{
return 0 ;
}
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
/* only one input in this sample driver */
2007-12-10 15:33:52 +03:00
static int vidioc_enum_input ( struct file * file , void * priv ,
2006-06-04 17:34:12 +04:00
struct v4l2_input * inp )
{
if ( inp - > index ! = 0 )
return - EINVAL ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
inp - > type = V4L2_INPUT_TYPE_CAMERA ;
2007-12-13 12:35:26 +03:00
inp - > std = V4L2_STD_525_60 ;
2007-12-10 15:33:52 +03:00
strcpy ( inp - > name , " Camera " ) ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( 0 ) ;
}
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
static int vidioc_g_input ( struct file * file , void * priv , unsigned int * i )
2006-06-04 17:34:12 +04:00
{
* i = 0 ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( 0 ) ;
}
2007-12-10 15:33:52 +03:00
static int vidioc_s_input ( struct file * file , void * priv , unsigned int i )
2006-06-04 17:34:12 +04:00
{
if ( i > 0 )
return - EINVAL ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return ( 0 ) ;
}
2006-03-10 18:40:10 +03:00
/* --- controls ---------------------------------------------- */
2007-12-10 15:33:52 +03:00
static int vidioc_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * qc )
2006-06-04 17:34:12 +04:00
{
int i ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vivi_qctrl ) ; i + + )
if ( qc - > id & & qc - > id = = vivi_qctrl [ i ] . id ) {
memcpy ( qc , & ( vivi_qctrl [ i ] ) ,
sizeof ( * qc ) ) ;
return ( 0 ) ;
}
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return - EINVAL ;
}
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
static int vidioc_g_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
2006-06-04 17:34:12 +04:00
{
int i ;
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vivi_qctrl ) ; i + + )
if ( ctrl - > id = = vivi_qctrl [ i ] . id ) {
2007-12-10 15:33:52 +03:00
ctrl - > value = qctl_regs [ i ] ;
2006-06-04 17:34:12 +04:00
return ( 0 ) ;
}
2006-03-10 18:40:10 +03:00
2006-06-04 17:34:12 +04:00
return - EINVAL ;
2006-03-10 18:40:10 +03:00
}
2007-12-10 15:33:52 +03:00
static int vidioc_s_ctrl ( struct file * file , void * priv ,
2006-06-04 17:34:12 +04:00
struct v4l2_control * ctrl )
2006-03-10 18:40:10 +03:00
{
2006-06-04 17:34:12 +04:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( vivi_qctrl ) ; i + + )
if ( ctrl - > id = = vivi_qctrl [ i ] . id ) {
2007-12-10 15:33:52 +03:00
if ( ctrl - > value < vivi_qctrl [ i ] . minimum
| | ctrl - > value > vivi_qctrl [ i ] . maximum ) {
2006-06-04 17:34:12 +04:00
return ( - ERANGE ) ;
}
2007-12-10 15:33:52 +03:00
qctl_regs [ i ] = ctrl - > value ;
2006-06-04 17:34:12 +04:00
return ( 0 ) ;
}
return - EINVAL ;
2006-03-10 18:40:10 +03:00
}
/* ------------------------------------------------------------------
File operations for the device
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7) / 8)
static int vivi_open ( struct inode * inode , struct file * file )
{
int minor = iminor ( inode ) ;
2007-10-10 12:37:43 +04:00
struct vivi_dev * dev ;
2008-04-26 15:25:18 +04:00
struct vivi_fh * fh = NULL ;
2006-03-10 18:40:10 +03:00
int i ;
2008-04-03 01:10:59 +04:00
int retval = 0 ;
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
printk ( KERN_DEBUG " vivi: open called (minor=%d) \n " , minor ) ;
2006-03-10 18:40:10 +03:00
2008-07-30 15:43:36 +04:00
lock_kernel ( ) ;
2007-10-10 12:37:43 +04:00
list_for_each_entry ( dev , & vivi_devlist , vivi_devlist )
2007-12-10 10:07:03 +03:00
if ( dev - > vfd - > minor = = minor )
2007-10-10 12:37:43 +04:00
goto found ;
2008-07-30 15:43:36 +04:00
unlock_kernel ( ) ;
2007-10-10 12:37:43 +04:00
return - ENODEV ;
2006-06-04 17:34:12 +04:00
2007-12-10 15:33:52 +03:00
found :
2008-04-03 01:10:59 +04:00
mutex_lock ( & dev - > mutex ) ;
2006-03-10 18:40:10 +03:00
dev - > users + + ;
2008-04-03 01:10:59 +04:00
if ( dev - > users > 1 ) {
dev - > users - - ;
retval = - EBUSY ;
goto unlock ;
}
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " open minor=%d type=%s users=%d \n " , minor ,
2007-10-10 12:37:43 +04:00
v4l2_type_names [ V4L2_BUF_TYPE_VIDEO_CAPTURE ] , dev - > users ) ;
2006-03-10 18:40:10 +03:00
/* allocate + initialize per filehandle data */
2007-12-10 15:33:52 +03:00
fh = kzalloc ( sizeof ( * fh ) , GFP_KERNEL ) ;
2006-03-10 18:40:10 +03:00
if ( NULL = = fh ) {
dev - > users - - ;
2008-04-03 01:10:59 +04:00
retval = - ENOMEM ;
goto unlock ;
2006-03-10 18:40:10 +03:00
}
2008-04-03 01:10:59 +04:00
unlock :
mutex_unlock ( & dev - > mutex ) ;
2008-07-30 15:43:36 +04:00
if ( retval ) {
unlock_kernel ( ) ;
2008-04-03 01:10:59 +04:00
return retval ;
2008-07-30 15:43:36 +04:00
}
2006-03-10 18:40:10 +03:00
file - > private_data = fh ;
fh - > dev = dev ;
2006-06-04 17:34:12 +04:00
2006-03-10 18:40:10 +03:00
fh - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
fh - > fmt = & format ;
fh - > width = 640 ;
fh - > height = 480 ;
/* Put all controls at a sane state */
for ( i = 0 ; i < ARRAY_SIZE ( vivi_qctrl ) ; i + + )
2007-12-10 15:33:52 +03:00
qctl_regs [ i ] = vivi_qctrl [ i ] . default_value ;
2006-03-10 18:40:10 +03:00
/* Resets frame counters */
2007-12-10 15:33:52 +03:00
dev - > h = 0 ;
dev - > m = 0 ;
dev - > s = 0 ;
2008-01-14 01:36:11 +03:00
dev - > ms = 0 ;
2007-12-10 15:33:52 +03:00
dev - > mv_count = 0 ;
dev - > jiffies = jiffies ;
sprintf ( dev - > timestr , " %02d:%02d:%02d:%03d " ,
2008-01-14 01:36:11 +03:00
dev - > h , dev - > m , dev - > s , dev - > ms ) ;
2006-03-10 18:40:10 +03:00
2007-08-03 06:31:54 +04:00
videobuf_queue_vmalloc_init ( & fh - > vb_vidq , & vivi_video_qops ,
2007-12-13 22:13:37 +03:00
NULL , & dev - > slock , fh - > type , V4L2_FIELD_INTERLACED ,
2007-12-10 15:33:52 +03:00
sizeof ( struct vivi_buffer ) , fh ) ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
vivi_start_thread ( fh ) ;
2008-07-30 15:43:36 +04:00
unlock_kernel ( ) ;
2008-04-03 01:10:59 +04:00
2006-03-10 18:40:10 +03:00
return 0 ;
}
static ssize_t
vivi_read ( struct file * file , char __user * data , size_t count , loff_t * ppos )
{
2007-12-10 15:33:52 +03:00
struct vivi_fh * fh = file - > private_data ;
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
if ( fh - > type = = V4L2_BUF_TYPE_VIDEO_CAPTURE ) {
2007-07-30 05:56:11 +04:00
return videobuf_read_stream ( & fh - > vb_vidq , data , count , ppos , 0 ,
2006-03-10 18:40:10 +03:00
file - > f_flags & O_NONBLOCK ) ;
}
return 0 ;
}
static unsigned int
vivi_poll ( struct file * file , struct poll_table_struct * wait )
{
2006-06-04 17:34:12 +04:00
struct vivi_fh * fh = file - > private_data ;
2007-12-13 19:30:14 +03:00
struct vivi_dev * dev = fh - > dev ;
2007-09-28 03:55:02 +04:00
struct videobuf_queue * q = & fh - > vb_vidq ;
2006-03-10 18:40:10 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 18:40:10 +03:00
if ( V4L2_BUF_TYPE_VIDEO_CAPTURE ! = fh - > type )
return POLLERR ;
2007-09-28 03:55:02 +04:00
return videobuf_poll_stream ( file , q , wait ) ;
2006-03-10 18:40:10 +03:00
}
2007-12-10 10:07:03 +03:00
static int vivi_close ( struct inode * inode , struct file * file )
2006-03-10 18:40:10 +03:00
{
2006-06-04 17:34:12 +04:00
struct vivi_fh * fh = file - > private_data ;
struct vivi_dev * dev = fh - > dev ;
2006-03-10 18:40:10 +03:00
struct vivi_dmaqueue * vidq = & dev - > vidq ;
int minor = iminor ( inode ) ;
vivi_stop_thread ( vidq ) ;
2007-11-14 02:11:26 +03:00
videobuf_stop ( & fh - > vb_vidq ) ;
2006-03-10 18:40:10 +03:00
videobuf_mmap_free ( & fh - > vb_vidq ) ;
2007-12-10 10:38:11 +03:00
kfree ( fh ) ;
2006-03-10 18:40:10 +03:00
2008-04-03 01:10:59 +04:00
mutex_lock ( & dev - > mutex ) ;
2006-03-10 18:40:10 +03:00
dev - > users - - ;
2008-04-03 01:10:59 +04:00
mutex_unlock ( & dev - > mutex ) ;
2006-03-10 18:40:10 +03:00
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " close called (minor=%d, users=%d) \n " ,
minor , dev - > users ) ;
2006-03-10 18:40:10 +03:00
return 0 ;
}
2007-12-10 10:38:11 +03:00
static int vivi_release ( void )
2007-12-10 10:07:03 +03:00
{
2007-12-10 10:38:11 +03:00
struct vivi_dev * dev ;
struct list_head * list ;
while ( ! list_empty ( & vivi_devlist ) ) {
list = vivi_devlist . next ;
list_del ( list ) ;
dev = list_entry ( list , struct vivi_dev , vivi_devlist ) ;
2007-12-10 10:07:03 +03:00
2008-06-10 07:02:32 +04:00
if ( - 1 ! = dev - > vfd - > minor ) {
2008-09-04 00:12:25 +04:00
printk ( KERN_INFO " %s: unregistering /dev/video%d \n " ,
2008-06-10 22:21:49 +04:00
VIVI_MODULE_NAME , dev - > vfd - > minor ) ;
2008-09-04 00:12:25 +04:00
video_unregister_device ( dev - > vfd ) ;
2008-06-10 07:02:32 +04:00
} else {
2008-09-04 00:12:25 +04:00
printk ( KERN_INFO " %s: releasing /dev/video%d \n " ,
2008-06-10 22:21:49 +04:00
VIVI_MODULE_NAME , dev - > vfd - > minor ) ;
2008-09-04 00:12:25 +04:00
video_device_release ( dev - > vfd ) ;
2008-06-10 07:02:32 +04:00
}
2007-12-10 10:38:11 +03:00
kfree ( dev ) ;
}
2007-12-10 10:07:03 +03:00
return 0 ;
}
2007-12-10 15:33:52 +03:00
static int vivi_mmap ( struct file * file , struct vm_area_struct * vma )
2006-03-10 18:40:10 +03:00
{
2007-12-13 19:30:14 +03:00
struct vivi_fh * fh = file - > private_data ;
struct vivi_dev * dev = fh - > dev ;
2006-03-10 18:40:10 +03:00
int ret ;
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " mmap called, vma=0x%08lx \n " , ( unsigned long ) vma ) ;
2006-03-10 18:40:10 +03:00
2007-12-10 15:33:52 +03:00
ret = videobuf_mmap_mapper ( & fh - > vb_vidq , vma ) ;
2006-03-10 18:40:10 +03:00
2007-12-13 19:30:14 +03:00
dprintk ( dev , 1 , " vma start=0x%08lx, size=%ld, ret=%d \n " ,
2006-03-10 18:40:10 +03:00
( unsigned long ) vma - > vm_start ,
( unsigned long ) vma - > vm_end - ( unsigned long ) vma - > vm_start ,
ret ) ;
return ret ;
}
2007-02-12 11:55:33 +03:00
static const struct file_operations vivi_fops = {
2006-03-10 18:40:10 +03:00
. owner = THIS_MODULE ,
. open = vivi_open ,
2007-12-10 10:07:03 +03:00
. release = vivi_close ,
2006-03-10 18:40:10 +03:00
. read = vivi_read ,
. poll = vivi_poll ,
2006-06-04 17:34:12 +04:00
. ioctl = video_ioctl2 , /* V4L2 ioctl handler */
2008-04-13 21:57:44 +04:00
. compat_ioctl = v4l_compat_ioctl32 ,
2007-08-03 06:31:54 +04:00
. mmap = vivi_mmap ,
2006-03-10 18:40:10 +03:00
. llseek = no_llseek ,
} ;
2008-07-21 09:57:38 +04:00
static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
2006-06-04 17:34:12 +04:00
. vidioc_querycap = vidioc_querycap ,
2008-05-28 19:16:41 +04:00
. vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap ,
. vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap ,
. vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap ,
. vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap ,
2006-06-04 17:34:12 +04:00
. vidioc_reqbufs = vidioc_reqbufs ,
. vidioc_querybuf = vidioc_querybuf ,
. vidioc_qbuf = vidioc_qbuf ,
. vidioc_dqbuf = vidioc_dqbuf ,
. vidioc_s_std = vidioc_s_std ,
. vidioc_enum_input = vidioc_enum_input ,
. vidioc_g_input = vidioc_g_input ,
. vidioc_s_input = vidioc_s_input ,
. vidioc_queryctrl = vidioc_queryctrl ,
. vidioc_g_ctrl = vidioc_g_ctrl ,
. vidioc_s_ctrl = vidioc_s_ctrl ,
. vidioc_streamon = vidioc_streamon ,
. vidioc_streamoff = vidioc_streamoff ,
2006-08-08 16:10:10 +04:00
# ifdef CONFIG_VIDEO_V4L1_COMPAT
2006-06-04 17:34:12 +04:00
. vidiocgmbuf = vidiocgmbuf ,
# endif
2008-07-21 09:57:38 +04:00
} ;
static struct video_device vivi_template = {
. name = " vivi " ,
. fops = & vivi_fops ,
. ioctl_ops = & vivi_ioctl_ops ,
. minor = - 1 ,
. release = video_device_release ,
2007-12-13 12:35:26 +03:00
. tvnorms = V4L2_STD_525_60 ,
2006-11-20 19:19:20 +03:00
. current_norm = V4L2_STD_NTSC_M ,
2006-03-10 18:40:10 +03:00
} ;
2006-06-04 17:34:12 +04:00
/* -----------------------------------------------------------------
2006-03-10 18:40:10 +03:00
Initialization and module stuff
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2008-09-04 00:11:53 +04:00
/* This routine allocates from 1 to n_devs virtual drivers.
The real maximum number of virtual drivers will depend on how many drivers
will succeed . This is limited to the maximum number of devices that
videodev supports . Since there are 64 minors for video grabbers , this is
currently the theoretical maximum limit . However , a further limit does
exist at videodev that forbids any driver to register more than 32 video
grabbers .
*/
2006-03-10 18:40:10 +03:00
static int __init vivi_init ( void )
{
2007-12-10 10:38:11 +03:00
int ret = - ENOMEM , i ;
2006-03-10 18:40:10 +03:00
struct vivi_dev * dev ;
2007-12-10 10:07:03 +03:00
struct video_device * vfd ;
2006-03-10 18:40:10 +03:00
2008-09-04 00:11:53 +04:00
if ( n_devs < = 0 )
n_devs = 1 ;
2007-12-10 10:38:11 +03:00
for ( i = 0 ; i < n_devs ; i + + ) {
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
2008-09-04 00:11:53 +04:00
if ( ! dev )
2007-12-10 10:38:11 +03:00
break ;
2006-03-10 18:40:10 +03:00
2007-12-10 10:38:11 +03:00
/* init video dma queues */
INIT_LIST_HEAD ( & dev - > vidq . active ) ;
init_waitqueue_head ( & dev - > vidq . wq ) ;
2006-03-10 18:40:10 +03:00
2007-12-10 10:38:11 +03:00
/* initialize locks */
2007-12-13 22:13:37 +03:00
spin_lock_init ( & dev - > slock ) ;
2008-04-03 01:10:59 +04:00
mutex_init ( & dev - > mutex ) ;
2006-03-10 18:40:10 +03:00
2007-12-10 10:38:11 +03:00
vfd = video_device_alloc ( ) ;
2008-09-04 00:11:53 +04:00
if ( ! vfd ) {
kfree ( dev ) ;
2007-12-10 10:38:11 +03:00
break ;
2008-09-04 00:11:53 +04:00
}
2007-12-10 10:38:11 +03:00
* vfd = vivi_template ;
ret = video_register_device ( vfd , VFL_TYPE_GRABBER , video_nr ) ;
2008-09-04 00:11:53 +04:00
if ( ret < 0 ) {
video_device_release ( vfd ) ;
kfree ( dev ) ;
/* If some registers succeeded, keep driver */
if ( i )
ret = 0 ;
2007-12-10 10:38:11 +03:00
break ;
2008-09-04 00:11:53 +04:00
}
/* Now that everything is fine, let's add it to device list */
list_add_tail ( & dev - > vivi_devlist , & vivi_devlist ) ;
2007-12-10 10:38:11 +03:00
snprintf ( vfd - > name , sizeof ( vfd - > name ) , " %s (%i) " ,
vivi_template . name , vfd - > minor ) ;
2007-12-10 10:07:03 +03:00
2007-12-10 10:38:11 +03:00
if ( video_nr > = 0 )
video_nr + + ;
2007-12-10 10:07:03 +03:00
2007-12-10 10:38:11 +03:00
dev - > vfd = vfd ;
2008-06-10 07:02:32 +04:00
printk ( KERN_INFO " %s: V4L2 device registered as /dev/video%d \n " ,
2008-06-10 22:21:49 +04:00
VIVI_MODULE_NAME , vfd - > minor ) ;
2007-12-10 10:38:11 +03:00
}
2007-12-10 10:07:03 +03:00
2007-12-10 10:38:11 +03:00
if ( ret < 0 ) {
vivi_release ( ) ;
printk ( KERN_INFO " Error %d while loading vivi driver \n " , ret ) ;
2008-09-04 00:11:53 +04:00
} else {
2007-12-10 10:38:11 +03:00
printk ( KERN_INFO " Video Technology Magazine Virtual Video "
2008-06-10 07:02:32 +04:00
" Capture Board ver %u.%u.%u successfully loaded. \n " ,
( VIVI_VERSION > > 16 ) & 0xFF , ( VIVI_VERSION > > 8 ) & 0xFF ,
VIVI_VERSION & 0xFF ) ;
2008-09-04 00:11:53 +04:00
/* n_devs will reflect the actual number of allocated devices */
n_devs = i ;
}
2006-03-10 18:40:10 +03:00
return ret ;
}
static void __exit vivi_exit ( void )
{
2007-12-10 10:38:11 +03:00
vivi_release ( ) ;
2006-03-10 18:40:10 +03:00
}
module_init ( vivi_init ) ;
module_exit ( vivi_exit ) ;
2006-06-04 17:34:12 +04:00
MODULE_DESCRIPTION ( " Video Technology Magazine Virtual Video Capture Board " ) ;
MODULE_AUTHOR ( " Mauro Carvalho Chehab, Ted Walther and John Sokol " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
2008-09-04 00:11:53 +04:00
module_param ( video_nr , uint , 0444 ) ;
2007-12-10 10:38:11 +03:00
MODULE_PARM_DESC ( video_nr , " video iminor start number " ) ;
2006-06-04 17:34:12 +04:00
2008-09-04 00:11:53 +04:00
module_param ( n_devs , uint , 0444 ) ;
2007-12-10 10:38:11 +03:00
MODULE_PARM_DESC ( n_devs , " number of video devices to create " ) ;
2006-06-04 17:34:12 +04:00
2007-12-13 12:36:22 +03:00
module_param_named ( debug , vivi_template . debug , int , 0444 ) ;
2007-12-10 10:38:11 +03:00
MODULE_PARM_DESC ( debug , " activates debug info " ) ;
2006-06-04 17:34:12 +04:00
2007-12-10 10:38:11 +03:00
module_param ( vid_limit , int , 0644 ) ;
MODULE_PARM_DESC ( vid_limit , " capture memory limit in megabytes " ) ;