2009-09-14 09:42:41 -03:00
/*
2010-10-20 06:35:12 -03:00
* tm6000 - video . c - driver for TM5600 / TM6000 / TM6010 USB video capture devices
*
* Copyright ( C ) 2006 - 2007 Mauro Carvalho Chehab < mchehab @ infradead . org >
*
* Copyright ( C ) 2007 Michel Ludwig < michel . ludwig @ gmail . com >
* - Fixed module load / unload
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2009-09-14 09:42:41 -03:00
*/
2011-08-04 04:14:01 -03:00
2009-09-14 09:42:41 -03:00
# 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/random.h>
# include <linux/usb.h>
# include <linux/videodev2.h>
2008-10-25 10:43:04 -03:00
# include <media/v4l2-ioctl.h>
2011-05-09 16:53:50 -03:00
# include <media/tuner.h>
2009-09-14 09:42:41 -03:00
# include <linux/interrupt.h>
# include <linux/kthread.h>
# include <linux/highmem.h>
# include <linux/freezer.h>
# include "tm6000-regs.h"
# include "tm6000.h"
# define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
2007-07-24 08:06:45 -03:00
/* Limits minimum and default number of buffers */
# define TM6000_MIN_BUF 4
# define TM6000_DEF_BUF 8
2010-05-19 13:58:27 -03:00
# define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
2008-01-10 17:27:26 -03:00
2009-09-14 09:42:41 -03:00
/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16 ; /* Video memory limit, in Mb */
static int video_nr = - 1 ; /* /dev/videoN, -1 for autodetect */
2011-02-17 22:11:05 -03:00
static int radio_nr = - 1 ; /* /dev/radioN, -1 for autodetect */
2009-09-14 09:42:41 -03:00
/* Debug level */
int tm6000_debug ;
2010-06-04 21:08:25 -03:00
EXPORT_SYMBOL_GPL ( tm6000_debug ) ;
2009-09-14 09:42:41 -03:00
2011-02-17 22:11:05 -03:00
static const struct v4l2_queryctrl no_ctrl = {
. name = " 42 " ,
. flags = V4L2_CTRL_FLAG_DISABLED ,
} ;
2009-09-14 09:42:41 -03:00
/* supported controls */
static struct v4l2_queryctrl tm6000_qctrl [ ] = {
{
. id = V4L2_CID_BRIGHTNESS ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Brightness " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 1 ,
. default_value = 54 ,
. flags = 0 ,
} , {
. id = V4L2_CID_CONTRAST ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Contrast " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
. default_value = 119 ,
. flags = 0 ,
} , {
. id = V4L2_CID_SATURATION ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Saturation " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
. default_value = 112 ,
. flags = 0 ,
} , {
. id = V4L2_CID_HUE ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Hue " ,
. minimum = - 128 ,
. maximum = 127 ,
. step = 0x1 ,
2008-01-09 22:44:51 -03:00
. default_value = 0 ,
2009-09-14 09:42:41 -03:00
. flags = 0 ,
2011-02-17 22:11:05 -03:00
} ,
/* --- audio --- */
{
. id = V4L2_CID_AUDIO_MUTE ,
. name = " Mute " ,
. minimum = 0 ,
. maximum = 1 ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
} , {
. id = V4L2_CID_AUDIO_VOLUME ,
. name = " Volume " ,
. minimum = - 15 ,
. maximum = 15 ,
. step = 1 ,
. default_value = 0 ,
. type = V4L2_CTRL_TYPE_INTEGER ,
2009-09-14 09:42:41 -03:00
}
} ;
2011-02-17 22:11:05 -03:00
static const unsigned int CTRLS = ARRAY_SIZE ( tm6000_qctrl ) ;
2009-09-14 09:42:41 -03:00
static int qctl_regs [ ARRAY_SIZE ( tm6000_qctrl ) ] ;
static struct tm6000_fmt format [ ] = {
{
. name = " 4:2:2, packed, YVY2 " ,
. fourcc = V4L2_PIX_FMT_YUYV ,
. depth = 16 ,
2008-01-09 22:44:51 -03:00
} , {
2009-09-14 09:42:41 -03:00
. name = " 4:2:2, packed, UYVY " ,
. fourcc = V4L2_PIX_FMT_UYVY ,
. depth = 16 ,
2008-01-09 22:44:51 -03:00
} , {
2009-09-14 09:42:41 -03:00
. name = " A/V + VBI mux packet " ,
. fourcc = V4L2_PIX_FMT_TM6000 ,
. depth = 16 ,
}
} ;
2011-02-17 22:11:05 -03:00
static const struct v4l2_queryctrl * ctrl_by_id ( unsigned int id )
{
unsigned int i ;
for ( i = 0 ; i < CTRLS ; i + + )
if ( tm6000_qctrl [ i ] . id = = id )
return tm6000_qctrl + i ;
return NULL ;
}
2009-09-14 09:42:41 -03:00
/* ------------------------------------------------------------------
2010-10-20 06:35:12 -03:00
* DMA and thread functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2009-09-14 09:42:41 -03:00
# define norm_maxw(a) 720
2007-09-03 21:51:45 -03:00
# define norm_maxh(a) 576
2009-09-14 09:42:41 -03:00
# define norm_minw(a) norm_maxw(a)
# define norm_minh(a) norm_maxh(a)
/*
* video - buf generic routine to get the next available buffer
*/
2008-10-26 09:18:53 -03:00
static inline void get_next_buf ( struct tm6000_dmaqueue * dma_q ,
2008-01-09 22:44:51 -03:00
struct tm6000_buffer * * buf )
2009-09-14 09:42:41 -03:00
{
2008-01-09 22:44:51 -03:00
struct tm6000_core * dev = container_of ( dma_q , struct tm6000_core , vidq ) ;
2008-10-26 09:18:53 -03:00
char * outp ;
2009-09-14 09:42:41 -03:00
if ( list_empty ( & dma_q - > active ) ) {
2008-01-09 22:44:51 -03:00
dprintk ( dev , V4L2_DEBUG_QUEUE , " No active queue to serve \n " ) ;
2008-11-28 06:44:06 -03:00
* buf = NULL ;
2008-10-26 09:18:53 -03:00
return ;
2009-09-14 09:42:41 -03:00
}
* buf = list_entry ( dma_q - > active . next ,
struct tm6000_buffer , vb . queue ) ;
2011-03-30 22:57:33 -03:00
/* Cleans up buffer - Useful for testing for frame/URB loss */
2008-10-26 09:18:53 -03:00
outp = videobuf_to_vmalloc ( & ( * buf ) - > vb ) ;
return ;
2009-09-14 09:42:41 -03:00
}
/*
* Announces that a buffer were filled and request the next
*/
2008-01-09 22:44:51 -03:00
static inline void buffer_filled ( struct tm6000_core * dev ,
struct tm6000_dmaqueue * dma_q ,
struct tm6000_buffer * buf )
2009-09-14 09:42:41 -03:00
{
/* Advice that buffer was filled */
2008-01-09 22:44:51 -03:00
dprintk ( dev , V4L2_DEBUG_ISOC , " [%p/%d] wakeup \n " , buf , buf - > vb . i ) ;
2007-11-15 16:37:35 -03:00
buf - > vb . state = VIDEOBUF_DONE ;
2009-09-14 09:42:41 -03:00
buf - > vb . field_count + + ;
do_gettimeofday ( & buf - > vb . ts ) ;
list_del ( & buf - > vb . queue ) ;
wake_up ( & buf - > vb . done ) ;
}
/*
* Identify the tm5600 / 6000 buffer header type and properly handles
*/
2010-05-19 13:58:26 -03:00
static int copy_streams ( u8 * data , unsigned long len ,
struct urb * urb )
2007-09-19 15:39:22 -03:00
{
struct tm6000_dmaqueue * dma_q = urb - > context ;
2010-10-20 06:35:12 -03:00
struct tm6000_core * dev = container_of ( dma_q , struct tm6000_core , vidq ) ;
u8 * ptr = data , * endp = data + len , c ;
unsigned long header = 0 ;
int rc = 0 ;
2010-06-01 12:47:42 -03:00
unsigned int cmd , cpysize , pktsize , size , field , block , line , pos = 0 ;
2011-04-11 18:49:24 -03:00
struct tm6000_buffer * vbuf = NULL ;
2010-06-01 12:47:42 -03:00
char * voutp = NULL ;
unsigned int linewidth ;
2011-02-17 22:11:05 -03:00
if ( ! dev - > radio ) {
/* get video buffer */
get_next_buf ( dma_q , & vbuf ) ;
if ( ! vbuf )
return rc ;
voutp = videobuf_to_vmalloc ( & vbuf - > vb ) ;
if ( ! voutp )
return 0 ;
}
2008-04-09 08:07:20 -03:00
2010-06-01 12:47:42 -03:00
for ( ptr = data ; ptr < endp ; ) {
2008-04-09 08:07:20 -03:00
if ( ! dev - > isoc_ctl . cmd ) {
2010-06-01 12:47:42 -03:00
/* Header */
if ( dev - > isoc_ctl . tmp_buf_len > 0 ) {
/* from last urb or packet */
header = dev - > isoc_ctl . tmp_buf ;
if ( 4 - dev - > isoc_ctl . tmp_buf_len > 0 ) {
2010-10-20 06:35:12 -03:00
memcpy ( ( u8 * ) & header +
2010-05-02 17:14:33 -03:00
dev - > isoc_ctl . tmp_buf_len ,
2008-04-09 08:07:20 -03:00
ptr ,
2010-05-02 17:14:33 -03:00
4 - dev - > isoc_ctl . tmp_buf_len ) ;
ptr + = 4 - dev - > isoc_ctl . tmp_buf_len ;
2008-04-09 08:07:20 -03:00
}
2010-06-01 12:47:42 -03:00
dev - > isoc_ctl . tmp_buf_len = 0 ;
} else {
if ( ptr + 3 > = endp ) {
/* have incomplete header */
dev - > isoc_ctl . tmp_buf_len = endp - ptr ;
2010-10-20 06:35:12 -03:00
memcpy ( & dev - > isoc_ctl . tmp_buf , ptr ,
2010-06-01 12:47:42 -03:00
dev - > isoc_ctl . tmp_buf_len ) ;
return rc ;
}
/* Seek for sync */
for ( ; ptr < endp - 3 ; ptr + + ) {
if ( * ( ptr + 3 ) = = 0x47 )
break ;
}
/* Get message header */
header = * ( unsigned long * ) ptr ;
ptr + = 4 ;
2008-04-09 08:07:20 -03:00
}
2010-06-07 11:57:28 -03:00
2010-06-01 12:47:42 -03:00
/* split the header fields */
c = ( header > > 24 ) & 0xff ;
size = ( ( header & 0x7e ) < < 1 ) ;
if ( size > 0 )
size - = 4 ;
block = ( header > > 7 ) & 0xf ;
field = ( header > > 11 ) & 0x1 ;
line = ( header > > 12 ) & 0x1ff ;
cmd = ( header > > 21 ) & 0x7 ;
/* Validates haeder fields */
if ( size > TM6000_URB_MSG_LEN )
size = TM6000_URB_MSG_LEN ;
pktsize = TM6000_URB_MSG_LEN ;
2011-08-04 04:14:01 -03:00
/*
* calculate position in buffer and change the buffer
2010-06-01 12:47:42 -03:00
*/
switch ( cmd ) {
case TM6000_URB_MSG_VIDEO :
2011-02-17 22:11:05 -03:00
if ( ! dev - > radio ) {
if ( ( dev - > isoc_ctl . vfield ! = field ) & &
( field = = 1 ) ) {
2011-08-04 04:14:01 -03:00
/*
* Announces that a new buffer
* were filled
*/
2011-02-17 22:11:05 -03:00
buffer_filled ( dev , dma_q , vbuf ) ;
dprintk ( dev , V4L2_DEBUG_ISOC ,
2010-06-01 12:47:42 -03:00
" new buffer filled \n " ) ;
2011-02-17 22:11:05 -03:00
get_next_buf ( dma_q , & vbuf ) ;
if ( ! vbuf )
return rc ;
voutp = videobuf_to_vmalloc ( & vbuf - > vb ) ;
if ( ! voutp )
return rc ;
memset ( voutp , 0 , vbuf - > vb . size ) ;
}
linewidth = vbuf - > vb . width < < 1 ;
pos = ( ( line < < 1 ) - field - 1 ) *
linewidth + block * TM6000_URB_MSG_LEN ;
/* Don't allow to write out of the buffer */
if ( pos + size > vbuf - > vb . size )
cmd = TM6000_URB_MSG_ERR ;
dev - > isoc_ctl . vfield = field ;
2011-04-11 18:49:24 -03:00
}
2010-06-01 12:47:42 -03:00
break ;
case TM6000_URB_MSG_VBI :
2010-06-07 11:57:28 -03:00
break ;
case TM6000_URB_MSG_AUDIO :
2010-06-01 12:47:42 -03:00
case TM6000_URB_MSG_PTS :
2011-08-04 04:14:01 -03:00
size = pktsize ; /* Size is always 180 bytes */
2010-06-01 12:47:42 -03:00
break ;
2009-09-14 09:42:41 -03:00
}
2010-06-01 12:47:42 -03:00
} else {
/* Continue the last copy */
cmd = dev - > isoc_ctl . cmd ;
size = dev - > isoc_ctl . size ;
pos = dev - > isoc_ctl . pos ;
pktsize = dev - > isoc_ctl . pktsize ;
2011-05-21 03:05:38 -03:00
field = dev - > isoc_ctl . field ;
2010-06-01 12:47:42 -03:00
}
cpysize = ( endp - ptr > size ) ? size : endp - ptr ;
if ( cpysize ) {
/* copy data in different buffers */
switch ( cmd ) {
case TM6000_URB_MSG_VIDEO :
/* Fills video buffer */
if ( vbuf )
2010-10-20 06:35:12 -03:00
memcpy ( & voutp [ pos ] , ptr , cpysize ) ;
2010-06-01 12:47:42 -03:00
break ;
2011-05-09 16:54:00 -03:00
case TM6000_URB_MSG_AUDIO : {
int i ;
for ( i = 0 ; i < cpysize ; i + = 2 )
swab16s ( ( u16 * ) ( ptr + i ) ) ;
2010-09-20 17:07:15 -03:00
2010-06-03 17:16:28 -03:00
tm6000_call_fillbuf ( dev , TM6000_AUDIO , ptr , cpysize ) ;
2010-06-01 12:47:42 -03:00
break ;
2011-05-09 16:54:00 -03:00
}
2010-06-01 12:47:42 -03:00
case TM6000_URB_MSG_VBI :
/* Need some code to copy vbi buffer */
break ;
2011-05-09 16:54:02 -03:00
case TM6000_URB_MSG_PTS : {
2010-06-01 12:47:42 -03:00
/* Need some code to copy pts */
2011-05-09 16:54:02 -03:00
u32 pts ;
pts = * ( u32 * ) ptr ;
2011-05-21 03:05:38 -03:00
dprintk ( dev , V4L2_DEBUG_ISOC , " field %d, PTS %x " ,
field , pts ) ;
2010-06-01 12:47:42 -03:00
break ;
2007-09-19 16:24:05 -03:00
}
2011-05-09 16:54:02 -03:00
}
2008-04-09 08:07:20 -03:00
}
2010-06-30 17:24:28 -03:00
if ( ptr + pktsize > endp ) {
2011-08-04 04:14:01 -03:00
/*
* End of URB packet , but cmd processing is not
2010-06-01 12:47:42 -03:00
* complete . Preserve the state for a next packet
*/
dev - > isoc_ctl . pos = pos + cpysize ;
dev - > isoc_ctl . size = size - cpysize ;
dev - > isoc_ctl . cmd = cmd ;
2011-05-21 03:05:38 -03:00
dev - > isoc_ctl . field = field ;
2010-06-01 12:47:42 -03:00
dev - > isoc_ctl . pktsize = pktsize - ( endp - ptr ) ;
2010-06-30 17:24:28 -03:00
ptr + = endp - ptr ;
2010-06-01 12:47:42 -03:00
} else {
dev - > isoc_ctl . cmd = 0 ;
ptr + = pktsize ;
2007-09-22 02:06:25 -03:00
}
2009-09-14 09:42:41 -03:00
}
2007-09-22 02:06:25 -03:00
return 0 ;
2009-09-14 09:42:41 -03:00
}
2010-06-01 12:47:42 -03:00
2009-09-14 09:42:41 -03:00
/*
* Identify the tm5600 / 6000 buffer header type and properly handles
*/
2010-05-19 13:58:26 -03:00
static int copy_multiplexed ( u8 * ptr , unsigned long len ,
struct urb * urb )
2009-09-14 09:42:41 -03:00
{
struct tm6000_dmaqueue * dma_q = urb - > context ;
2010-10-20 06:35:12 -03:00
struct tm6000_core * dev = container_of ( dma_q , struct tm6000_core , vidq ) ;
unsigned int pos = dev - > isoc_ctl . pos , cpysize ;
int rc = 1 ;
2010-05-19 13:58:26 -03:00
struct tm6000_buffer * buf ;
char * outp = NULL ;
get_next_buf ( dma_q , & buf ) ;
if ( buf )
outp = videobuf_to_vmalloc ( & buf - > vb ) ;
if ( ! outp )
return 0 ;
2008-04-09 08:07:20 -03:00
2010-10-20 06:35:12 -03:00
while ( len > 0 ) {
cpysize = min ( len , buf - > vb . size - pos ) ;
2010-05-19 13:58:26 -03:00
memcpy ( & outp [ pos ] , ptr , cpysize ) ;
2010-10-20 06:35:12 -03:00
pos + = cpysize ;
ptr + = cpysize ;
len - = cpysize ;
2010-05-19 13:58:26 -03:00
if ( pos > = buf - > vb . size ) {
2010-10-20 06:35:12 -03:00
pos = 0 ;
2009-09-14 09:42:41 -03:00
/* Announces that a new buffer were filled */
2010-10-20 06:35:12 -03:00
buffer_filled ( dev , dma_q , buf ) ;
2007-08-27 07:55:05 -03:00
dprintk ( dev , V4L2_DEBUG_ISOC , " new buffer filled \n " ) ;
2010-10-20 06:35:12 -03:00
get_next_buf ( dma_q , & buf ) ;
2010-05-19 13:58:26 -03:00
if ( ! buf )
2009-09-14 09:42:41 -03:00
break ;
2010-05-19 13:58:26 -03:00
outp = videobuf_to_vmalloc ( & ( buf - > vb ) ) ;
if ( ! outp )
2008-11-28 07:39:00 -03:00
return rc ;
pos = 0 ;
2009-09-14 09:42:41 -03:00
}
}
2010-10-20 06:35:12 -03:00
dev - > isoc_ctl . pos = pos ;
2009-09-14 09:42:41 -03:00
return rc ;
}
2010-10-20 06:35:12 -03:00
static inline void print_err_status ( struct tm6000_core * dev ,
2008-04-09 08:07:20 -03:00
int packet , int status )
2007-08-27 07:55:05 -03:00
{
char * errmsg = " Unknown " ;
2010-10-20 06:35:12 -03:00
switch ( status ) {
2007-08-27 07:55:05 -03:00
case - ENOENT :
errmsg = " unlinked synchronuously " ;
break ;
case - ECONNRESET :
errmsg = " unlinked asynchronuously " ;
break ;
case - ENOSR :
errmsg = " Buffer error (overrun) " ;
break ;
case - EPIPE :
errmsg = " Stalled (device not responding) " ;
break ;
case - EOVERFLOW :
errmsg = " Babble (bad cable?) " ;
break ;
case - EPROTO :
errmsg = " Bit-stuff error (bad cable?) " ;
break ;
case - EILSEQ :
errmsg = " CRC/Timeout (could be anything) " ;
break ;
case - ETIME :
errmsg = " Device does not respond " ;
break ;
}
2010-10-20 06:35:12 -03:00
if ( packet < 0 ) {
2007-08-27 07:55:05 -03:00
dprintk ( dev , V4L2_DEBUG_QUEUE , " URB status %d [%s]. \n " ,
status , errmsg ) ;
} else {
2008-04-09 08:07:20 -03:00
dprintk ( dev , V4L2_DEBUG_QUEUE , " URB packet %d, status %d [%s]. \n " ,
2007-08-27 07:55:05 -03:00
packet , status , errmsg ) ;
}
}
2009-09-14 09:42:41 -03:00
/*
* Controls the isoc copy of each urb packet
*/
2008-11-28 07:39:00 -03:00
static inline int tm6000_isoc_copy ( struct urb * urb )
2009-09-14 09:42:41 -03:00
{
struct tm6000_dmaqueue * dma_q = urb - > context ;
2010-10-20 06:35:12 -03:00
struct tm6000_core * dev = container_of ( dma_q , struct tm6000_core , vidq ) ;
int i , len = 0 , rc = 1 , status ;
2010-05-19 13:58:26 -03:00
char * p ;
2009-09-14 09:42:41 -03:00
2010-05-19 13:58:26 -03:00
if ( urb - > status < 0 ) {
2010-10-20 06:35:12 -03:00
print_err_status ( dev , - 1 , urb - > status ) ;
2007-08-27 07:55:05 -03:00
return 0 ;
}
2009-09-14 09:42:41 -03:00
for ( i = 0 ; i < urb - > number_of_packets ; i + + ) {
2010-05-19 13:58:26 -03:00
status = urb - > iso_frame_desc [ i ] . status ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
if ( status < 0 ) {
print_err_status ( dev , i , status ) ;
2009-09-14 09:42:41 -03:00
continue ;
2007-08-27 07:55:05 -03:00
}
2009-09-14 09:42:41 -03:00
2010-05-19 13:58:26 -03:00
len = urb - > iso_frame_desc [ i ] . actual_length ;
2008-04-09 08:07:20 -03:00
2010-05-19 13:58:26 -03:00
if ( len > 0 ) {
p = urb - > transfer_buffer + urb - > iso_frame_desc [ i ] . offset ;
2008-04-09 08:07:20 -03:00
if ( ! urb - > iso_frame_desc [ i ] . status ) {
2010-10-20 06:35:12 -03:00
if ( ( dev - > fourcc ) = = V4L2_PIX_FMT_TM6000 ) {
rc = copy_multiplexed ( p , len , urb ) ;
if ( rc < = 0 )
2008-04-09 08:07:20 -03:00
return rc ;
} else {
2010-05-19 13:58:26 -03:00
copy_streams ( p , len , urb ) ;
2008-04-09 08:07:20 -03:00
}
}
2010-05-19 13:58:26 -03:00
}
2009-09-14 09:42:41 -03:00
}
return rc ;
}
/* ------------------------------------------------------------------
2010-10-20 06:35:12 -03:00
* URB control
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2009-09-14 09:42:41 -03:00
/*
* IRQ callback , called by URB callback
*/
static void tm6000_irq_callback ( struct urb * urb )
{
struct tm6000_dmaqueue * dma_q = urb - > context ;
2008-01-09 22:44:51 -03:00
struct tm6000_core * dev = container_of ( dma_q , struct tm6000_core , vidq ) ;
2008-11-28 07:39:00 -03:00
int i ;
2009-09-14 09:42:41 -03:00
2011-08-04 04:14:06 -03:00
switch ( urb - > status ) {
case 0 :
case - ETIMEDOUT :
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
2008-10-26 09:18:53 -03:00
return ;
2007-09-22 02:06:25 -03:00
2011-08-04 04:14:06 -03:00
default :
tm6000_err ( " urb completion error %d. \n " , urb - > status ) ;
break ;
}
2008-11-28 07:39:00 -03:00
spin_lock ( & dev - > slock ) ;
tm6000_isoc_copy ( urb ) ;
spin_unlock ( & dev - > slock ) ;
2009-09-14 09:42:41 -03:00
2008-11-28 07:39:00 -03:00
/* Reset urb buffers */
for ( i = 0 ; i < urb - > number_of_packets ; i + + ) {
urb - > iso_frame_desc [ i ] . status = 0 ;
urb - > iso_frame_desc [ i ] . actual_length = 0 ;
}
2009-09-14 09:42:41 -03:00
2008-01-09 22:44:51 -03:00
urb - > status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( urb - > status )
2009-09-14 09:42:41 -03:00
tm6000_err ( " urb resubmit failed (error=%i) \n " ,
urb - > status ) ;
}
/*
* Stop and Deallocate URBs
*/
static void tm6000_uninit_isoc ( struct tm6000_core * dev )
{
struct urb * urb ;
int i ;
2008-01-10 17:27:26 -03:00
dev - > isoc_ctl . buf = NULL ;
2009-09-14 09:42:41 -03:00
for ( i = 0 ; i < dev - > isoc_ctl . num_bufs ; i + + ) {
2010-10-20 06:35:12 -03:00
urb = dev - > isoc_ctl . urb [ i ] ;
2009-09-14 09:42:41 -03:00
if ( urb ) {
usb_kill_urb ( urb ) ;
usb_unlink_urb ( urb ) ;
if ( dev - > isoc_ctl . transfer_buffer [ i ] ) {
2010-05-03 15:17:57 -03:00
usb_free_coherent ( dev - > udev ,
2009-09-14 09:42:41 -03:00
urb - > transfer_buffer_length ,
dev - > isoc_ctl . transfer_buffer [ i ] ,
urb - > transfer_dma ) ;
}
usb_free_urb ( urb ) ;
dev - > isoc_ctl . urb [ i ] = NULL ;
}
dev - > isoc_ctl . transfer_buffer [ i ] = NULL ;
}
2010-10-20 06:35:12 -03:00
kfree ( dev - > isoc_ctl . urb ) ;
kfree ( dev - > isoc_ctl . transfer_buffer ) ;
2008-04-09 01:49:19 -03:00
2010-10-20 06:35:12 -03:00
dev - > isoc_ctl . urb = NULL ;
dev - > isoc_ctl . transfer_buffer = NULL ;
2008-04-09 01:49:19 -03:00
dev - > isoc_ctl . num_bufs = 0 ;
2009-09-14 09:42:41 -03:00
}
/*
* Allocate URBs and start IRQ
*/
2011-02-17 22:11:05 -03:00
static int tm6000_prepare_isoc ( struct tm6000_core * dev )
2009-09-14 09:42:41 -03:00
{
struct tm6000_dmaqueue * dma_q = & dev - > vidq ;
2010-05-19 13:58:27 -03:00
int i , j , sb_size , pipe , size , max_packets , num_bufs = 8 ;
2009-09-14 09:42:41 -03:00
struct urb * urb ;
2008-01-09 18:12:39 -03:00
2009-09-14 09:42:41 -03:00
/* De-allocates all pending stuff */
tm6000_uninit_isoc ( dev ) ;
2010-12-22 05:57:46 -03:00
/* Stop interrupt USB pipe */
tm6000_ir_int_stop ( dev ) ;
2009-09-14 09:42:41 -03:00
2010-04-26 11:24:18 -03:00
usb_set_interface ( dev - > udev ,
dev - > isoc_in . bInterfaceNumber ,
dev - > isoc_in . bAlternateSetting ) ;
2010-12-22 05:57:46 -03:00
/* Start interrupt USB pipe */
tm6000_ir_int_start ( dev ) ;
2008-01-10 17:27:26 -03:00
pipe = usb_rcvisocpipe ( dev - > udev ,
2010-04-26 11:24:18 -03:00
dev - > isoc_in . endp - > desc . bEndpointAddress &
2008-01-10 17:27:26 -03:00
USB_ENDPOINT_NUMBER_MASK ) ;
size = usb_maxpacket ( dev - > udev , pipe , usb_pipeout ( pipe ) ) ;
2010-04-26 11:24:18 -03:00
if ( size > dev - > isoc_in . maxsize )
size = dev - > isoc_in . maxsize ;
2008-01-10 17:27:26 -03:00
dev - > isoc_ctl . max_pkt_size = size ;
2011-02-17 22:11:05 -03:00
max_packets = TM6000_MAX_ISO_PACKETS ;
2008-01-10 17:27:26 -03:00
sb_size = max_packets * size ;
dev - > isoc_ctl . num_bufs = num_bufs ;
2008-04-09 01:49:19 -03:00
dev - > isoc_ctl . urb = kmalloc ( sizeof ( void * ) * num_bufs , GFP_KERNEL ) ;
2009-09-14 09:42:41 -03:00
if ( ! dev - > isoc_ctl . urb ) {
tm6000_err ( " cannot alloc memory for usb buffers \n " ) ;
return - ENOMEM ;
}
2008-01-10 17:27:26 -03:00
dev - > isoc_ctl . transfer_buffer = kmalloc ( sizeof ( void * ) * num_bufs ,
2009-09-14 09:42:41 -03:00
GFP_KERNEL ) ;
2010-02-11 03:30:30 -03:00
if ( ! dev - > isoc_ctl . transfer_buffer ) {
2009-09-14 09:42:41 -03:00
tm6000_err ( " cannot allocate memory for usbtransfer \n " ) ;
kfree ( dev - > isoc_ctl . urb ) ;
return - ENOMEM ;
}
2008-01-10 17:27:26 -03:00
dprintk ( dev , V4L2_DEBUG_QUEUE , " Allocating %d x %d packets "
" (%d bytes) of %d bytes each to handle %u size \n " ,
max_packets , num_bufs , sb_size ,
2010-04-26 11:24:18 -03:00
dev - > isoc_in . maxsize , size ) ;
2009-09-14 09:42:41 -03:00
/* allocate urbs and transfer buffers */
for ( i = 0 ; i < dev - > isoc_ctl . num_bufs ; i + + ) {
urb = usb_alloc_urb ( max_packets , GFP_KERNEL ) ;
if ( ! urb ) {
tm6000_err ( " cannot alloc isoc_ctl.urb %i \n " , i ) ;
tm6000_uninit_isoc ( dev ) ;
2007-10-15 15:43:50 -03:00
usb_free_urb ( urb ) ;
2009-09-14 09:42:41 -03:00
return - ENOMEM ;
}
dev - > isoc_ctl . urb [ i ] = urb ;
2010-05-03 15:17:57 -03:00
dev - > isoc_ctl . transfer_buffer [ i ] = usb_alloc_coherent ( dev - > udev ,
2007-09-19 07:36:34 -03:00
sb_size , GFP_KERNEL , & urb - > transfer_dma ) ;
2009-09-14 09:42:41 -03:00
if ( ! dev - > isoc_ctl . transfer_buffer [ i ] ) {
2010-10-20 06:35:12 -03:00
tm6000_err ( " unable to allocate %i bytes for transfer "
2007-09-22 02:06:25 -03:00
" buffer %i%s \n " ,
sb_size , i ,
2010-10-20 06:35:12 -03:00
in_interrupt ( ) ? " while in int " : " " ) ;
2009-09-14 09:42:41 -03:00
tm6000_uninit_isoc ( dev ) ;
return - ENOMEM ;
}
memset ( dev - > isoc_ctl . transfer_buffer [ i ] , 0 , sb_size ) ;
2008-01-10 17:27:26 -03:00
usb_fill_bulk_urb ( urb , dev - > udev , pipe ,
dev - > isoc_ctl . transfer_buffer [ i ] , sb_size ,
tm6000_irq_callback , dma_q ) ;
2010-04-26 11:24:18 -03:00
urb - > interval = dev - > isoc_in . endp - > desc . bInterval ;
2009-09-14 09:42:41 -03:00
urb - > number_of_packets = max_packets ;
2008-01-10 17:27:26 -03:00
urb - > transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP ;
2009-09-14 09:42:41 -03:00
for ( j = 0 ; j < max_packets ; j + + ) {
2008-01-10 17:27:26 -03:00
urb - > iso_frame_desc [ j ] . offset = size * j ;
urb - > iso_frame_desc [ j ] . length = size ;
2009-09-14 09:42:41 -03:00
}
}
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int tm6000_start_thread ( struct tm6000_core * dev )
2009-09-14 09:42:41 -03:00
{
2008-04-09 01:49:19 -03:00
struct tm6000_dmaqueue * dma_q = & dev - > vidq ;
int i ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
dma_q - > frame = 0 ;
dma_q - > ini_jiffies = jiffies ;
2009-09-14 09:42:41 -03:00
init_waitqueue_head ( & dma_q - > wq ) ;
/* submit urbs and enables IRQ */
for ( i = 0 ; i < dev - > isoc_ctl . num_bufs ; i + + ) {
2008-04-09 01:49:19 -03:00
int rc = usb_submit_urb ( dev - > isoc_ctl . urb [ i ] , GFP_ATOMIC ) ;
2009-09-14 09:42:41 -03:00
if ( rc ) {
tm6000_err ( " submit of urb %i failed (error=%i) \n " , i ,
rc ) ;
tm6000_uninit_isoc ( dev ) ;
return rc ;
}
}
return 0 ;
}
/* ------------------------------------------------------------------
2010-10-20 06:35:12 -03:00
* Videobuf operations
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2007-07-24 08:06:45 -03:00
2009-09-14 09:42:41 -03:00
static int
buffer_setup ( struct videobuf_queue * vq , unsigned int * count , unsigned int * size )
{
struct tm6000_fh * fh = vq - > priv_data ;
* size = fh - > fmt - > depth * fh - > width * fh - > height > > 3 ;
if ( 0 = = * count )
2007-07-24 08:06:45 -03:00
* count = TM6000_DEF_BUF ;
2010-10-20 06:35:12 -03:00
if ( * count < TM6000_MIN_BUF )
* count = TM6000_MIN_BUF ;
2007-07-24 08:06:45 -03:00
2009-09-14 09:42:41 -03:00
while ( * size * * count > vid_limit * 1024 * 1024 )
( * count ) - - ;
2007-07-24 08:06:45 -03:00
2009-09-14 09:42:41 -03:00
return 0 ;
}
static void free_buffer ( struct videobuf_queue * vq , struct tm6000_buffer * buf )
{
2008-10-26 09:18:53 -03:00
struct tm6000_fh * fh = vq - > priv_data ;
struct tm6000_core * dev = fh - > dev ;
unsigned long flags ;
2009-09-14 09:42:41 -03:00
if ( in_interrupt ( ) )
BUG ( ) ;
2008-10-26 09:18:53 -03:00
/* We used to wait for the buffer to finish here, but this didn't work
because , as we were keeping the state as VIDEOBUF_QUEUED ,
videobuf_queue_cancel marked it as finished for us .
( Also , it could wedge forever if the hardware was misconfigured . )
This should be safe ; by the time we get here , the buffer isn ' t
queued anymore . If we ever start marking the buffers as
VIDEOBUF_ACTIVE , it won ' t be , though .
*/
spin_lock_irqsave ( & dev - > slock , flags ) ;
if ( dev - > isoc_ctl . buf = = buf )
dev - > isoc_ctl . buf = NULL ;
spin_unlock_irqrestore ( & dev - > slock , flags ) ;
2009-09-14 09:42:41 -03:00
videobuf_vmalloc_free ( & buf - > vb ) ;
2007-11-15 16:37:35 -03:00
buf - > vb . state = VIDEOBUF_NEEDS_INIT ;
2009-09-14 09:42:41 -03:00
}
static int
buffer_prepare ( struct videobuf_queue * vq , struct videobuf_buffer * vb ,
enum v4l2_field field )
{
struct tm6000_fh * fh = vq - > priv_data ;
2010-10-20 06:35:12 -03:00
struct tm6000_buffer * buf = container_of ( vb , struct tm6000_buffer , vb ) ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
2011-08-04 04:14:12 -03:00
int rc = 0 ;
2009-09-14 09:42:41 -03:00
BUG_ON ( NULL = = fh - > fmt ) ;
/* FIXME: It assumes depth=2 */
/* The only currently supported format is 16 bits/pixel */
buf - > vb . size = fh - > fmt - > depth * fh - > width * fh - > height > > 3 ;
if ( 0 ! = buf - > vb . baddr & & buf - > vb . bsize < buf - > vb . size )
return - EINVAL ;
if ( buf - > fmt ! = fh - > fmt | |
buf - > vb . width ! = fh - > width | |
buf - > vb . height ! = fh - > height | |
buf - > vb . field ! = field ) {
buf - > fmt = fh - > fmt ;
buf - > vb . width = fh - > width ;
buf - > vb . height = fh - > height ;
buf - > vb . field = field ;
2007-11-15 16:37:35 -03:00
buf - > vb . state = VIDEOBUF_NEEDS_INIT ;
2009-09-14 09:42:41 -03:00
}
2007-11-15 16:37:35 -03:00
if ( VIDEOBUF_NEEDS_INIT = = buf - > vb . state ) {
2011-06-01 22:21:56 -04:00
rc = videobuf_iolock ( vq , & buf - > vb , NULL ) ;
if ( rc ! = 0 )
2009-09-14 09:42:41 -03:00
goto fail ;
}
2011-08-04 04:14:12 -03:00
if ( ! dev - > isoc_ctl . num_bufs ) {
2011-02-17 22:11:05 -03:00
rc = tm6000_prepare_isoc ( dev ) ;
2008-04-09 01:49:19 -03:00
if ( rc < 0 )
goto fail ;
2008-01-10 17:27:26 -03:00
2008-04-09 01:49:19 -03:00
rc = tm6000_start_thread ( dev ) ;
2008-01-10 17:27:26 -03:00
if ( rc < 0 )
2009-09-14 09:42:41 -03:00
goto fail ;
2008-04-09 01:49:19 -03:00
2009-09-14 09:42:41 -03:00
}
2007-11-15 16:37:35 -03:00
buf - > vb . state = VIDEOBUF_PREPARED ;
2009-09-14 09:42:41 -03:00
return 0 ;
fail :
2008-01-10 17:27:26 -03:00
free_buffer ( vq , buf ) ;
2009-09-14 09:42:41 -03:00
return rc ;
}
static void
buffer_queue ( struct videobuf_queue * vq , struct videobuf_buffer * vb )
{
2010-10-20 06:35:12 -03:00
struct tm6000_buffer * buf = container_of ( vb , struct tm6000_buffer , vb ) ;
2009-09-14 09:42:41 -03:00
struct tm6000_fh * fh = vq - > priv_data ;
struct tm6000_core * dev = fh - > dev ;
struct tm6000_dmaqueue * vidq = & dev - > vidq ;
2008-04-09 01:49:19 -03:00
buf - > vb . state = VIDEOBUF_QUEUED ;
list_add_tail ( & buf - > vb . queue , & vidq - > active ) ;
2009-09-14 09:42:41 -03:00
}
static void buffer_release ( struct videobuf_queue * vq , struct videobuf_buffer * vb )
{
2010-10-20 06:35:12 -03:00
struct tm6000_buffer * buf = container_of ( vb , struct tm6000_buffer , vb ) ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
free_buffer ( vq , buf ) ;
2009-09-14 09:42:41 -03:00
}
static struct videobuf_queue_ops tm6000_video_qops = {
. buf_setup = buffer_setup ,
. buf_prepare = buffer_prepare ,
. buf_queue = buffer_queue ,
. buf_release = buffer_release ,
} ;
/* ------------------------------------------------------------------
2010-10-20 06:35:12 -03:00
* IOCTL handling
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2009-09-14 09:42:41 -03:00
2010-10-11 10:48:11 -03:00
static bool is_res_read ( struct tm6000_core * dev , struct tm6000_fh * fh )
2009-09-14 09:42:41 -03:00
{
2010-10-11 10:48:11 -03:00
/* Is the current fh handling it? if so, that's OK */
if ( dev - > resources = = fh & & dev - > is_res_read )
return true ;
return false ;
}
static bool is_res_streaming ( struct tm6000_core * dev , struct tm6000_fh * fh )
{
/* Is the current fh handling it? if so, that's OK */
if ( dev - > resources = = fh )
return true ;
return false ;
2009-09-14 09:42:41 -03:00
}
2010-10-11 10:48:11 -03:00
static bool res_get ( struct tm6000_core * dev , struct tm6000_fh * fh ,
bool is_res_read )
2009-09-14 09:42:41 -03:00
{
2010-10-11 10:48:11 -03:00
/* Is the current fh handling it? if so, that's OK */
if ( dev - > resources = = fh & & dev - > is_res_read = = is_res_read )
return true ;
/* is it free? */
if ( dev - > resources )
return false ;
/* grab it */
dev - > resources = fh ;
dev - > is_res_read = is_res_read ;
dprintk ( dev , V4L2_DEBUG_RES_LOCK , " res: get \n " ) ;
return true ;
2009-09-14 09:42:41 -03:00
}
static void res_free ( struct tm6000_core * dev , struct tm6000_fh * fh )
{
2010-10-11 10:48:11 -03:00
/* Is the current fh handling it? if so, that's OK */
if ( dev - > resources ! = fh )
return ;
dev - > resources = NULL ;
2009-09-14 09:42:41 -03:00
dprintk ( dev , V4L2_DEBUG_RES_LOCK , " res: put \n " ) ;
}
/* ------------------------------------------------------------------
2010-10-20 06:35:12 -03:00
* IOCTL vidioc handling
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static int vidioc_querycap ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_capability * cap )
{
2011-05-09 16:53:50 -03:00
struct tm6000_core * dev = ( ( struct tm6000_fh * ) priv ) - > dev ;
2009-09-14 09:42:41 -03:00
strlcpy ( cap - > driver , " tm6000 " , sizeof ( cap - > driver ) ) ;
2010-10-20 06:35:12 -03:00
strlcpy ( cap - > card , " Trident TVMaster TM5600/6000/6010 " , sizeof ( cap - > card ) ) ;
2009-09-14 09:42:41 -03:00
cap - > version = TM6000_VERSION ;
cap - > capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
2011-05-09 16:53:50 -03:00
V4L2_CAP_AUDIO |
2009-09-14 09:42:41 -03:00
V4L2_CAP_READWRITE ;
2011-05-09 16:53:50 -03:00
if ( dev - > tuner_type ! = TUNER_ABSENT )
cap - > capabilities | = V4L2_CAP_TUNER ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_enum_fmt_vid_cap ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_fmtdesc * f )
{
if ( unlikely ( f - > index > = ARRAY_SIZE ( format ) ) )
return - EINVAL ;
2010-10-20 06:35:12 -03:00
strlcpy ( f - > description , format [ f - > index ] . name , sizeof ( f - > description ) ) ;
2009-09-14 09:42:41 -03:00
f - > pixelformat = format [ f - > index ] . fourcc ;
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_g_fmt_vid_cap ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_format * f )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03: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 ;
2010-10-20 06:35:12 -03:00
return 0 ;
2009-09-14 09:42:41 -03:00
}
2010-10-20 06:35:12 -03:00
static struct tm6000_fmt * format_by_fourcc ( unsigned int fourcc )
2009-09-14 09:42:41 -03:00
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( format ) ; i + + )
if ( format [ i ] . fourcc = = fourcc )
return format + i ;
return NULL ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_try_fmt_vid_cap ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_format * f )
{
struct tm6000_core * dev = ( ( struct tm6000_fh * ) priv ) - > dev ;
struct tm6000_fmt * fmt ;
enum v4l2_field field ;
fmt = format_by_fourcc ( f - > fmt . pix . pixelformat ) ;
if ( NULL = = fmt ) {
dprintk ( dev , V4L2_DEBUG_IOCTL_ARG , " Fourcc format (0x%08x) "
" invalid. \n " , f - > fmt . pix . pixelformat ) ;
return - EINVAL ;
}
field = f - > fmt . pix . field ;
2010-10-20 06:35:12 -03:00
if ( field = = V4L2_FIELD_ANY )
field = V4L2_FIELD_SEQ_TB ;
else if ( V4L2_FIELD_INTERLACED ! = field ) {
2009-09-14 09:42:41 -03:00
dprintk ( dev , V4L2_DEBUG_IOCTL_ARG , " Field type invalid. \n " ) ;
return - EINVAL ;
}
2010-10-20 06:35:12 -03:00
tm6000_get_std_res ( dev ) ;
2009-09-14 09:42:41 -03:00
2007-09-03 21:51:45 -03:00
f - > fmt . pix . width = dev - > width ;
f - > fmt . pix . height = dev - > height ;
2009-09-14 09:42:41 -03:00
f - > fmt . pix . width & = ~ 0x01 ;
f - > fmt . pix . field = field ;
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 ;
}
/*FIXME: This seems to be generic enough to be at videodev2 */
2010-10-20 06:35:12 -03:00
static int vidioc_s_fmt_vid_cap ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_format * f )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
2010-10-20 06:35:12 -03:00
int ret = vidioc_try_fmt_vid_cap ( file , fh , f ) ;
2009-09-14 09:42:41 -03:00
if ( ret < 0 )
2010-10-20 06:35:12 -03:00
return ret ;
2009-09-14 09:42:41 -03:00
fh - > fmt = format_by_fourcc ( f - > fmt . pix . pixelformat ) ;
fh - > width = f - > fmt . pix . width ;
fh - > height = f - > fmt . pix . height ;
fh - > vb_vidq . field = f - > fmt . pix . field ;
fh - > type = f - > type ;
dev - > fourcc = f - > fmt . pix . pixelformat ;
tm6000_set_fourcc_format ( dev ) ;
2010-10-20 06:35:12 -03:00
return 0 ;
2009-09-14 09:42:41 -03:00
}
2010-10-20 06:35:12 -03:00
static int vidioc_reqbufs ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_requestbuffers * p )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
return videobuf_reqbufs ( & fh - > vb_vidq , p ) ;
2009-09-14 09:42:41 -03:00
}
2010-10-20 06:35:12 -03:00
static int vidioc_querybuf ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_buffer * p )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
return videobuf_querybuf ( & fh - > vb_vidq , p ) ;
2009-09-14 09:42:41 -03:00
}
2010-10-20 06:35:12 -03:00
static int vidioc_qbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2009-09-14 09:42:41 -03:00
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
return videobuf_qbuf ( & fh - > vb_vidq , p ) ;
2009-09-14 09:42:41 -03:00
}
2010-10-20 06:35:12 -03:00
static int vidioc_dqbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
2009-09-14 09:42:41 -03:00
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
return videobuf_dqbuf ( & fh - > vb_vidq , p ,
file - > f_flags & O_NONBLOCK ) ;
2009-09-14 09:42:41 -03:00
}
static int vidioc_streamon ( struct file * file , void * priv , enum v4l2_buf_type i )
{
2011-08-04 04:14:01 -03:00
struct tm6000_fh * fh = priv ;
struct tm6000_core * dev = fh - > dev ;
2009-09-14 09:42:41 -03:00
if ( fh - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
if ( i ! = fh - > type )
return - EINVAL ;
2010-10-11 10:48:11 -03:00
if ( ! res_get ( dev , fh , false ) )
2009-09-14 09:42:41 -03:00
return - EBUSY ;
2011-06-01 22:21:56 -04:00
return videobuf_streamon ( & fh - > vb_vidq ) ;
2009-09-14 09:42:41 -03:00
}
static int vidioc_streamoff ( struct file * file , void * priv , enum v4l2_buf_type i )
{
2011-08-04 04:14:01 -03:00
struct tm6000_fh * fh = priv ;
struct tm6000_core * dev = fh - > dev ;
2009-09-14 09:42:41 -03:00
if ( fh - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2011-08-04 04:14:01 -03:00
2009-09-14 09:42:41 -03:00
if ( i ! = fh - > type )
return - EINVAL ;
videobuf_streamoff ( & fh - > vb_vidq ) ;
2011-06-01 22:21:56 -04:00
res_free ( dev , fh ) ;
2009-09-14 09:42:41 -03:00
2011-06-01 22:21:56 -04:00
return 0 ;
2009-09-14 09:42:41 -03:00
}
2011-06-01 22:21:56 -04:00
static int vidioc_s_std ( struct file * file , void * priv , v4l2_std_id * norm )
2009-09-14 09:42:41 -03:00
{
2011-06-01 22:21:56 -04:00
int rc = 0 ;
2011-08-04 04:14:01 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
2010-10-27 16:48:05 -03:00
dev - > norm = * norm ;
2010-10-07 02:28:24 -03:00
rc = tm6000_init_analog_mode ( dev ) ;
2007-09-06 20:12:10 -03:00
fh - > width = dev - > width ;
fh - > height = dev - > height ;
2011-06-01 22:21:56 -04:00
if ( rc < 0 )
2009-09-14 09:42:41 -03:00
return rc ;
2009-09-14 16:37:13 -03:00
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , core , s_std , dev - > norm ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2011-06-01 22:21:56 -04:00
static const char * iname [ ] = {
2011-05-09 16:53:52 -03:00
[ TM6000_INPUT_TV ] = " Television " ,
[ TM6000_INPUT_COMPOSITE1 ] = " Composite 1 " ,
[ TM6000_INPUT_COMPOSITE2 ] = " Composite 2 " ,
[ TM6000_INPUT_SVIDEO ] = " S-Video " ,
} ;
2010-10-20 06:35:12 -03:00
static int vidioc_enum_input ( struct file * file , void * priv ,
2011-05-09 16:53:52 -03:00
struct v4l2_input * i )
2009-09-14 09:42:41 -03:00
{
2011-03-17 21:08:55 -03:00
struct tm6000_fh * fh = priv ;
struct tm6000_core * dev = fh - > dev ;
2011-05-09 16:53:52 -03:00
unsigned int n ;
2011-03-17 21:08:55 -03:00
2011-05-09 16:53:52 -03:00
n = i - > index ;
if ( n > = 3 )
2009-09-14 09:42:41 -03:00
return - EINVAL ;
2011-05-09 16:53:52 -03:00
if ( ! dev - > vinput [ n ] . type )
return - EINVAL ;
i - > index = n ;
if ( dev - > vinput [ n ] . type = = TM6000_INPUT_TV )
i - > type = V4L2_INPUT_TYPE_TUNER ;
else
i - > type = V4L2_INPUT_TYPE_CAMERA ;
strcpy ( i - > name , iname [ dev - > vinput [ n ] . type ] ) ;
i - > std = TM6000_STD ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_g_input ( struct file * file , void * priv , unsigned int * i )
2009-09-14 09:42:41 -03:00
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
2010-10-20 06:35:12 -03:00
* i = dev - > input ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2011-05-09 16:53:52 -03:00
2010-10-20 06:35:12 -03:00
static int vidioc_s_input ( struct file * file , void * priv , unsigned int i )
2009-09-14 09:42:41 -03:00
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
2010-10-20 06:35:12 -03:00
int rc = 0 ;
2009-09-14 09:42:41 -03:00
2011-05-09 16:53:52 -03:00
if ( i > = 3 )
return - EINVAL ;
if ( ! dev - > vinput [ i ] . type )
2009-09-14 09:42:41 -03:00
return - EINVAL ;
2011-05-09 16:53:52 -03:00
dev - > input = i ;
rc = vidioc_s_std ( file , priv , & dev - > vfd - > current_norm ) ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
return rc ;
2009-09-14 09:42:41 -03:00
}
2011-05-09 16:53:50 -03:00
/* --- controls ---------------------------------------------- */
2010-10-20 06:35:12 -03:00
static int vidioc_queryctrl ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_queryctrl * qc )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( tm6000_qctrl ) ; i + + )
if ( qc - > id & & qc - > id = = tm6000_qctrl [ i ] . id ) {
memcpy ( qc , & ( tm6000_qctrl [ i ] ) ,
sizeof ( * qc ) ) ;
2010-10-20 06:35:12 -03:00
return 0 ;
2009-09-14 09:42:41 -03:00
}
return - EINVAL ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_g_ctrl ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_control * ctrl )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
int val ;
/* FIXME: Probably, those won't work! Maybe we need shadow regs */
switch ( ctrl - > id ) {
case V4L2_CID_CONTRAST :
2010-03-11 10:26:46 -03:00
val = tm6000_get_reg ( dev , TM6010_REQ07_R08_LUMA_CONTRAST_ADJ , 0 ) ;
2009-09-14 09:42:41 -03:00
break ;
case V4L2_CID_BRIGHTNESS :
2010-03-11 10:26:46 -03:00
val = tm6000_get_reg ( dev , TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ , 0 ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
case V4L2_CID_SATURATION :
2010-03-11 10:26:46 -03:00
val = tm6000_get_reg ( dev , TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ , 0 ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
case V4L2_CID_HUE :
2010-03-11 10:26:46 -03:00
val = tm6000_get_reg ( dev , TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ , 0 ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
2011-02-17 22:11:05 -03:00
case V4L2_CID_AUDIO_MUTE :
val = dev - > ctl_mute ;
return 0 ;
case V4L2_CID_AUDIO_VOLUME :
val = dev - > ctl_volume ;
return 0 ;
2009-09-14 09:42:41 -03:00
default :
return - EINVAL ;
}
2010-10-20 06:35:12 -03:00
if ( val < 0 )
2009-09-14 09:42:41 -03:00
return val ;
2010-10-20 06:35:12 -03:00
ctrl - > value = val ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_s_ctrl ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_control * ctrl )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
2010-10-20 06:35:12 -03:00
u8 val = ctrl - > value ;
2009-09-14 09:42:41 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_CONTRAST :
2010-10-20 06:35:12 -03:00
tm6000_set_reg ( dev , TM6010_REQ07_R08_LUMA_CONTRAST_ADJ , val ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
case V4L2_CID_BRIGHTNESS :
2010-10-20 06:35:12 -03:00
tm6000_set_reg ( dev , TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ , val ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
case V4L2_CID_SATURATION :
2010-10-20 06:35:12 -03:00
tm6000_set_reg ( dev , TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ , val ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
case V4L2_CID_HUE :
2010-10-20 06:35:12 -03:00
tm6000_set_reg ( dev , TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ , val ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
2011-02-17 22:11:05 -03:00
case V4L2_CID_AUDIO_MUTE :
dev - > ctl_mute = val ;
tm6000_tvaudio_set_mute ( dev , val ) ;
return 0 ;
case V4L2_CID_AUDIO_VOLUME :
dev - > ctl_volume = val ;
tm6000_set_volume ( dev , val ) ;
return 0 ;
2009-09-14 09:42:41 -03:00
}
return - EINVAL ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_g_tuner ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_tuner * t )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
if ( unlikely ( UNSET = = dev - > tuner_type ) )
return - EINVAL ;
if ( 0 ! = t - > index )
return - EINVAL ;
strcpy ( t - > name , " Television " ) ;
t - > type = V4L2_TUNER_ANALOG_TV ;
t - > capability = V4L2_TUNER_CAP_NORM ;
t - > rangehigh = 0xffffffffUL ;
2011-05-09 16:53:50 -03:00
t - > rxsubchans = V4L2_TUNER_SUB_STEREO ;
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , g_tuner , t ) ;
t - > audmode = dev - > amode ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_s_tuner ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_tuner * t )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
if ( UNSET = = dev - > tuner_type )
return - EINVAL ;
if ( 0 ! = t - > index )
return - EINVAL ;
2011-05-09 16:53:50 -03:00
dev - > amode = t - > audmode ;
dprintk ( dev , 3 , " audio mode: %x \n " , t - > audmode ) ;
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , s_tuner , t ) ;
2011-05-09 16:53:53 -03:00
2009-09-14 09:42:41 -03:00
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_g_frequency ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_frequency * f )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
if ( unlikely ( UNSET = = dev - > tuner_type ) )
return - EINVAL ;
2011-02-17 22:11:05 -03:00
f - > type = fh - > radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV ;
2009-09-14 09:42:41 -03:00
f - > frequency = dev - > freq ;
2009-09-14 16:37:13 -03:00
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , g_frequency , f ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2010-10-20 06:35:12 -03:00
static int vidioc_s_frequency ( struct file * file , void * priv ,
2009-09-14 09:42:41 -03:00
struct v4l2_frequency * f )
{
2010-10-20 06:35:12 -03:00
struct tm6000_fh * fh = priv ;
2009-09-14 09:42:41 -03:00
struct tm6000_core * dev = fh - > dev ;
if ( unlikely ( UNSET = = dev - > tuner_type ) )
return - EINVAL ;
if ( unlikely ( f - > tuner ! = 0 ) )
return - EINVAL ;
2011-02-17 22:11:05 -03:00
if ( 0 = = fh - > radio & & V4L2_TUNER_ANALOG_TV ! = f - > type )
return - EINVAL ;
if ( 1 = = fh - > radio & & V4L2_TUNER_RADIO ! = f - > type )
return - EINVAL ;
2009-09-14 09:42:41 -03:00
dev - > freq = f - > frequency ;
2009-09-14 17:16:32 -03:00
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , s_frequency , f ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2011-02-17 22:11:05 -03:00
static int radio_querycap ( struct file * file , void * priv ,
struct v4l2_capability * cap )
{
struct tm6000_fh * fh = file - > private_data ;
struct tm6000_core * dev = fh - > dev ;
strcpy ( cap - > driver , " tm6000 " ) ;
strlcpy ( cap - > card , dev - > name , sizeof ( dev - > name ) ) ;
sprintf ( cap - > bus_info , " USB%04x:%04x " ,
le16_to_cpu ( dev - > udev - > descriptor . idVendor ) ,
le16_to_cpu ( dev - > udev - > descriptor . idProduct ) ) ;
cap - > version = dev - > dev_type ;
2011-05-09 16:53:50 -03:00
cap - > capabilities = V4L2_CAP_TUNER |
V4L2_CAP_AUDIO |
V4L2_CAP_RADIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING ;
2011-02-17 22:11:05 -03:00
return 0 ;
}
static int radio_g_tuner ( struct file * file , void * priv ,
struct v4l2_tuner * t )
{
struct tm6000_fh * fh = file - > private_data ;
struct tm6000_core * dev = fh - > dev ;
if ( 0 ! = t - > index )
return - EINVAL ;
memset ( t , 0 , sizeof ( * t ) ) ;
strcpy ( t - > name , " Radio " ) ;
t - > type = V4L2_TUNER_RADIO ;
2011-05-09 16:53:50 -03:00
t - > rxsubchans = V4L2_TUNER_SUB_STEREO ;
2011-02-17 22:11:05 -03:00
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , g_tuner , t ) ;
return 0 ;
}
static int radio_s_tuner ( struct file * file , void * priv ,
struct v4l2_tuner * t )
{
struct tm6000_fh * fh = file - > private_data ;
struct tm6000_core * dev = fh - > dev ;
if ( 0 ! = t - > index )
return - EINVAL ;
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , s_tuner , t ) ;
return 0 ;
}
static int radio_enum_input ( struct file * file , void * priv ,
struct v4l2_input * i )
{
2011-05-09 16:53:52 -03:00
struct tm6000_fh * fh = priv ;
struct tm6000_core * dev = fh - > dev ;
2011-02-17 22:11:05 -03:00
if ( i - > index ! = 0 )
return - EINVAL ;
2011-05-09 16:53:52 -03:00
if ( ! dev - > rinput . type )
return - EINVAL ;
2011-02-17 22:11:05 -03:00
strcpy ( i - > name , " Radio " ) ;
i - > type = V4L2_INPUT_TYPE_TUNER ;
return 0 ;
}
static int radio_g_input ( struct file * filp , void * priv , unsigned int * i )
{
2011-05-09 16:53:52 -03:00
struct tm6000_fh * fh = priv ;
struct tm6000_core * dev = fh - > dev ;
2011-06-01 22:21:56 -04:00
if ( dev - > input ! = 5 )
2011-05-09 16:53:52 -03:00
return - EINVAL ;
2011-06-01 22:21:56 -04:00
* i = dev - > input - 5 ;
2011-05-09 16:53:52 -03:00
2011-02-17 22:11:05 -03:00
return 0 ;
}
static int radio_g_audio ( struct file * file , void * priv ,
struct v4l2_audio * a )
{
memset ( a , 0 , sizeof ( * a ) ) ;
strcpy ( a - > name , " Radio " ) ;
return 0 ;
}
static int radio_s_audio ( struct file * file , void * priv ,
struct v4l2_audio * a )
{
return 0 ;
}
static int radio_s_input ( struct file * filp , void * priv , unsigned int i )
{
2011-05-09 16:53:52 -03:00
struct tm6000_fh * fh = priv ;
struct tm6000_core * dev = fh - > dev ;
if ( i )
return - EINVAL ;
if ( ! dev - > rinput . type )
return - EINVAL ;
dev - > input = i + 5 ;
2011-02-17 22:11:05 -03:00
return 0 ;
}
static int radio_s_std ( struct file * file , void * fh , v4l2_std_id * norm )
{
return 0 ;
}
static int radio_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * c )
{
const struct v4l2_queryctrl * ctrl ;
if ( c - > id < V4L2_CID_BASE | |
c - > id > = V4L2_CID_LASTP1 )
return - EINVAL ;
if ( c - > id = = V4L2_CID_AUDIO_MUTE ) {
ctrl = ctrl_by_id ( c - > id ) ;
* c = * ctrl ;
} else
* c = no_ctrl ;
return 0 ;
}
2009-09-14 09:42:41 -03:00
/* ------------------------------------------------------------------
File operations for the device
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2009-09-14 17:16:32 -03:00
static int tm6000_open ( struct file * file )
2009-09-14 09:42:41 -03:00
{
2010-05-18 00:43:18 -03:00
struct video_device * vdev = video_devdata ( file ) ;
struct tm6000_core * dev = video_drvdata ( file ) ;
2009-09-14 09:42:41 -03:00
struct tm6000_fh * fh ;
2010-05-18 04:27:27 -03:00
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2010-10-20 06:35:12 -03:00
int i , rc ;
2011-02-17 22:11:05 -03:00
int radio = 0 ;
2009-09-14 09:42:41 -03:00
2010-05-18 00:43:18 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " tm6000: open called (dev=%s) \n " ,
video_device_node_name ( vdev ) ) ;
2009-09-14 09:42:41 -03:00
2011-02-17 22:11:05 -03:00
switch ( vdev - > vfl_type ) {
case VFL_TYPE_GRABBER :
type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
break ;
case VFL_TYPE_VBI :
type = V4L2_BUF_TYPE_VBI_CAPTURE ;
break ;
case VFL_TYPE_RADIO :
radio = 1 ;
break ;
}
2009-09-14 09:42:41 -03:00
/* If more than one user, mutex should be added */
dev - > users + + ;
2010-05-18 00:43:18 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " open dev=%s type=%s users=%d \n " ,
video_device_node_name ( vdev ) , v4l2_type_names [ type ] ,
dev - > users ) ;
2009-09-14 09:42:41 -03:00
/* allocate + initialize per filehandle data */
2010-10-20 06:35:12 -03:00
fh = kzalloc ( sizeof ( * fh ) , GFP_KERNEL ) ;
2009-09-14 09:42:41 -03:00
if ( NULL = = fh ) {
dev - > users - - ;
return - ENOMEM ;
}
file - > private_data = fh ;
fh - > dev = dev ;
2011-02-17 22:11:05 -03:00
fh - > radio = radio ;
dev - > radio = radio ;
fh - > type = type ;
2009-09-14 09:42:41 -03:00
dev - > fourcc = format [ 0 ] . fourcc ;
fh - > fmt = format_by_fourcc ( dev - > fourcc ) ;
2007-09-03 21:51:45 -03:00
2011-06-01 22:21:56 -04:00
tm6000_get_std_res ( dev ) ;
2007-09-03 21:51:45 -03:00
2011-08-04 04:14:01 -03:00
fh - > width = dev - > width ;
fh - > height = dev - > height ;
2009-09-14 09:42:41 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " Open: fh=0x%08lx, dev=0x%08lx, "
" dev->vidq=0x%08lx \n " ,
2011-08-04 04:14:01 -03:00
( unsigned long ) fh , ( unsigned long ) dev ,
( unsigned long ) & dev - > vidq ) ;
2009-09-14 09:42:41 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " Open: list_empty "
2011-06-01 22:21:56 -04:00
" queued=%d \n " , list_empty ( & dev - > vidq . queued ) ) ;
2009-09-14 09:42:41 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " Open: list_empty "
2011-06-01 22:21:56 -04:00
" active=%d \n " , list_empty ( & dev - > vidq . active ) ) ;
2009-09-14 09:42:41 -03:00
/* initialize hardware on analog mode */
2010-10-12 12:11:55 -03:00
rc = tm6000_init_analog_mode ( dev ) ;
if ( rc < 0 )
return rc ;
2009-09-14 09:42:41 -03:00
2010-10-12 12:11:55 -03:00
if ( dev - > mode ! = TM6000_MODE_ANALOG ) {
2009-09-14 09:42:41 -03:00
/* Put all controls at a sane state */
for ( i = 0 ; i < ARRAY_SIZE ( tm6000_qctrl ) ; i + + )
2010-10-12 12:11:55 -03:00
qctl_regs [ i ] = tm6000_qctrl [ i ] . default_value ;
2009-09-14 09:42:41 -03:00
2010-10-12 12:11:55 -03:00
dev - > mode = TM6000_MODE_ANALOG ;
}
2009-09-14 09:42:41 -03:00
2011-08-04 04:14:15 -03:00
if ( ! fh - > radio ) {
videobuf_queue_vmalloc_init ( & fh - > vb_vidq , & tm6000_video_qops ,
NULL , & dev - > slock ,
fh - > type ,
V4L2_FIELD_INTERLACED ,
sizeof ( struct tm6000_buffer ) , fh , & dev - > lock ) ;
} else {
2011-02-17 22:11:05 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " video_open: setting radio device \n " ) ;
2011-05-09 16:53:53 -03:00
dev - > input = 5 ;
tm6000_set_audio_rinput ( dev ) ;
2011-02-17 22:11:05 -03:00
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , s_radio ) ;
tm6000_prepare_isoc ( dev ) ;
tm6000_start_thread ( dev ) ;
}
2009-09-14 09:42:41 -03:00
return 0 ;
}
static ssize_t
tm6000_read ( struct file * file , char __user * data , size_t count , loff_t * pos )
{
struct tm6000_fh * fh = file - > private_data ;
2011-06-01 22:21:56 -04:00
if ( fh - > type = = V4L2_BUF_TYPE_VIDEO_CAPTURE ) {
2010-10-11 10:48:11 -03:00
if ( ! res_get ( fh - > dev , fh , true ) )
2009-09-14 09:42:41 -03:00
return - EBUSY ;
return videobuf_read_stream ( & fh - > vb_vidq , data , count , pos , 0 ,
file - > f_flags & O_NONBLOCK ) ;
}
return 0 ;
}
static unsigned int
tm6000_poll ( struct file * file , struct poll_table_struct * wait )
{
struct tm6000_fh * fh = file - > private_data ;
struct tm6000_buffer * buf ;
if ( V4L2_BUF_TYPE_VIDEO_CAPTURE ! = fh - > type )
return POLLERR ;
2010-10-11 10:48:11 -03:00
if ( ! ! is_res_streaming ( fh - > dev , fh ) )
return POLLERR ;
if ( ! is_res_read ( fh - > dev , fh ) ) {
2009-09-14 09:42:41 -03:00
/* streaming capture */
if ( list_empty ( & fh - > vb_vidq . stream ) )
return POLLERR ;
2011-06-01 22:21:56 -04:00
buf = list_entry ( fh - > vb_vidq . stream . next , struct tm6000_buffer , vb . stream ) ;
2009-09-14 09:42:41 -03:00
} else {
/* read() capture */
2011-08-04 04:14:01 -03:00
return videobuf_poll_stream ( file , & fh - > vb_vidq , wait ) ;
2009-09-14 09:42:41 -03:00
}
poll_wait ( file , & buf - > vb . done , wait ) ;
2007-11-15 16:37:35 -03:00
if ( buf - > vb . state = = VIDEOBUF_DONE | |
buf - > vb . state = = VIDEOBUF_ERROR )
2010-10-20 06:35:12 -03:00
return POLLIN | POLLRDNORM ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
2009-09-14 17:16:32 -03:00
static int tm6000_release ( struct file * file )
2009-09-14 09:42:41 -03:00
{
struct tm6000_fh * fh = file - > private_data ;
struct tm6000_core * dev = fh - > dev ;
2010-05-18 00:43:18 -03:00
struct video_device * vdev = video_devdata ( file ) ;
2009-09-14 09:42:41 -03:00
2010-05-18 00:43:18 -03:00
dprintk ( dev , V4L2_DEBUG_OPEN , " tm6000: close called (dev=%s, users=%d) \n " ,
video_device_node_name ( vdev ) , dev - > users ) ;
2007-06-16 23:21:48 -03:00
2007-06-17 17:14:12 -03:00
dev - > users - - ;
2010-10-11 10:48:11 -03:00
res_free ( dev , fh ) ;
2011-08-04 04:14:13 -03:00
2007-06-17 17:14:12 -03:00
if ( ! dev - > users ) {
2008-04-09 01:49:19 -03:00
tm6000_uninit_isoc ( dev ) ;
2011-08-04 04:14:15 -03:00
2011-11-28 15:46:18 -03:00
/* Stop interrupt USB pipe */
tm6000_ir_int_stop ( dev ) ;
usb_reset_configuration ( dev - > udev ) ;
if ( & dev - > int_in )
usb_set_interface ( dev - > udev ,
dev - > isoc_in . bInterfaceNumber ,
2 ) ;
else
usb_set_interface ( dev - > udev ,
dev - > isoc_in . bInterfaceNumber ,
0 ) ;
/* Start interrupt USB pipe */
tm6000_ir_int_start ( dev ) ;
2011-08-04 04:14:15 -03:00
if ( ! fh - > radio )
videobuf_mmap_free ( & fh - > vb_vidq ) ;
2007-06-17 17:14:12 -03:00
}
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
kfree ( fh ) ;
2009-09-14 09:42:41 -03:00
return 0 ;
}
static int tm6000_mmap ( struct file * file , struct vm_area_struct * vma )
{
2011-08-04 04:14:01 -03:00
struct tm6000_fh * fh = file - > private_data ;
2009-09-14 09:42:41 -03:00
2011-08-04 04:14:01 -03:00
return videobuf_mmap_mapper ( & fh - > vb_vidq , vma ) ;
2009-09-14 09:42:41 -03:00
}
2009-09-14 17:16:32 -03:00
static struct v4l2_file_operations tm6000_fops = {
2011-08-04 04:14:01 -03:00
. owner = THIS_MODULE ,
. open = tm6000_open ,
. release = tm6000_release ,
. unlocked_ioctl = video_ioctl2 , /* V4L2 ioctl handler */
. read = tm6000_read ,
. poll = tm6000_poll ,
. mmap = tm6000_mmap ,
2009-09-14 09:42:41 -03:00
} ;
2008-10-25 10:43:04 -03:00
static const struct v4l2_ioctl_ops video_ioctl_ops = {
. vidioc_querycap = vidioc_querycap ,
. 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 ,
. 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_g_tuner = vidioc_g_tuner ,
. vidioc_s_tuner = vidioc_s_tuner ,
. vidioc_g_frequency = vidioc_g_frequency ,
. vidioc_s_frequency = vidioc_s_frequency ,
. vidioc_streamon = vidioc_streamon ,
. vidioc_streamoff = vidioc_streamoff ,
. vidioc_reqbufs = vidioc_reqbufs ,
. vidioc_querybuf = vidioc_querybuf ,
. vidioc_qbuf = vidioc_qbuf ,
. vidioc_dqbuf = vidioc_dqbuf ,
} ;
2009-09-14 09:42:41 -03:00
static struct video_device tm6000_template = {
. name = " tm6000 " ,
. fops = & tm6000_fops ,
2008-10-25 10:43:04 -03:00
. ioctl_ops = & video_ioctl_ops ,
2009-09-14 09:42:41 -03:00
. release = video_device_release ,
2008-10-25 10:43:04 -03:00
. tvnorms = TM6000_STD ,
. current_norm = V4L2_STD_NTSC_M ,
2009-09-14 09:42:41 -03:00
} ;
2008-10-25 10:43:04 -03:00
2011-02-17 22:11:05 -03:00
static const struct v4l2_file_operations radio_fops = {
2011-05-09 16:54:01 -03:00
. owner = THIS_MODULE ,
. open = tm6000_open ,
. release = tm6000_release ,
. unlocked_ioctl = video_ioctl2 ,
2011-02-17 22:11:05 -03:00
} ;
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
. vidioc_querycap = radio_querycap ,
. vidioc_g_tuner = radio_g_tuner ,
. vidioc_enum_input = radio_enum_input ,
. vidioc_g_audio = radio_g_audio ,
. vidioc_s_tuner = radio_s_tuner ,
. vidioc_s_audio = radio_s_audio ,
. vidioc_s_input = radio_s_input ,
. vidioc_s_std = radio_s_std ,
. vidioc_queryctrl = radio_queryctrl ,
. vidioc_g_input = radio_g_input ,
. vidioc_g_ctrl = vidioc_g_ctrl ,
. vidioc_s_ctrl = vidioc_s_ctrl ,
. vidioc_g_frequency = vidioc_g_frequency ,
. vidioc_s_frequency = vidioc_s_frequency ,
} ;
2011-08-04 04:14:01 -03:00
static struct video_device tm6000_radio_template = {
2011-02-17 22:11:05 -03:00
. name = " tm6000 " ,
. fops = & radio_fops ,
2011-06-01 22:21:56 -04:00
. ioctl_ops = & radio_ioctl_ops ,
2011-02-17 22:11:05 -03:00
} ;
2009-09-14 09:42:41 -03:00
/* -----------------------------------------------------------------
2010-10-20 06:35:12 -03:00
* Initialization and module stuff
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2009-09-14 09:42:41 -03:00
2011-01-13 00:46:07 -03:00
static struct video_device * vdev_init ( struct tm6000_core * dev ,
const struct video_device
* template , const char * type_name )
2009-09-14 09:42:41 -03:00
{
2007-06-16 23:21:48 -03:00
struct video_device * vfd ;
vfd = video_device_alloc ( ) ;
2011-01-13 00:46:07 -03:00
if ( NULL = = vfd )
return NULL ;
* vfd = * template ;
vfd - > v4l2_dev = & dev - > v4l2_dev ;
vfd - > release = video_device_release ;
vfd - > debug = tm6000_debug ;
vfd - > lock = & dev - > lock ;
snprintf ( vfd - > name , sizeof ( vfd - > name ) , " %s %s " , dev - > name , type_name ) ;
video_set_drvdata ( vfd , dev ) ;
return vfd ;
}
int tm6000_v4l2_register ( struct tm6000_core * dev )
{
int ret = - 1 ;
dev - > vfd = vdev_init ( dev , & tm6000_template , " video " ) ;
if ( ! dev - > vfd ) {
printk ( KERN_INFO " %s: can't register video device \n " ,
dev - > name ) ;
2007-06-16 23:21:48 -03:00
return - ENOMEM ;
}
2009-09-14 09:42:41 -03:00
/* init video dma queues */
INIT_LIST_HEAD ( & dev - > vidq . active ) ;
INIT_LIST_HEAD ( & dev - > vidq . queued ) ;
2011-01-13 00:46:07 -03:00
ret = video_register_device ( dev - > vfd , VFL_TYPE_GRABBER , video_nr ) ;
2010-10-09 17:05:14 -03:00
2011-01-13 00:46:07 -03:00
if ( ret < 0 ) {
printk ( KERN_INFO " %s: can't register video device \n " ,
dev - > name ) ;
return ret ;
}
printk ( KERN_INFO " %s: registered device %s \n " ,
dev - > name , video_device_node_name ( dev - > vfd ) ) ;
2009-09-14 09:42:41 -03:00
2011-05-09 16:53:49 -03:00
if ( dev - > caps . has_radio ) {
dev - > radio_dev = vdev_init ( dev , & tm6000_radio_template ,
" radio " ) ;
if ( ! dev - > radio_dev ) {
printk ( KERN_INFO " %s: can't register radio device \n " ,
dev - > name ) ;
return ret ; /* FIXME release resource */
}
2011-02-17 22:11:05 -03:00
2011-05-09 16:53:49 -03:00
ret = video_register_device ( dev - > radio_dev , VFL_TYPE_RADIO ,
radio_nr ) ;
if ( ret < 0 ) {
printk ( KERN_INFO " %s: can't register radio device \n " ,
dev - > name ) ;
return ret ; /* FIXME release resource */
}
2011-02-17 22:11:05 -03:00
2011-05-09 16:53:49 -03:00
printk ( KERN_INFO " %s: registered device %s \n " ,
dev - > name , video_device_node_name ( dev - > radio_dev ) ) ;
}
2011-02-17 22:11:05 -03:00
2010-02-22 06:32:15 -03:00
printk ( KERN_INFO " Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d) \n " , ret ) ;
2009-09-14 09:42:41 -03:00
return ret ;
}
int tm6000_v4l2_unregister ( struct tm6000_core * dev )
{
2007-06-16 23:21:48 -03:00
video_unregister_device ( dev - > vfd ) ;
2007-06-14 17:19:59 -03:00
2011-02-17 22:11:05 -03:00
if ( dev - > radio_dev ) {
if ( video_is_registered ( dev - > radio_dev ) )
video_unregister_device ( dev - > radio_dev ) ;
else
video_device_release ( dev - > radio_dev ) ;
dev - > radio_dev = NULL ;
}
2009-09-14 09:42:41 -03:00
return 0 ;
}
int tm6000_v4l2_exit ( void )
{
return 0 ;
}
module_param ( video_nr , int , 0 ) ;
2010-10-20 06:35:12 -03:00
MODULE_PARM_DESC ( video_nr , " Allow changing video device number " ) ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
module_param_named ( debug , tm6000_debug , int , 0444 ) ;
MODULE_PARM_DESC ( debug , " activates debug info " ) ;
2009-09-14 09:42:41 -03:00
2010-10-20 06:35:12 -03:00
module_param ( vid_limit , int , 0644 ) ;
MODULE_PARM_DESC ( vid_limit , " capture memory limit in megabytes " ) ;
2009-09-14 09:42:41 -03:00