2006-03-10 12: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/errno.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/sched.h>
2010-05-07 15:22:26 -03:00
# include <linux/slab.h>
2010-04-10 04:13:53 -03:00
# include <linux/font.h>
2006-03-10 12:40:10 -03:00
# include <linux/version.h>
2007-07-02 10:19:38 -03:00
# include <linux/mutex.h>
2006-03-10 12:40:10 -03:00
# include <linux/videodev2.h>
# include <linux/kthread.h>
2010-04-10 04:13:53 -03:00
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
2006-12-06 20:34:23 -08:00
# include <linux/freezer.h>
2010-04-10 04:13:53 -03:00
# endif
2009-02-14 13:23:12 -03:00
# include <media/videobuf-vmalloc.h>
# include <media/v4l2-device.h>
# include <media/v4l2-ioctl.h>
2010-04-10 04:13:53 -03:00
# include <media/v4l2-common.h>
2006-03-10 12:40:10 -03:00
2008-06-10 15:21:49 -03:00
# define VIVI_MODULE_NAME "vivi"
2008-06-10 00:02:32 -03:00
2006-03-10 12: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 */
2010-04-10 04:13:53 -03:00
# define MAX_WIDTH 1920
# define MAX_HEIGHT 1200
2006-03-10 12:40:10 -03:00
# define VIVI_MAJOR_VERSION 0
2010-04-10 04:13:53 -03:00
# define VIVI_MINOR_VERSION 7
2006-03-10 12:40:10 -03:00
# define VIVI_RELEASE 0
2007-12-10 09:33:52 -03:00
# define VIVI_VERSION \
KERNEL_VERSION ( VIVI_MAJOR_VERSION , VIVI_MINOR_VERSION , VIVI_RELEASE )
2006-03-10 12:40:10 -03:00
2009-02-14 13:23:12 -03: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 " ) ;
static unsigned video_nr = - 1 ;
module_param ( video_nr , uint , 0644 ) ;
MODULE_PARM_DESC ( video_nr , " videoX start number, -1 is autodetect " ) ;
static unsigned n_devs = 1 ;
module_param ( n_devs , uint , 0644 ) ;
MODULE_PARM_DESC ( n_devs , " number of video devices to create " ) ;
static unsigned debug ;
module_param ( debug , uint , 0644 ) ;
MODULE_PARM_DESC ( debug , " activates debug info " ) ;
static unsigned int vid_limit = 16 ;
module_param ( vid_limit , uint , 0644 ) ;
MODULE_PARM_DESC ( vid_limit , " capture memory limit in megabytes " ) ;
2010-04-10 04:13:53 -03:00
/* Global font descriptor */
static const u8 * font8x16 ;
2006-03-10 12:40:10 -03:00
2009-02-14 13:23:12 -03:00
# define dprintk(dev, level, fmt, arg...) \
v4l2_dbg ( level , debug , & dev - > v4l2_dev , fmt , # # arg )
2006-03-10 12:40:10 -03:00
/* ------------------------------------------------------------------
Basic structures
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
struct vivi_fmt {
char * name ;
u32 fourcc ; /* v4l2 format id */
int depth ;
} ;
2008-10-14 12:47:09 -03:00
static struct vivi_fmt formats [ ] = {
{
. name = " 4:2:2, packed, YUYV " ,
. fourcc = V4L2_PIX_FMT_YUYV ,
. depth = 16 ,
} ,
2008-10-14 12:47:25 -03:00
{
. name = " 4:2:2, packed, UYVY " ,
. fourcc = V4L2_PIX_FMT_UYVY ,
. depth = 16 ,
} ,
2008-10-14 12:47:35 -03:00
{
. name = " RGB565 (LE) " ,
. fourcc = V4L2_PIX_FMT_RGB565 , /* gggbbbbb rrrrrggg */
. depth = 16 ,
} ,
{
. name = " RGB565 (BE) " ,
. fourcc = V4L2_PIX_FMT_RGB565X , /* rrrrrggg gggbbbbb */
. depth = 16 ,
} ,
2008-10-14 12:47:43 -03:00
{
. name = " RGB555 (LE) " ,
. fourcc = V4L2_PIX_FMT_RGB555 , /* gggbbbbb arrrrrgg */
. depth = 16 ,
} ,
{
. name = " RGB555 (BE) " ,
. fourcc = V4L2_PIX_FMT_RGB555X , /* arrrrrgg gggbbbbb */
. depth = 16 ,
} ,
2006-03-10 12:40:10 -03:00
} ;
2008-10-14 12:47:09 -03:00
static struct vivi_fmt * get_format ( struct v4l2_format * f )
{
struct vivi_fmt * fmt ;
unsigned int k ;
for ( k = 0 ; k < ARRAY_SIZE ( formats ) ; k + + ) {
fmt = & formats [ k ] ;
if ( fmt - > fourcc = = f - > fmt . pix . pixelformat )
break ;
}
if ( k = = ARRAY_SIZE ( formats ) )
return NULL ;
return & formats [ k ] ;
}
2006-03-10 12:40:10 -03:00
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 ;
2009-02-14 13:23:12 -03:00
struct v4l2_device v4l2_dev ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
/* controls */
int brightness ;
int contrast ;
int saturation ;
int hue ;
int volume ;
2007-12-13 16:13:37 -03:00
spinlock_t slock ;
2008-04-02 18:10:59 -03:00
struct mutex mutex ;
2006-03-10 12:40:10 -03:00
/* various device info */
2007-12-10 04:07:03 -03:00
struct video_device * vfd ;
2006-03-10 12:40:10 -03:00
struct vivi_dmaqueue vidq ;
/* Several counters */
2010-04-10 04:13:53 -03:00
unsigned ms ;
2008-01-13 19:36:11 -03:00
unsigned long jiffies ;
2007-12-10 04:43:38 -03:00
int mv_count ; /* Controls bars movement */
2009-01-11 10:29:43 -03:00
/* Input Number */
int input ;
2009-02-14 13:43:44 -03:00
2006-03-10 12:40:10 -03:00
/* video capture */
struct vivi_fmt * fmt ;
2007-12-10 09:33:52 -03:00
unsigned int width , height ;
2006-03-10 12:40:10 -03:00
struct videobuf_queue vb_vidq ;
2010-04-10 04:13:53 -03:00
unsigned long generating ;
u8 bars [ 9 ] [ 3 ] ;
u8 line [ MAX_WIDTH * 4 ] ;
2006-03-10 12:40:10 -03:00
} ;
/* ------------------------------------------------------------------
DMA and thread functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Bars and Colors should match positions */
enum colors {
WHITE ,
2010-04-10 04:13:53 -03:00
AMBER ,
2006-03-10 12:40:10 -03:00
CYAN ,
GREEN ,
MAGENTA ,
RED ,
2007-12-10 09:33:52 -03:00
BLUE ,
BLACK ,
2010-04-10 04:13:53 -03:00
TEXT_BLACK ,
2006-03-10 12:40:10 -03:00
} ;
2010-04-10 04:13:53 -03:00
/* R G B */
2009-01-11 10:29:43 -03:00
# define COLOR_WHITE {204, 204, 204}
2010-04-10 04:13:53 -03:00
# define COLOR_AMBER {208, 208, 0}
# define COLOR_CYAN { 0, 206, 206}
2009-01-11 10:29:43 -03:00
# define COLOR_GREEN { 0, 239, 0}
# define COLOR_MAGENTA {239, 0, 239}
# define COLOR_RED {205, 0, 0}
# define COLOR_BLUE { 0, 0, 255}
# define COLOR_BLACK { 0, 0, 0}
struct bar_std {
2010-04-10 04:13:53 -03:00
u8 bar [ 9 ] [ 3 ] ;
2009-01-11 10:29:43 -03:00
} ;
/* Maximum number of bars are 10 - otherwise, the input print code
should be modified */
static struct bar_std bars [ ] = {
{ /* Standard ITU-R color bar sequence */
2010-04-10 04:13:53 -03:00
{ COLOR_WHITE , COLOR_AMBER , COLOR_CYAN , COLOR_GREEN ,
COLOR_MAGENTA , COLOR_RED , COLOR_BLUE , COLOR_BLACK , COLOR_BLACK }
2009-01-11 10:29:43 -03:00
} , {
2010-04-10 04:13:53 -03:00
{ COLOR_WHITE , COLOR_AMBER , COLOR_BLACK , COLOR_WHITE ,
COLOR_AMBER , COLOR_BLACK , COLOR_WHITE , COLOR_AMBER , COLOR_BLACK }
2009-01-11 10:29:43 -03:00
} , {
2010-04-10 04:13:53 -03:00
{ COLOR_WHITE , COLOR_CYAN , COLOR_BLACK , COLOR_WHITE ,
COLOR_CYAN , COLOR_BLACK , COLOR_WHITE , COLOR_CYAN , COLOR_BLACK }
2009-01-11 10:29:43 -03:00
} , {
2010-04-10 04:13:53 -03:00
{ COLOR_WHITE , COLOR_GREEN , COLOR_BLACK , COLOR_WHITE ,
COLOR_GREEN , COLOR_BLACK , COLOR_WHITE , COLOR_GREEN , COLOR_BLACK }
2009-01-11 10:29:43 -03:00
} ,
2006-03-10 12:40:10 -03:00
} ;
2009-01-11 10:29:43 -03:00
# define NUM_INPUTS ARRAY_SIZE(bars)
2007-12-10 09:33:52 -03:00
# define TO_Y(r, g, b) \
( ( ( 16829 * r + 33039 * g + 6416 * b + 32768 ) > > 16 ) + 16 )
2006-03-10 12:40:10 -03:00
/* RGB to V(Cr) Color transform */
2007-12-10 09:33:52 -03:00
# define TO_V(r, g, b) \
( ( ( 28784 * r - 24103 * g - 4681 * b + 32768 ) > > 16 ) + 128 )
2006-03-10 12:40:10 -03:00
/* RGB to U(Cb) Color transform */
2007-12-10 09:33:52 -03:00
# define TO_U(r, g, b) \
( ( ( - 9714 * r - 19070 * g + 28784 * b + 32768 ) > > 16 ) + 128 )
2006-03-10 12:40:10 -03:00
2009-06-25 16:28:23 -03:00
/* precalculate color bar values to speed up rendering */
2010-04-10 04:13:53 -03:00
static void precalculate_bars ( struct vivi_dev * dev )
2009-06-25 16:28:23 -03:00
{
2010-04-10 04:13:53 -03:00
u8 r , g , b ;
2009-06-25 16:28:23 -03:00
int k , is_yuv ;
2010-04-10 04:13:53 -03:00
for ( k = 0 ; k < 9 ; k + + ) {
r = bars [ dev - > input ] . bar [ k ] [ 0 ] ;
g = bars [ dev - > input ] . bar [ k ] [ 1 ] ;
b = bars [ dev - > input ] . bar [ k ] [ 2 ] ;
2009-06-25 16:28:23 -03:00
is_yuv = 0 ;
2010-04-10 04:13:53 -03:00
switch ( dev - > fmt - > fourcc ) {
2009-06-25 16:28:23 -03:00
case V4L2_PIX_FMT_YUYV :
case V4L2_PIX_FMT_UYVY :
is_yuv = 1 ;
break ;
case V4L2_PIX_FMT_RGB565 :
case V4L2_PIX_FMT_RGB565X :
r > > = 3 ;
g > > = 2 ;
b > > = 3 ;
break ;
case V4L2_PIX_FMT_RGB555 :
case V4L2_PIX_FMT_RGB555X :
r > > = 3 ;
g > > = 3 ;
b > > = 3 ;
break ;
}
if ( is_yuv ) {
2010-04-10 04:13:53 -03:00
dev - > bars [ k ] [ 0 ] = TO_Y ( r , g , b ) ; /* Luma */
dev - > bars [ k ] [ 1 ] = TO_U ( r , g , b ) ; /* Cb */
dev - > bars [ k ] [ 2 ] = TO_V ( r , g , b ) ; /* Cr */
2009-06-25 16:28:23 -03:00
} else {
2010-04-10 04:13:53 -03:00
dev - > bars [ k ] [ 0 ] = r ;
dev - > bars [ k ] [ 1 ] = g ;
dev - > bars [ k ] [ 2 ] = b ;
2009-06-25 16:28:23 -03:00
}
}
}
2009-01-11 10:29:43 -03:00
# define TSTAMP_MIN_Y 24
# define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15)
# define TSTAMP_INPUT_X 10
# define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X)
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
static void gen_twopix ( struct vivi_dev * dev , u8 * buf , int colorpos )
2008-10-14 12:46:59 -03:00
{
2010-04-10 04:13:53 -03:00
u8 r_y , g_u , b_v ;
2008-10-14 12:46:59 -03:00
int color ;
2010-04-10 04:13:53 -03:00
u8 * p ;
2008-10-14 12:46:59 -03:00
2010-04-10 04:13:53 -03:00
r_y = dev - > bars [ colorpos ] [ 0 ] ; /* R or precalculated Y */
g_u = dev - > bars [ colorpos ] [ 1 ] ; /* G or precalculated U */
b_v = dev - > bars [ colorpos ] [ 2 ] ; /* B or precalculated V */
2008-10-14 12:46:59 -03:00
for ( color = 0 ; color < 4 ; color + + ) {
p = buf + color ;
2010-04-10 04:13:53 -03:00
switch ( dev - > fmt - > fourcc ) {
2008-10-14 12:47:09 -03:00
case V4L2_PIX_FMT_YUYV :
switch ( color ) {
case 0 :
case 2 :
* p = r_y ;
break ;
case 1 :
* p = g_u ;
break ;
case 3 :
* p = b_v ;
break ;
}
2008-10-14 12:46:59 -03:00
break ;
2008-10-14 12:47:25 -03:00
case V4L2_PIX_FMT_UYVY :
switch ( color ) {
case 1 :
case 3 :
* p = r_y ;
break ;
case 0 :
* p = g_u ;
break ;
case 2 :
* p = b_v ;
break ;
}
break ;
2008-10-14 12:47:35 -03:00
case V4L2_PIX_FMT_RGB565 :
switch ( color ) {
case 0 :
case 2 :
* p = ( g_u < < 5 ) | b_v ;
break ;
case 1 :
case 3 :
* p = ( r_y < < 3 ) | ( g_u > > 3 ) ;
break ;
}
break ;
case V4L2_PIX_FMT_RGB565X :
switch ( color ) {
case 0 :
case 2 :
* p = ( r_y < < 3 ) | ( g_u > > 3 ) ;
break ;
case 1 :
case 3 :
* p = ( g_u < < 5 ) | b_v ;
break ;
}
break ;
2008-10-14 12:47:43 -03:00
case V4L2_PIX_FMT_RGB555 :
switch ( color ) {
case 0 :
case 2 :
* p = ( g_u < < 5 ) | b_v ;
break ;
case 1 :
case 3 :
* p = ( r_y < < 2 ) | ( g_u > > 3 ) ;
break ;
}
break ;
case V4L2_PIX_FMT_RGB555X :
switch ( color ) {
case 0 :
case 2 :
* p = ( r_y < < 2 ) | ( g_u > > 3 ) ;
break ;
case 1 :
case 3 :
* p = ( g_u < < 5 ) | b_v ;
break ;
}
break ;
2008-10-14 12:46:59 -03:00
}
}
}
2010-04-10 04:13:53 -03:00
static void precalculate_line ( struct vivi_dev * dev )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
int w ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
for ( w = 0 ; w < dev - > width * 2 ; w + = 2 ) {
int colorpos = ( w / ( dev - > width / 8 ) % 8 ) ;
2008-10-14 12:46:59 -03:00
2010-04-10 04:13:53 -03:00
gen_twopix ( dev , dev - > line + w * 2 , colorpos ) ;
2006-03-10 12:40:10 -03:00
}
2010-04-10 04:13:53 -03:00
}
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
static void gen_text ( struct vivi_dev * dev , char * basep ,
int y , int x , char * text )
{
int line ;
2009-01-11 10:29:43 -03:00
2010-04-10 04:13:53 -03:00
/* Checks if it is possible to show string */
if ( y + 16 > = dev - > height | | x + strlen ( text ) * 8 > = dev - > width )
return ;
2006-03-10 12:40:10 -03:00
/* Print stream time */
2010-04-10 04:13:53 -03:00
for ( line = y ; line < y + 16 ; line + + ) {
int j = 0 ;
char * pos = basep + line * dev - > width * 2 + x * 2 ;
char * s ;
for ( s = text ; * s ; s + + ) {
u8 chr = font8x16 [ * s * 16 + line - y ] ;
int i ;
for ( i = 0 ; i < 7 ; i + + , j + + ) {
2008-10-14 12:46:59 -03:00
/* Draw white font on black background */
2010-04-10 04:13:53 -03:00
if ( chr & ( 1 < < ( 7 - i ) ) )
gen_twopix ( dev , pos + j * 2 , WHITE ) ;
2008-10-14 12:46:59 -03:00
else
2010-04-10 04:13:53 -03:00
gen_twopix ( dev , pos + j * 2 , TEXT_BLACK ) ;
2006-03-10 12:40:10 -03:00
}
}
}
}
2008-04-02 18:10:59 -03:00
2010-04-10 04:13:53 -03:00
static void vivi_fillbuff ( struct vivi_dev * dev , struct vivi_buffer * buf )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
int hmax = buf - > vb . height ;
int wmax = buf - > vb . width ;
2006-03-10 12:40:10 -03:00
struct timeval ts ;
2007-12-10 09:33:52 -03:00
void * vbuf = videobuf_to_vmalloc ( & buf - > vb ) ;
2010-04-10 04:13:53 -03:00
unsigned ms ;
char str [ 100 ] ;
int h , line = 1 ;
2007-01-25 05:00:01 -03:00
2008-06-22 09:11:40 -03:00
if ( ! vbuf )
2007-08-02 23:31:54 -03:00
return ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
for ( h = 0 ; h < hmax ; h + + )
memcpy ( vbuf + h * wmax * 2 , dev - > line + ( dev - > mv_count % wmax ) * 2 , wmax * 2 ) ;
2007-08-02 23:31:54 -03:00
2006-03-10 12:40:10 -03:00
/* Updates stream time */
2010-04-10 04:13:53 -03:00
dev - > ms + = jiffies_to_msecs ( jiffies - dev - > jiffies ) ;
2007-12-10 09:33:52 -03:00
dev - > jiffies = jiffies ;
2010-04-10 04:13:53 -03:00
ms = dev - > ms ;
snprintf ( str , sizeof ( str ) , " %02d:%02d:%02d:%03d " ,
( ms / ( 60 * 60 * 1000 ) ) % 24 ,
( ms / ( 60 * 1000 ) ) % 60 ,
( ms / 1000 ) % 60 ,
ms % 1000 ) ;
gen_text ( dev , vbuf , line + + * 16 , 16 , str ) ;
snprintf ( str , sizeof ( str ) , " %dx%d, input %d " ,
dev - > width , dev - > height , dev - > input ) ;
gen_text ( dev , vbuf , line + + * 16 , 16 , str ) ;
snprintf ( str , sizeof ( str ) , " brightness %3d, contrast %3d, saturation %3d, hue %d " ,
dev - > brightness ,
dev - > contrast ,
dev - > saturation ,
dev - > hue ) ;
gen_text ( dev , vbuf , line + + * 16 , 16 , str ) ;
snprintf ( str , sizeof ( str ) , " volume %3d " , dev - > volume ) ;
gen_text ( dev , vbuf , line + + * 16 , 16 , str ) ;
dev - > mv_count + = 2 ;
2006-03-10 12:40:10 -03:00
/* Advice that buffer was filled */
buf - > vb . field_count + + ;
do_gettimeofday ( & ts ) ;
buf - > vb . ts = ts ;
2008-04-02 18:10:59 -03:00
buf - > vb . state = VIDEOBUF_DONE ;
2006-03-10 12:40:10 -03:00
}
2010-04-10 04:13:53 -03:00
static void vivi_thread_tick ( struct vivi_dev * dev )
2006-03-10 12:40:10 -03:00
{
2008-04-02 18:10:59 -03:00
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
2010-04-10 04:13:53 -03:00
struct vivi_buffer * buf ;
2008-04-02 18:10:59 -03:00
unsigned long flags = 0 ;
2006-03-10 12:40:10 -03:00
2008-04-02 18:10:59 -03:00
dprintk ( dev , 1 , " Thread tick \n " ) ;
2006-03-10 12:40:10 -03:00
2008-04-02 18:10:59 -03: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 12:40:10 -03:00
2008-04-02 18:10:59 -03:00
buf = list_entry ( dma_q - > active . next ,
struct vivi_buffer , vb . queue ) ;
2006-03-10 12:40:10 -03:00
2008-04-02 18:10:59 -03:00
/* Nobody is waiting on this buffer, return */
if ( ! waitqueue_active ( & buf - > vb . done ) )
goto unlock ;
2006-03-10 12:40:10 -03:00
2008-04-02 18:10:59 -03:00
list_del ( & buf - > vb . queue ) ;
2007-01-14 08:33:24 -03:00
2008-04-02 18:10:59 -03:00
do_gettimeofday ( & buf - > vb . ts ) ;
/* Fill buffer */
2010-04-10 04:13:53 -03:00
vivi_fillbuff ( dev , buf ) ;
2008-04-02 18:10:59 -03:00
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 ) ;
2006-03-10 12:40:10 -03:00
}
2007-12-13 16:15:41 -03:00
# define frames_to_ms(frames) \
( ( frames * WAKE_NUMERATOR * 1000 ) / WAKE_DENOMINATOR )
2010-04-10 04:13:53 -03:00
static void vivi_sleep ( struct vivi_dev * dev )
2006-03-10 12:40:10 -03:00
{
2008-04-02 18:10:59 -03:00
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
int timeout ;
2006-03-10 12:40:10 -03:00
DECLARE_WAITQUEUE ( wait , current ) ;
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s dma_q=0x%08lx \n " , __func__ ,
2007-12-13 13:30:14 -03:00
( unsigned long ) dma_q ) ;
2006-03-10 12:40:10 -03:00
add_wait_queue ( & dma_q - > wq , & wait ) ;
2007-12-13 16:15:41 -03:00
if ( kthread_should_stop ( ) )
goto stop_task ;
/* Calculate time to wake up */
2008-04-02 18:10:59 -03:00
timeout = msecs_to_jiffies ( frames_to_ms ( 1 ) ) ;
2007-12-13 16:15:41 -03:00
2010-04-10 04:13:53 -03:00
vivi_thread_tick ( dev ) ;
2007-12-13 16:15:41 -03:00
schedule_timeout_interruptible ( timeout ) ;
2006-03-10 12:40:10 -03:00
2007-12-13 16:15:41 -03:00
stop_task :
2006-03-10 12:40:10 -03:00
remove_wait_queue ( & dma_q - > wq , & wait ) ;
try_to_freeze ( ) ;
}
2006-04-27 21:06:50 -03:00
static int vivi_thread ( void * data )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = data ;
2006-03-10 12:40:10 -03:00
2007-12-13 13:30:14 -03:00
dprintk ( dev , 1 , " thread started \n " ) ;
2006-03-10 12:40:10 -03:00
2007-07-17 04:03:35 -07:00
set_freezable ( ) ;
2007-01-14 08:33:24 -03:00
2006-03-10 12:40:10 -03:00
for ( ; ; ) {
2010-04-10 04:13:53 -03:00
vivi_sleep ( dev ) ;
2006-03-10 12:40:10 -03:00
if ( kthread_should_stop ( ) )
break ;
}
2007-12-13 13:30:14 -03:00
dprintk ( dev , 1 , " thread: exit \n " ) ;
2006-03-10 12:40:10 -03:00
return 0 ;
}
2010-04-10 04:13:53 -03:00
static void vivi_start_generating ( struct file * file )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2008-04-02 18:10:59 -03:00
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
2007-12-13 13:30:14 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
if ( test_and_set_bit ( 0 , & dev - > generating ) )
return ;
file - > private_data = dev ;
/* Resets frame counters */
dev - > ms = 0 ;
dev - > mv_count = 0 ;
dev - > jiffies = jiffies ;
dma_q - > frame = 0 ;
dma_q - > ini_jiffies = jiffies ;
dma_q - > kthread = kthread_run ( vivi_thread , dev , dev - > v4l2_dev . name ) ;
2006-03-10 12:40:10 -03:00
2006-12-20 10:04:00 -03:00
if ( IS_ERR ( dma_q - > kthread ) ) {
2009-02-14 13:23:12 -03:00
v4l2_err ( & dev - > v4l2_dev , " kernel_thread() failed \n " ) ;
2010-04-10 04:13:53 -03:00
clear_bit ( 0 , & dev - > generating ) ;
return ;
2006-03-10 12:40:10 -03:00
}
2007-01-14 08:33:24 -03:00
/* Wakes thread */
wake_up_interruptible ( & dma_q - > wq ) ;
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " returning from %s \n " , __func__ ) ;
2006-03-10 12:40:10 -03:00
}
2010-04-10 04:13:53 -03:00
static void vivi_stop_generating ( struct file * file )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
struct vivi_dmaqueue * dma_q = & dev - > vidq ;
2007-12-13 13:30:14 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2010-04-10 04:13:53 -03:00
if ( ! file - > private_data )
return ;
if ( ! test_and_clear_bit ( 0 , & dev - > generating ) )
return ;
2006-03-10 12:40:10 -03:00
/* shutdown control thread */
if ( dma_q - > kthread ) {
kthread_stop ( dma_q - > kthread ) ;
2007-12-10 09:33:52 -03:00
dma_q - > kthread = NULL ;
2006-03-10 12:40:10 -03:00
}
2010-04-10 04:13:53 -03:00
videobuf_stop ( & dev - > vb_vidq ) ;
videobuf_mmap_free ( & dev - > vb_vidq ) ;
}
static int vivi_is_generating ( struct vivi_dev * dev )
{
return test_bit ( 0 , & dev - > generating ) ;
2006-03-10 12:40:10 -03:00
}
/* ------------------------------------------------------------------
Videobuf operations
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
buffer_setup ( struct videobuf_queue * vq , unsigned int * count , unsigned int * size )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = vq - > priv_data ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
* size = dev - > width * dev - > height * 2 ;
2006-03-10 12:40:10 -03:00
if ( 0 = = * count )
* count = 32 ;
2007-08-23 16:41:14 -03:00
2010-04-10 04:13:53 -03:00
while ( * size * * count > vid_limit * 1024 * 1024 )
( * count ) - - ;
2007-08-23 16:41:14 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s, count=%d, size=%d \n " , __func__ ,
2007-12-13 13:30:14 -03:00
* count , * size ) ;
2007-08-23 16:41:14 -03:00
2006-03-10 12:40:10 -03:00
return 0 ;
}
2006-04-27 21:06:50 -03:00
static void free_buffer ( struct videobuf_queue * vq , struct vivi_buffer * buf )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = vq - > priv_data ;
2007-12-13 13:30:14 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s, state: %i \n " , __func__ , buf - > vb . state ) ;
2006-03-10 12:40:10 -03:00
2007-08-02 23:31:54 -03:00
videobuf_vmalloc_free ( & buf - > vb ) ;
2008-04-13 14:57:44 -03:00
dprintk ( dev , 1 , " free_buffer: freed \n " ) ;
2007-11-06 20:02:36 -03:00
buf - > vb . state = VIDEOBUF_NEEDS_INIT ;
2006-03-10 12:40:10 -03:00
}
static int
buffer_prepare ( struct videobuf_queue * vq , struct videobuf_buffer * vb ,
enum v4l2_field field )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = vq - > priv_data ;
2007-12-10 09:33:52 -03:00
struct vivi_buffer * buf = container_of ( vb , struct vivi_buffer , vb ) ;
2008-04-02 18:10:59 -03:00
int rc ;
2006-03-10 12:40:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s, field=%d \n " , __func__ , field ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
BUG_ON ( NULL = = dev - > fmt ) ;
2008-04-02 18:10:59 -03:00
2010-04-10 04:13:53 -03:00
if ( dev - > width < 48 | | dev - > width > MAX_WIDTH | |
dev - > height < 32 | | dev - > height > MAX_HEIGHT )
2006-03-10 12:40:10 -03:00
return - EINVAL ;
2008-04-02 18:10:59 -03:00
2010-04-10 04:13:53 -03:00
buf - > vb . size = dev - > width * dev - > height * 2 ;
if ( 0 ! = buf - > vb . baddr & & buf - > vb . bsize < buf - > vb . size )
2006-03-10 12:40:10 -03:00
return - EINVAL ;
2008-04-02 18:10:59 -03:00
/* These properties only change when queue is idle, see s_fmt */
2010-04-10 04:13:53 -03:00
buf - > fmt = dev - > fmt ;
buf - > vb . width = dev - > width ;
buf - > vb . height = dev - > height ;
2008-04-02 18:10:59 -03:00
buf - > vb . field = field ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
precalculate_bars ( dev ) ;
precalculate_line ( dev ) ;
2009-06-25 16:28:23 -03:00
2007-11-06 20:02:36 -03:00
if ( VIDEOBUF_NEEDS_INIT = = buf - > vb . state ) {
2007-12-10 09:33:52 -03:00
rc = videobuf_iolock ( vq , & buf - > vb , NULL ) ;
if ( rc < 0 )
2006-03-10 12:40:10 -03:00
goto fail ;
}
2007-11-06 20:02:36 -03:00
buf - > vb . state = VIDEOBUF_PREPARED ;
2006-03-10 12:40:10 -03:00
return 0 ;
fail :
2007-12-10 09:33:52 -03:00
free_buffer ( vq , buf ) ;
2006-03-10 12:40:10 -03:00
return rc ;
}
static void
buffer_queue ( struct videobuf_queue * vq , struct videobuf_buffer * vb )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = vq - > priv_data ;
struct vivi_buffer * buf = container_of ( vb , struct vivi_buffer , vb ) ;
2008-04-02 18:10:59 -03:00
struct vivi_dmaqueue * vidq = & dev - > vidq ;
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2008-04-02 18:10:59 -03:00
buf - > vb . state = VIDEOBUF_QUEUED ;
list_add_tail ( & buf - > vb . queue , & vidq - > active ) ;
2006-03-10 12:40:10 -03:00
}
2007-12-10 09:33:52 -03:00
static void buffer_release ( struct videobuf_queue * vq ,
struct videobuf_buffer * vb )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = vq - > priv_data ;
struct vivi_buffer * buf = container_of ( vb , struct vivi_buffer , vb ) ;
2006-03-10 12:40:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 12:40:10 -03:00
2007-12-10 09:33:52 -03:00
free_buffer ( vq , buf ) ;
2006-03-10 12: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 10:34:12 -03:00
/* ------------------------------------------------------------------
IOCTL vidioc handling
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-12-10 09:33:52 -03:00
static int vidioc_querycap ( struct file * file , void * priv ,
2006-06-04 10:34:12 -03:00
struct v4l2_capability * cap )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2009-02-14 13:23:12 -03:00
2006-06-04 10:34:12 -03:00
strcpy ( cap - > driver , " vivi " ) ;
strcpy ( cap - > card , " vivi " ) ;
2009-02-14 13:23:12 -03:00
strlcpy ( cap - > bus_info , dev - > v4l2_dev . name , sizeof ( cap - > bus_info ) ) ;
2006-06-04 10:34:12 -03:00
cap - > version = VIVI_VERSION ;
2010-04-10 04:13:53 -03:00
cap - > capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
V4L2_CAP_READWRITE ;
2006-06-04 10:34:12 -03:00
return 0 ;
}
2008-05-28 12:16:41 -03:00
static int vidioc_enum_fmt_vid_cap ( struct file * file , void * priv ,
2006-06-04 10:34:12 -03:00
struct v4l2_fmtdesc * f )
{
2008-10-14 12:47:09 -03:00
struct vivi_fmt * fmt ;
if ( f - > index > = ARRAY_SIZE ( formats ) )
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2008-10-14 12:47:09 -03:00
fmt = & formats [ f - > index ] ;
strlcpy ( f - > description , fmt - > name , sizeof ( f - > description ) ) ;
f - > pixelformat = fmt - > fourcc ;
2006-06-04 10:34:12 -03:00
return 0 ;
}
2008-05-28 12:16:41 -03:00
static int vidioc_g_fmt_vid_cap ( struct file * file , void * priv ,
2006-06-04 10:34:12 -03:00
struct v4l2_format * f )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-06-04 10:34:12 -03:00
2010-04-10 04:13:53 -03:00
f - > fmt . pix . width = dev - > width ;
f - > fmt . pix . height = dev - > height ;
f - > fmt . pix . field = dev - > vb_vidq . field ;
f - > fmt . pix . pixelformat = dev - > fmt - > fourcc ;
2006-06-04 10:34:12 -03:00
f - > fmt . pix . bytesperline =
2010-04-10 04:13:53 -03:00
( f - > fmt . pix . width * dev - > fmt - > depth ) > > 3 ;
2006-06-04 10:34:12 -03:00
f - > fmt . pix . sizeimage =
f - > fmt . pix . height * f - > fmt . pix . bytesperline ;
2010-04-10 04:13:53 -03:00
return 0 ;
2006-06-04 10:34:12 -03:00
}
2008-05-28 12:16:41 -03:00
static int vidioc_try_fmt_vid_cap ( struct file * file , void * priv ,
2006-03-10 12:40:10 -03:00
struct v4l2_format * f )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
struct vivi_fmt * fmt ;
enum v4l2_field field ;
2008-10-14 12:47:09 -03:00
fmt = get_format ( f ) ;
if ( ! fmt ) {
dprintk ( dev , 1 , " Fourcc format (0x%08x) invalid. \n " ,
f - > fmt . pix . pixelformat ) ;
2006-03-10 12:40:10 -03:00
return - EINVAL ;
}
field = f - > fmt . pix . field ;
if ( field = = V4L2_FIELD_ANY ) {
2007-12-10 09:33:52 -03:00
field = V4L2_FIELD_INTERLACED ;
2006-03-10 12:40:10 -03:00
} else if ( V4L2_FIELD_INTERLACED ! = field ) {
2007-12-13 13:30:14 -03:00
dprintk ( dev , 1 , " Field type invalid. \n " ) ;
2006-03-10 12:40:10 -03:00
return - EINVAL ;
}
f - > fmt . pix . field = field ;
2010-04-10 04:13:53 -03:00
v4l_bound_align_image ( & f - > fmt . pix . width , 48 , MAX_WIDTH , 2 ,
& f - > fmt . pix . height , 32 , MAX_HEIGHT , 0 , 0 ) ;
2006-03-10 12:40:10 -03:00
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 ;
}
2009-01-11 10:29:43 -03:00
static int vidioc_s_fmt_vid_cap ( struct file * file , void * priv ,
struct v4l2_format * f )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2009-01-11 10:29:43 -03:00
2010-04-10 04:13:53 -03:00
int ret = vidioc_try_fmt_vid_cap ( file , priv , f ) ;
2009-01-11 10:29:43 -03:00
if ( ret < 0 )
return ret ;
2010-04-10 04:13:53 -03:00
if ( vivi_is_generating ( dev ) ) {
dprintk ( dev , 1 , " %s device busy \n " , __func__ ) ;
2009-01-11 10:29:43 -03:00
ret = - EBUSY ;
goto out ;
}
2010-04-10 04:13:53 -03:00
dev - > fmt = get_format ( f ) ;
dev - > width = f - > fmt . pix . width ;
dev - > height = f - > fmt . pix . height ;
dev - > vb_vidq . field = f - > fmt . pix . field ;
2008-04-02 18:10:59 -03:00
ret = 0 ;
out :
2009-01-11 10:29:43 -03:00
return ret ;
2006-03-10 12:40:10 -03:00
}
2007-12-10 09:33:52 -03:00
static int vidioc_reqbufs ( struct file * file , void * priv ,
struct v4l2_requestbuffers * p )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
return videobuf_reqbufs ( & dev - > vb_vidq , p ) ;
2006-03-10 12:40:10 -03:00
}
2007-12-10 09:33:52 -03:00
static int vidioc_querybuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
return videobuf_querybuf ( & dev - > vb_vidq , p ) ;
2006-06-04 10:34:12 -03:00
}
2006-03-10 12:40:10 -03:00
2007-12-10 09:33:52 -03:00
static int vidioc_qbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
return videobuf_qbuf ( & dev - > vb_vidq , p ) ;
2006-06-04 10:34:12 -03:00
}
2006-03-10 12:40:10 -03:00
2007-12-10 09:33:52 -03:00
static int vidioc_dqbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
return videobuf_dqbuf ( & dev - > vb_vidq , p ,
file - > f_flags & O_NONBLOCK ) ;
2006-06-04 10:34:12 -03:00
}
2006-03-10 12:40:10 -03:00
2006-06-23 06:42:44 -03:00
static int vidioc_streamon ( struct file * file , void * priv , enum v4l2_buf_type i )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
int ret ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
if ( i ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2010-04-10 04:13:53 -03:00
ret = videobuf_streamon ( & dev - > vb_vidq ) ;
if ( ret )
return ret ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
vivi_start_generating ( file ) ;
return 0 ;
2006-06-04 10:34:12 -03:00
}
2006-03-10 12:40:10 -03:00
2006-06-23 06:42:44 -03:00
static int vidioc_streamoff ( struct file * file , void * priv , enum v4l2_buf_type i )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
int ret ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
if ( i ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2010-04-10 04:13:53 -03:00
ret = videobuf_streamoff ( & dev - > vb_vidq ) ;
if ( ! ret )
vivi_stop_generating ( file ) ;
return ret ;
2006-06-04 10:34:12 -03:00
}
2007-12-10 09:33:52 -03:00
static int vidioc_s_std ( struct file * file , void * priv , v4l2_std_id * i )
2006-06-04 10:34:12 -03:00
{
return 0 ;
}
2006-03-10 12:40:10 -03:00
2006-06-04 10:34:12 -03:00
/* only one input in this sample driver */
2007-12-10 09:33:52 -03:00
static int vidioc_enum_input ( struct file * file , void * priv ,
2006-06-04 10:34:12 -03:00
struct v4l2_input * inp )
{
2009-01-11 10:29:43 -03:00
if ( inp - > index > = NUM_INPUTS )
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2006-03-10 12:40:10 -03:00
2006-06-04 10:34:12 -03:00
inp - > type = V4L2_INPUT_TYPE_CAMERA ;
2007-12-13 06:35:26 -03:00
inp - > std = V4L2_STD_525_60 ;
2009-01-11 10:29:43 -03:00
sprintf ( inp - > name , " Camera %u " , inp - > index ) ;
2010-04-10 04:13:53 -03:00
return 0 ;
2006-06-04 10:34:12 -03:00
}
2006-03-10 12:40:10 -03:00
2007-12-10 09:33:52 -03:00
static int vidioc_g_input ( struct file * file , void * priv , unsigned int * i )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2009-01-11 10:29:43 -03:00
* i = dev - > input ;
2010-04-10 04:13:53 -03:00
return 0 ;
2006-06-04 10:34:12 -03:00
}
2010-04-10 04:13:53 -03:00
2007-12-10 09:33:52 -03:00
static int vidioc_s_input ( struct file * file , void * priv , unsigned int i )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2009-01-11 10:29:43 -03:00
if ( i > = NUM_INPUTS )
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2006-03-10 12:40:10 -03:00
2009-01-11 10:29:43 -03:00
dev - > input = i ;
2010-04-10 04:13:53 -03:00
precalculate_bars ( dev ) ;
precalculate_line ( dev ) ;
return 0 ;
2006-06-04 10:34:12 -03:00
}
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
/* --- controls ---------------------------------------------- */
2007-12-10 09:33:52 -03:00
static int vidioc_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * qc )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
switch ( qc - > id ) {
case V4L2_CID_AUDIO_VOLUME :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 200 ) ;
case V4L2_CID_BRIGHTNESS :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 127 ) ;
case V4L2_CID_CONTRAST :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 16 ) ;
case V4L2_CID_SATURATION :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 127 ) ;
case V4L2_CID_HUE :
return v4l2_ctrl_query_fill ( qc , - 128 , 127 , 1 , 0 ) ;
}
2006-06-04 10:34:12 -03:00
return - EINVAL ;
}
2006-03-10 12:40:10 -03:00
2007-12-10 09:33:52 -03:00
static int vidioc_g_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
2006-06-04 10:34:12 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_AUDIO_VOLUME :
ctrl - > value = dev - > volume ;
return 0 ;
case V4L2_CID_BRIGHTNESS :
ctrl - > value = dev - > brightness ;
return 0 ;
case V4L2_CID_CONTRAST :
ctrl - > value = dev - > contrast ;
return 0 ;
case V4L2_CID_SATURATION :
ctrl - > value = dev - > saturation ;
return 0 ;
case V4L2_CID_HUE :
ctrl - > value = dev - > hue ;
return 0 ;
}
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2006-03-10 12:40:10 -03:00
}
2010-04-10 04:13:53 -03:00
2007-12-10 09:33:52 -03:00
static int vidioc_s_ctrl ( struct file * file , void * priv ,
2006-06-04 10:34:12 -03:00
struct v4l2_control * ctrl )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
struct v4l2_queryctrl qc ;
int err ;
qc . id = ctrl - > id ;
err = vidioc_queryctrl ( file , priv , & qc ) ;
if ( err < 0 )
return err ;
if ( ctrl - > value < qc . minimum | | ctrl - > value > qc . maximum )
return - ERANGE ;
switch ( ctrl - > id ) {
case V4L2_CID_AUDIO_VOLUME :
dev - > volume = ctrl - > value ;
return 0 ;
case V4L2_CID_BRIGHTNESS :
dev - > brightness = ctrl - > value ;
return 0 ;
case V4L2_CID_CONTRAST :
dev - > contrast = ctrl - > value ;
return 0 ;
case V4L2_CID_SATURATION :
dev - > saturation = ctrl - > value ;
return 0 ;
case V4L2_CID_HUE :
dev - > hue = ctrl - > value ;
return 0 ;
}
2006-06-04 10:34:12 -03:00
return - EINVAL ;
2006-03-10 12:40:10 -03:00
}
/* ------------------------------------------------------------------
File operations for the device
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static ssize_t
vivi_read ( struct file * file , char __user * data , size_t count , loff_t * ppos )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
vivi_start_generating ( file ) ;
return videobuf_read_stream ( & dev - > vb_vidq , data , count , ppos , 0 ,
2006-03-10 12:40:10 -03:00
file - > f_flags & O_NONBLOCK ) ;
}
static unsigned int
vivi_poll ( struct file * file , struct poll_table_struct * wait )
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
struct videobuf_queue * q = & dev - > vb_vidq ;
2006-03-10 12:40:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( dev , 1 , " %s \n " , __func__ ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
vivi_start_generating ( file ) ;
2007-09-27 20:55:02 -03:00
return videobuf_poll_stream ( file , q , wait ) ;
2006-03-10 12:40:10 -03:00
}
2008-12-30 06:58:20 -03:00
static int vivi_close ( struct file * file )
2006-03-10 12:40:10 -03:00
{
2009-12-10 11:47:13 -02:00
struct video_device * vdev = video_devdata ( file ) ;
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
vivi_stop_generating ( file ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
dprintk ( dev , 1 , " close called (dev=%s) \n " ,
video_device_node_name ( vdev ) ) ;
2006-03-10 12:40:10 -03:00
return 0 ;
}
2007-12-10 09:33:52 -03:00
static int vivi_mmap ( struct file * file , struct vm_area_struct * vma )
2006-03-10 12:40:10 -03:00
{
2010-04-10 04:13:53 -03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2006-03-10 12:40:10 -03:00
int ret ;
2007-12-13 13:30:14 -03:00
dprintk ( dev , 1 , " mmap called, vma=0x%08lx \n " , ( unsigned long ) vma ) ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
ret = videobuf_mmap_mapper ( & dev - > vb_vidq , vma ) ;
2006-03-10 12:40:10 -03:00
2007-12-13 13:30:14 -03:00
dprintk ( dev , 1 , " vma start=0x%08lx, size=%ld, ret=%d \n " ,
2006-03-10 12:40:10 -03:00
( unsigned long ) vma - > vm_start ,
2010-04-10 04:13:53 -03:00
( unsigned long ) vma - > vm_end - ( unsigned long ) vma - > vm_start ,
2006-03-10 12:40:10 -03:00
ret ) ;
return ret ;
}
2008-12-30 06:58:20 -03:00
static const struct v4l2_file_operations vivi_fops = {
2006-03-10 12:40:10 -03:00
. owner = THIS_MODULE ,
2007-12-10 04:07:03 -03:00
. release = vivi_close ,
2006-03-10 12:40:10 -03:00
. read = vivi_read ,
. poll = vivi_poll ,
2010-09-20 18:25:55 -03:00
. unlocked_ioctl = video_ioctl2 , /* V4L2 ioctl handler */
2007-08-02 23:31:54 -03:00
. mmap = vivi_mmap ,
2006-03-10 12:40:10 -03:00
} ;
2008-07-21 02:57:38 -03:00
static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
2006-06-04 10:34:12 -03:00
. vidioc_querycap = vidioc_querycap ,
2008-05-28 12:16:41 -03: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 10:34:12 -03: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 ,
2010-04-10 04:13:53 -03:00
. vidioc_streamon = vidioc_streamon ,
. vidioc_streamoff = vidioc_streamoff ,
2006-06-04 10:34:12 -03:00
. vidioc_queryctrl = vidioc_queryctrl ,
. vidioc_g_ctrl = vidioc_g_ctrl ,
. vidioc_s_ctrl = vidioc_s_ctrl ,
2008-07-21 02:57:38 -03:00
} ;
static struct video_device vivi_template = {
. name = " vivi " ,
. fops = & vivi_fops ,
. ioctl_ops = & vivi_ioctl_ops ,
. release = video_device_release ,
2007-12-13 06:35:26 -03:00
. tvnorms = V4L2_STD_525_60 ,
2006-11-20 13:19:20 -03:00
. current_norm = V4L2_STD_NTSC_M ,
2006-03-10 12:40:10 -03:00
} ;
2009-02-14 13:23:12 -03:00
2006-06-04 10:34:12 -03:00
/* -----------------------------------------------------------------
2006-03-10 12:40:10 -03:00
Initialization and module stuff
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2009-02-14 13:23:12 -03:00
static int vivi_release ( void )
{
struct vivi_dev * dev ;
struct list_head * list ;
2008-09-03 17:11:53 -03:00
2009-02-14 13:23:12 -03:00
while ( ! list_empty ( & vivi_devlist ) ) {
list = vivi_devlist . next ;
list_del ( list ) ;
dev = list_entry ( list , struct vivi_dev , vivi_devlist ) ;
2009-11-27 13:57:15 -03:00
v4l2_info ( & dev - > v4l2_dev , " unregistering %s \n " ,
video_device_node_name ( dev - > vfd ) ) ;
2009-02-14 13:23:12 -03:00
video_unregister_device ( dev - > vfd ) ;
v4l2_device_unregister ( & dev - > v4l2_dev ) ;
kfree ( dev ) ;
}
return 0 ;
}
2009-02-14 13:43:44 -03:00
static int __init vivi_create_instance ( int inst )
2006-03-10 12:40:10 -03:00
{
struct vivi_dev * dev ;
2007-12-10 04:07:03 -03:00
struct video_device * vfd ;
2010-04-10 04:13:53 -03:00
int ret ;
2006-03-10 12:40:10 -03:00
2009-02-14 13:23:12 -03:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev )
return - ENOMEM ;
2008-09-03 17:11:53 -03:00
2009-02-14 13:23:12 -03:00
snprintf ( dev - > v4l2_dev . name , sizeof ( dev - > v4l2_dev . name ) ,
2009-02-14 13:43:44 -03:00
" %s-%03d " , VIVI_MODULE_NAME , inst ) ;
2009-02-14 13:23:12 -03:00
ret = v4l2_device_register ( NULL , & dev - > v4l2_dev ) ;
if ( ret )
goto free_dev ;
2006-03-10 12:40:10 -03:00
2010-04-10 04:13:53 -03:00
dev - > fmt = & formats [ 0 ] ;
dev - > width = 640 ;
dev - > height = 480 ;
dev - > volume = 200 ;
dev - > brightness = 127 ;
dev - > contrast = 16 ;
dev - > saturation = 127 ;
dev - > hue = 0 ;
2010-09-20 18:25:55 -03:00
/* initialize locks */
spin_lock_init ( & dev - > slock ) ;
mutex_init ( & dev - > mutex ) ;
2010-04-10 04:13:53 -03:00
videobuf_queue_vmalloc_init ( & dev - > vb_vidq , & vivi_video_qops ,
NULL , & dev - > slock , V4L2_BUF_TYPE_VIDEO_CAPTURE ,
V4L2_FIELD_INTERLACED ,
2010-09-20 18:25:55 -03:00
sizeof ( struct vivi_buffer ) , dev , & dev - > mutex ) ;
2010-04-10 04:13:53 -03:00
2009-02-14 13:23:12 -03:00
/* init video dma queues */
INIT_LIST_HEAD ( & dev - > vidq . active ) ;
init_waitqueue_head ( & dev - > vidq . wq ) ;
2006-03-10 12:40:10 -03:00
2009-02-14 13:23:12 -03:00
ret = - ENOMEM ;
vfd = video_device_alloc ( ) ;
if ( ! vfd )
goto unreg_dev ;
2007-12-10 04:38:11 -03:00
2009-02-14 13:23:12 -03:00
* vfd = vivi_template ;
2009-06-25 16:28:23 -03:00
vfd - > debug = debug ;
2010-04-10 04:13:53 -03:00
vfd - > v4l2_dev = & dev - > v4l2_dev ;
2010-09-20 18:25:55 -03:00
vfd - > lock = & dev - > mutex ;
2007-12-10 04:38:11 -03:00
2009-02-14 13:23:12 -03:00
ret = video_register_device ( vfd , VFL_TYPE_GRABBER , video_nr ) ;
if ( ret < 0 )
goto rel_vdev ;
2008-09-03 17:11:53 -03:00
2009-02-14 13:23:12 -03:00
video_set_drvdata ( vfd , dev ) ;
2008-09-03 17:11:53 -03:00
2009-02-14 13:23:12 -03:00
/* Now that everything is fine, let's add it to device list */
list_add_tail ( & dev - > vivi_devlist , & vivi_devlist ) ;
2008-09-03 17:11:53 -03:00
2009-12-16 13:06:33 -03:00
if ( video_nr ! = - 1 )
2009-02-14 13:23:12 -03:00
video_nr + + ;
2007-12-10 04:07:03 -03:00
2009-02-14 13:23:12 -03:00
dev - > vfd = vfd ;
2009-11-27 13:57:15 -03:00
v4l2_info ( & dev - > v4l2_dev , " V4L2 device registered as %s \n " ,
video_device_node_name ( vfd ) ) ;
2009-02-14 13:23:12 -03:00
return 0 ;
rel_vdev :
video_device_release ( vfd ) ;
unreg_dev :
v4l2_device_unregister ( & dev - > v4l2_dev ) ;
free_dev :
kfree ( dev ) ;
return ret ;
}
2007-12-10 04:07:03 -03:00
2009-02-14 13:23:12 -03: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 , which is equal to VIDEO_NUM_DEVICES .
*/
static int __init vivi_init ( void )
{
2010-04-10 04:13:53 -03:00
const struct font_desc * font = find_font ( " VGA8x16 " ) ;
2009-03-06 09:58:12 -03:00
int ret = 0 , i ;
2009-02-14 13:23:12 -03:00
2010-04-10 04:13:53 -03:00
if ( font = = NULL ) {
printk ( KERN_ERR " vivi: could not find font \n " ) ;
return - ENODEV ;
}
font8x16 = font - > data ;
2009-02-14 13:23:12 -03:00
if ( n_devs < = 0 )
n_devs = 1 ;
for ( i = 0 ; i < n_devs ; i + + ) {
ret = vivi_create_instance ( i ) ;
if ( ret ) {
/* If some instantiations succeeded, keep driver */
if ( i )
ret = 0 ;
break ;
}
2007-12-10 04:38:11 -03:00
}
2007-12-10 04:07:03 -03:00
2007-12-10 04:38:11 -03:00
if ( ret < 0 ) {
2010-04-10 04:13:53 -03:00
printk ( KERN_ERR " vivi: error %d while loading driver \n " , ret ) ;
2009-02-14 13:23:12 -03:00
return ret ;
}
printk ( KERN_INFO " Video Technology Magazine Virtual Video "
2008-06-10 00:02:32 -03:00
" Capture Board ver %u.%u.%u successfully loaded. \n " ,
( VIVI_VERSION > > 16 ) & 0xFF , ( VIVI_VERSION > > 8 ) & 0xFF ,
VIVI_VERSION & 0xFF ) ;
2008-09-03 17:11:53 -03:00
2009-02-14 13:23:12 -03:00
/* n_devs will reflect the actual number of allocated devices */
n_devs = i ;
2008-09-03 17:11:53 -03:00
2006-03-10 12:40:10 -03:00
return ret ;
}
static void __exit vivi_exit ( void )
{
2007-12-10 04:38:11 -03:00
vivi_release ( ) ;
2006-03-10 12:40:10 -03:00
}
module_init ( vivi_init ) ;
module_exit ( vivi_exit ) ;