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-03-24 04:01:44 +03:00
# include <linux/interrupt.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>
2009-02-14 19:23:12 +03:00
# include <media/videobuf-vmalloc.h>
# include <media/v4l2-device.h>
# include <media/v4l2-ioctl.h>
# include "font.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 */
# define VIVI_MAJOR_VERSION 0
2009-02-14 19:23:12 +03:00
# define VIVI_MINOR_VERSION 6
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
2009-02-14 19: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 " ) ;
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 ,
2009-02-14 19:50:19 +03:00
. flags = V4L2_CTRL_FLAG_SLIDER ,
2006-03-10 18:40:10 +03:00
. 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 ,
2009-02-14 19:50:19 +03:00
. flags = V4L2_CTRL_FLAG_SLIDER ,
2006-03-10 18:40:10 +03:00
} , {
. id = V4L2_CID_CONTRAST ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Contrast " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
. default_value = 0x10 ,
2009-02-14 19:50:19 +03:00
. flags = V4L2_CTRL_FLAG_SLIDER ,
2006-03-10 18:40:10 +03:00
} , {
. id = V4L2_CID_SATURATION ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Saturation " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
. default_value = 127 ,
2009-02-14 19:50:19 +03:00
. flags = V4L2_CTRL_FLAG_SLIDER ,
2006-03-10 18:40:10 +03:00
} , {
. id = V4L2_CID_HUE ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Hue " ,
. minimum = - 128 ,
. maximum = 127 ,
. step = 0x1 ,
. default_value = 0 ,
2009-02-14 19:50:19 +03:00
. flags = V4L2_CTRL_FLAG_SLIDER ,
2006-03-10 18:40:10 +03:00
}
} ;
2009-02-14 19:23:12 +03:00
# define dprintk(dev, level, fmt, arg...) \
v4l2_dbg ( level , debug , & dev - > v4l2_dev , fmt , # # arg )
2006-03-10 18:40:10 +03:00
/* ------------------------------------------------------------------
Basic structures
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
struct vivi_fmt {
char * name ;
u32 fourcc ; /* v4l2 format id */
int depth ;
} ;
2008-10-14 19:47:09 +04:00
static struct vivi_fmt formats [ ] = {
{
. name = " 4:2:2, packed, YUYV " ,
. fourcc = V4L2_PIX_FMT_YUYV ,
. depth = 16 ,
} ,
2008-10-14 19:47:25 +04:00
{
. name = " 4:2:2, packed, UYVY " ,
. fourcc = V4L2_PIX_FMT_UYVY ,
. depth = 16 ,
} ,
2008-10-14 19:47:35 +04: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 19:47:43 +04: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 18:40:10 +03:00
} ;
2008-10-14 19:47:09 +04: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 18: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 19:23:12 +03:00
struct v4l2_device v4l2_dev ;
2006-03-10 18:40:10 +03:00
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 */
2009-01-11 16:29:43 +03:00
/* Input Number */
int input ;
2009-02-14 19:43:44 +03:00
/* Control 'registers' */
int qctl_regs [ ARRAY_SIZE ( vivi_qctrl ) ] ;
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 ;
2008-10-14 19:46:59 +04:00
unsigned char bars [ 8 ] [ 3 ] ;
2009-01-11 16:29:43 +03:00
int input ; /* Input Number on bars */
2006-03-10 18:40:10 +03:00
} ;
/* ------------------------------------------------------------------
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
} ;
/* R G B */
2009-01-11 16:29:43 +03:00
# define COLOR_WHITE {204, 204, 204}
# define COLOR_AMBAR {208, 208, 0}
# define COLOR_CIAN { 0, 206, 206}
# 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 {
u8 bar [ 8 ] [ 3 ] ;
} ;
/* 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 */
{
COLOR_WHITE ,
COLOR_AMBAR ,
COLOR_CIAN ,
COLOR_GREEN ,
COLOR_MAGENTA ,
COLOR_RED ,
COLOR_BLUE ,
COLOR_BLACK ,
}
} , {
{
COLOR_WHITE ,
COLOR_AMBAR ,
COLOR_BLACK ,
COLOR_WHITE ,
COLOR_AMBAR ,
COLOR_BLACK ,
COLOR_WHITE ,
COLOR_AMBAR ,
}
} , {
{
COLOR_WHITE ,
COLOR_CIAN ,
COLOR_BLACK ,
COLOR_WHITE ,
COLOR_CIAN ,
COLOR_BLACK ,
COLOR_WHITE ,
COLOR_CIAN ,
}
} , {
{
COLOR_WHITE ,
COLOR_GREEN ,
COLOR_BLACK ,
COLOR_WHITE ,
COLOR_GREEN ,
COLOR_BLACK ,
COLOR_WHITE ,
COLOR_GREEN ,
}
} ,
2006-03-10 18:40:10 +03:00
} ;
2009-01-11 16:29:43 +03:00
# define NUM_INPUTS ARRAY_SIZE(bars)
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
2009-06-25 23:28:23 +04:00
/* precalculate color bar values to speed up rendering */
static void precalculate_bars ( struct vivi_fh * fh )
{
struct vivi_dev * dev = fh - > dev ;
unsigned char r , g , b ;
int k , is_yuv ;
fh - > input = dev - > input ;
for ( k = 0 ; k < 8 ; k + + ) {
r = bars [ fh - > input ] . bar [ k ] [ 0 ] ;
g = bars [ fh - > input ] . bar [ k ] [ 1 ] ;
b = bars [ fh - > input ] . bar [ k ] [ 2 ] ;
is_yuv = 0 ;
switch ( fh - > fmt - > fourcc ) {
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 ) {
fh - > bars [ k ] [ 0 ] = TO_Y ( r , g , b ) ; /* Luma */
fh - > bars [ k ] [ 1 ] = TO_U ( r , g , b ) ; /* Cb */
fh - > bars [ k ] [ 2 ] = TO_V ( r , g , b ) ; /* Cr */
} else {
fh - > bars [ k ] [ 0 ] = r ;
fh - > bars [ k ] [ 1 ] = g ;
fh - > bars [ k ] [ 2 ] = b ;
}
}
}
2009-01-11 16: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 18:40:10 +03:00
2008-10-14 19:46:59 +04:00
static void gen_twopix ( struct vivi_fh * fh , unsigned char * buf , int colorpos )
{
unsigned char r_y , g_u , b_v ;
unsigned char * p ;
int color ;
r_y = fh - > bars [ colorpos ] [ 0 ] ; /* R or precalculated Y */
g_u = fh - > bars [ colorpos ] [ 1 ] ; /* G or precalculated U */
b_v = fh - > bars [ colorpos ] [ 2 ] ; /* B or precalculated V */
for ( color = 0 ; color < 4 ; color + + ) {
p = buf + color ;
2008-10-14 19:47:09 +04:00
switch ( fh - > fmt - > fourcc ) {
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 19:46:59 +04:00
break ;
2008-10-14 19:47:25 +04: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 19:47:35 +04: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 19:47:43 +04: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 19:46:59 +04:00
}
}
}
static void gen_line ( struct vivi_fh * fh , char * basep , int inipos , int wmax ,
2007-12-10 15:33:52 +03:00
int hmax , int line , int count , char * timestr )
2006-03-10 18:40:10 +03:00
{
2008-10-14 19:46:59 +04:00
int w , i , j ;
2007-12-10 15:33:52 +03:00
int pos = inipos ;
2008-10-14 19:46:59 +04:00
char * s ;
u8 chr ;
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 ;
2008-10-14 19:46:59 +04:00
gen_twopix ( fh , basep + pos , colorpos ) ;
pos + = 4 ; /* only 16 bpp supported for now */
2006-03-10 18:40:10 +03:00
}
2009-01-11 16:29:43 +03:00
/* Prints input entry number */
/* Checks if it is possible to input number */
2007-12-10 15:33:52 +03:00
if ( TSTAMP_MAX_Y > = hmax )
2006-03-10 18:40:10 +03:00
goto end ;
2009-01-11 16:29:43 +03:00
if ( TSTAMP_INPUT_X + strlen ( timestr ) > = wmax )
goto end ;
if ( line > = TSTAMP_MIN_Y & & line < = TSTAMP_MAX_Y ) {
chr = rom8x16_bits [ fh - > input * 16 + line - TSTAMP_MIN_Y ] ;
pos = TSTAMP_INPUT_X ;
for ( i = 0 ; i < 7 ; i + + ) {
/* Draw white font on black background */
if ( chr & 1 < < ( 7 - i ) )
gen_twopix ( fh , basep + pos , WHITE ) ;
else
gen_twopix ( fh , basep + pos , BLACK ) ;
pos + = 2 ;
}
}
/* Checks if it is possible to show timestamp */
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 + + ) {
pos = inipos + j * 2 ;
2008-10-14 19:46:59 +04:00
/* Draw white font on black background */
if ( chr & 1 < < ( 7 - i ) )
gen_twopix ( fh , basep + pos , WHITE ) ;
else
gen_twopix ( fh , basep + pos , BLACK ) ;
2006-03-10 18:40:10 +03:00
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
2008-10-14 19:46:59 +04:00
static void vivi_fillbuff ( struct vivi_fh * fh , struct vivi_buffer * buf )
2006-03-10 18:40:10 +03:00
{
2008-10-14 19:46:59 +04:00
struct vivi_dev * dev = fh - > dev ;
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 + + ) {
2008-10-14 19:46:59 +04:00
gen_line ( fh , 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 */
2008-10-14 19:46:59 +04:00
vivi_fillbuff ( fh , buf ) ;
2008-04-03 01:10:59 +04: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 ) ;
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 ) ) {
2009-02-14 19:23:12 +03:00
v4l2_err ( & dev - > v4l2_dev , " 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
2009-06-25 23:28:23 +04:00
precalculate_bars ( fh ) ;
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 )
{
2009-02-14 19:23:12 +03:00
struct vivi_fh * fh = priv ;
struct vivi_dev * dev = fh - > dev ;
2006-06-04 17:34:12 +04:00
strcpy ( cap - > driver , " vivi " ) ;
strcpy ( cap - > card , " vivi " ) ;
2009-02-14 19:23:12 +03:00
strlcpy ( cap - > bus_info , dev - > v4l2_dev . name , sizeof ( cap - > bus_info ) ) ;
2006-06-04 17:34:12 +04:00
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 )
{
2008-10-14 19:47:09 +04:00
struct vivi_fmt * fmt ;
if ( f - > index > = ARRAY_SIZE ( formats ) )
2006-06-04 17:34:12 +04:00
return - EINVAL ;
2008-10-14 19:47:09 +04:00
fmt = & formats [ f - > index ] ;
strlcpy ( f - > description , fmt - > name , sizeof ( f - > description ) ) ;
f - > pixelformat = fmt - > fourcc ;
2006-06-04 17:34:12 +04:00
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 ;
2008-10-14 19:47:09 +04:00
fmt = get_format ( f ) ;
if ( ! fmt ) {
dprintk ( dev , 1 , " Fourcc format (0x%08x) invalid. \n " ,
f - > fmt . pix . pixelformat ) ;
2006-03-10 18:40:10 +03:00
return - EINVAL ;
}
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 ;
2009-05-31 04:45:46 +04:00
v4l_bound_align_image ( & f - > fmt . pix . width , 48 , maxw , 2 ,
& f - > fmt . pix . height , 32 , maxh , 0 , 0 ) ;
2006-03-10 18: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 16:29:43 +03:00
/*FIXME: This seems to be generic enough to be at videodev2 */
static int vidioc_s_fmt_vid_cap ( struct file * file , void * priv ,
struct v4l2_format * f )
{
struct vivi_fh * fh = priv ;
struct videobuf_queue * q = & fh - > vb_vidq ;
int ret = vidioc_try_fmt_vid_cap ( file , fh , f ) ;
if ( ret < 0 )
return ret ;
mutex_lock ( & q - > vb_lock ) ;
if ( videobuf_queue_is_busy ( & fh - > vb_vidq ) ) {
dprintk ( fh - > dev , 1 , " %s queue busy \n " , __func__ ) ;
ret = - EBUSY ;
goto out ;
}
fh - > fmt = get_format ( f ) ;
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 ) ;
2009-01-11 16:29:43 +03:00
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 )
{
2009-01-11 16:29:43 +03:00
if ( inp - > index > = NUM_INPUTS )
2006-06-04 17:34:12 +04:00
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 ;
2009-01-11 16:29:43 +03:00
sprintf ( inp - > name , " Camera %u " , inp - > index ) ;
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
{
2009-01-11 16:29:43 +03:00
struct vivi_fh * fh = priv ;
struct vivi_dev * dev = fh - > dev ;
* i = dev - > input ;
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
{
2009-01-11 16:29:43 +03:00
struct vivi_fh * fh = priv ;
struct vivi_dev * dev = fh - > dev ;
if ( i > = NUM_INPUTS )
2006-06-04 17:34:12 +04:00
return - EINVAL ;
2006-03-10 18:40:10 +03:00
2009-01-11 16:29:43 +03:00
dev - > input = i ;
precalculate_bars ( fh ) ;
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
{
2009-02-14 19:43:44 +03:00
struct vivi_fh * fh = priv ;
struct vivi_dev * dev = fh - > dev ;
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 ) {
2009-02-14 19:43:44 +03:00
ctrl - > value = dev - > qctl_regs [ i ] ;
return 0 ;
2006-06-04 17:34:12 +04:00
}
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
{
2009-02-14 19:43:44 +03:00
struct vivi_fh * fh = priv ;
struct vivi_dev * dev = fh - > dev ;
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 ) {
2009-02-14 19:43:44 +03:00
if ( ctrl - > value < vivi_qctrl [ i ] . minimum | |
ctrl - > value > vivi_qctrl [ i ] . maximum ) {
return - ERANGE ;
}
dev - > qctl_regs [ i ] = ctrl - > value ;
return 0 ;
2006-06-04 17:34:12 +04:00
}
return - EINVAL ;
2006-03-10 18:40:10 +03:00
}
/* ------------------------------------------------------------------
File operations for the device
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2008-12-30 12:58:20 +03:00
static int vivi_open ( struct file * file )
2006-03-10 18:40:10 +03:00
{
2009-02-14 19:23:12 +03:00
struct vivi_dev * dev = video_drvdata ( file ) ;
2008-04-26 15:25:18 +04:00
struct vivi_fh * fh = NULL ;
2008-04-03 01:10:59 +04:00
int retval = 0 ;
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
if ( dev - > users > 1 ) {
dev - > users - - ;
2009-02-14 19:23:12 +03:00
mutex_unlock ( & dev - > mutex ) ;
return - EBUSY ;
2008-04-03 01:10:59 +04:00
}
2009-11-27 19:57:15 +03:00
dprintk ( dev , 1 , " open %s type=%s users=%d \n " ,
video_device_node_name ( dev - > vfd ) ,
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 ;
2006-03-10 18:40:10 +03:00
}
2008-04-03 01:10:59 +04:00
mutex_unlock ( & dev - > mutex ) ;
2009-02-14 19:23:12 +03:00
if ( retval )
2008-04-03 01:10:59 +04:00
return retval ;
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 ;
2008-10-14 19:47:09 +04:00
fh - > fmt = & formats [ 0 ] ;
2006-03-10 18:40:10 +03:00
fh - > width = 640 ;
fh - > height = 480 ;
/* 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 ) ;
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
}
2008-12-30 12:58:20 +03:00
static int vivi_close ( 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 ;
2009-12-10 16:47:13 +03:00
struct video_device * vdev = video_devdata ( file ) ;
2006-03-10 18:40:10 +03:00
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
2009-12-10 16:47:13 +03:00
dprintk ( dev , 1 , " close called (dev=%s, users=%d) \n " ,
video_device_node_name ( vdev ) , dev - > users ) ;
2006-03-10 18:40:10 +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 ;
}
2008-12-30 12:58:20 +03:00
static const struct v4l2_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 */
2007-08-03 06:31:54 +04:00
. mmap = vivi_mmap ,
2006-03-10 18:40:10 +03:00
} ;
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 ,
. 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
} ;
2009-02-14 19:23:12 +03:00
2006-06-04 17:34:12 +04:00
/* -----------------------------------------------------------------
2006-03-10 18:40:10 +03:00
Initialization and module stuff
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2009-02-14 19:23:12 +03:00
static int vivi_release ( void )
{
struct vivi_dev * dev ;
struct list_head * list ;
2008-09-04 00:11:53 +04:00
2009-02-14 19: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 19:57:15 +03:00
v4l2_info ( & dev - > v4l2_dev , " unregistering %s \n " ,
video_device_node_name ( dev - > vfd ) ) ;
2009-02-14 19:23:12 +03:00
video_unregister_device ( dev - > vfd ) ;
v4l2_device_unregister ( & dev - > v4l2_dev ) ;
kfree ( dev ) ;
}
return 0 ;
}
2009-02-14 19:43:44 +03:00
static int __init vivi_create_instance ( int inst )
2006-03-10 18:40:10 +03:00
{
struct vivi_dev * dev ;
2007-12-10 10:07:03 +03:00
struct video_device * vfd ;
2009-02-14 19:43:44 +03:00
int ret , i ;
2006-03-10 18:40:10 +03:00
2009-02-14 19:23:12 +03:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev )
return - ENOMEM ;
2008-09-04 00:11:53 +04:00
2009-02-14 19:23:12 +03:00
snprintf ( dev - > v4l2_dev . name , sizeof ( dev - > v4l2_dev . name ) ,
2009-02-14 19:43:44 +03:00
" %s-%03d " , VIVI_MODULE_NAME , inst ) ;
2009-02-14 19:23:12 +03:00
ret = v4l2_device_register ( NULL , & dev - > v4l2_dev ) ;
if ( ret )
goto free_dev ;
2006-03-10 18:40:10 +03:00
2009-02-14 19:23:12 +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
2009-02-14 19:23:12 +03:00
/* initialize locks */
spin_lock_init ( & dev - > slock ) ;
mutex_init ( & dev - > mutex ) ;
2006-03-10 18:40:10 +03:00
2009-02-14 19:23:12 +03:00
ret = - ENOMEM ;
vfd = video_device_alloc ( ) ;
if ( ! vfd )
goto unreg_dev ;
2007-12-10 10:38:11 +03:00
2009-02-14 19:23:12 +03:00
* vfd = vivi_template ;
2009-06-25 23:28:23 +04:00
vfd - > debug = debug ;
2007-12-10 10:38:11 +03:00
2009-02-14 19:23:12 +03:00
ret = video_register_device ( vfd , VFL_TYPE_GRABBER , video_nr ) ;
if ( ret < 0 )
goto rel_vdev ;
2008-09-04 00:11:53 +04:00
2009-02-14 19:23:12 +03:00
video_set_drvdata ( vfd , dev ) ;
2008-09-04 00:11:53 +04:00
2009-02-14 19:43:44 +03:00
/* Set all controls to their default value. */
for ( i = 0 ; i < ARRAY_SIZE ( vivi_qctrl ) ; i + + )
dev - > qctl_regs [ i ] = vivi_qctrl [ i ] . default_value ;
2009-02-14 19: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-04 00:11:53 +04:00
2009-12-16 19:06:33 +03:00
if ( video_nr ! = - 1 )
2009-02-14 19:23:12 +03:00
video_nr + + ;
2007-12-10 10:07:03 +03:00
2009-02-14 19:23:12 +03:00
dev - > vfd = vfd ;
2009-11-27 19:57:15 +03:00
v4l2_info ( & dev - > v4l2_dev , " V4L2 device registered as %s \n " ,
video_device_node_name ( vfd ) ) ;
2009-02-14 19: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 10:07:03 +03:00
2009-02-14 19: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 )
{
2009-03-06 15:58:12 +03:00
int ret = 0 , i ;
2009-02-14 19: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 10:38:11 +03:00
}
2007-12-10 10:07:03 +03:00
2007-12-10 10:38:11 +03:00
if ( ret < 0 ) {
printk ( KERN_INFO " Error %d while loading vivi driver \n " , ret ) ;
2009-02-14 19:23:12 +03:00
return ret ;
}
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
2009-02-14 19:23:12 +03:00
/* n_devs will reflect the actual number of allocated devices */
n_devs = i ;
2008-09-04 00:11:53 +04:00
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 ) ;