2005-04-16 15:20:36 -07:00
/* Driver for Philips webcam
Functions that send various control messages to the webcam , including
video modes .
( C ) 1999 - 2003 Nemosoft Unv .
2006-04-24 10:29:46 -03:00
( C ) 2004 - 2006 Luc Saillard ( luc @ saillard . org )
2011-06-26 12:52:01 -03:00
( C ) 2011 Hans de Goede < hdegoede @ redhat . com >
2005-04-16 15:20:36 -07:00
NOTE : this version of pwc is an unofficial ( modified ) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version .
Please send bug reports and support requests to < luc @ saillard . org > .
NOTE : this version of pwc is an unofficial ( modified ) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version .
Please send bug reports and support requests to < luc @ saillard . org > .
The decompression routines have been implemented by reverse - engineering the
Nemosoft binary pwcx module . Caveat emptor .
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 ; either version 2 of the License , or
( at your option ) any later version .
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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
Changes
2006-03-25 09:19:53 -03:00
2001 / 08 / 03 Alvarado Added methods for changing white balance and
red / green gains
2005-04-16 15:20:36 -07:00
*/
/* Control functions for the cam; brightness, contrast, video mode, etc. */
# ifdef __KERNEL__
2016-12-24 11:46:01 -08:00
# include <linux/uaccess.h>
2005-04-16 15:20:36 -07:00
# endif
# include <asm/errno.h>
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
# include "pwc.h"
# include "pwc-kiara.h"
# include "pwc-timon.h"
2006-04-24 10:29:46 -03:00
# include "pwc-dec1.h"
# include "pwc-dec23.h"
2005-04-16 15:20:36 -07:00
2011-06-26 12:52:01 -03:00
/* Selectors for status controls used only in this file */
2006-04-24 10:29:46 -03:00
# define GET_STATUS_B00 0x0B00
2005-04-16 15:20:36 -07:00
# define SENSOR_TYPE_FORMATTER1 0x0C00
2006-04-24 10:29:46 -03:00
# define GET_STATUS_3000 0x3000
2005-04-16 15:20:36 -07:00
# define READ_RAW_Y_MEAN_FORMATTER 0x3100
# define SET_POWER_SAVE_MODE_FORMATTER 0x3200
# define MIRROR_IMAGE_FORMATTER 0x3300
# define LED_FORMATTER 0x3400
2006-04-24 10:29:46 -03:00
# define LOWLIGHT 0x3500
# define GET_STATUS_3600 0x3600
2005-04-16 15:20:36 -07:00
# define SENSOR_TYPE_FORMATTER2 0x3700
2006-04-24 10:29:46 -03:00
# define GET_STATUS_3800 0x3800
# define GET_STATUS_4000 0x4000
# define GET_STATUS_4100 0x4100 /* Get */
# define CTL_STATUS_4200 0x4200 /* [GS] 1 */
2005-04-16 15:20:36 -07:00
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
# define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
2005-11-29 09:43:42 +01:00
static const char * size2name [ PSZ_MAX ] =
2005-04-16 15:20:36 -07:00
{
" subQCIF " ,
" QSIF " ,
" QCIF " ,
" SIF " ,
" CIF " ,
" VGA " ,
2006-03-25 09:19:53 -03:00
} ;
2005-04-16 15:20:36 -07:00
/********/
2006-03-25 09:19:53 -03:00
/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
2005-04-16 15:20:36 -07:00
preferences , so you either get compressed or non - compressed streams .
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
An alternate value of 0 means this mode is not available at all .
*/
2007-04-22 23:54:36 -03:00
# define PWC_FPS_MAX_NALA 8
2005-04-16 15:20:36 -07:00
struct Nala_table_entry {
char alternate ; /* USB alternate setting */
int compressed ; /* Compressed yes/no */
unsigned char mode [ 3 ] ; /* precomputed mode table */
} ;
2007-04-22 23:54:36 -03:00
static unsigned int Nala_fps_vector [ PWC_FPS_MAX_NALA ] = { 4 , 5 , 7 , 10 , 12 , 15 , 20 , 24 } ;
static struct Nala_table_entry Nala_table [ PSZ_MAX ] [ PWC_FPS_MAX_NALA ] =
2005-04-16 15:20:36 -07:00
{
# include "pwc-nala.h"
} ;
/****************************************************************************/
2009-04-21 21:48:09 +02:00
static int recv_control_msg ( struct pwc_device * pdev ,
2012-01-10 17:02:04 -03:00
u8 request , u16 value , int recv_count )
2009-04-21 21:48:09 +02:00
{
int rc ;
rc = usb_control_msg ( pdev - > udev , usb_rcvctrlpipe ( pdev - > udev , 0 ) ,
request ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
2012-01-10 17:02:04 -03:00
value , pdev - > vcinterface ,
pdev - > ctrl_buf , recv_count , USB_CTRL_GET_TIMEOUT ) ;
2011-06-26 12:52:01 -03:00
if ( rc < 0 )
PWC_ERROR ( " recv_control_msg error %d req %02x val %04x \n " ,
rc , request , value ) ;
2009-04-21 21:48:09 +02:00
return rc ;
}
2005-04-16 15:20:36 -07:00
2009-04-21 21:48:09 +02:00
static inline int send_video_command ( struct pwc_device * pdev ,
2012-01-10 17:02:04 -03:00
int index , const unsigned char * buf , int buflen )
2005-04-16 15:20:36 -07:00
{
2012-01-10 17:02:04 -03:00
int rc ;
memcpy ( pdev - > ctrl_buf , buf , buflen ) ;
rc = usb_control_msg ( pdev - > udev , usb_sndctrlpipe ( pdev - > udev , 0 ) ,
SET_EP_STREAM_CTL ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
VIDEO_OUTPUT_CONTROL_FORMATTER , index ,
pdev - > ctrl_buf , buflen , USB_CTRL_SET_TIMEOUT ) ;
if ( rc > = 0 )
memcpy ( pdev - > cmd_buf , buf , buflen ) ;
else
PWC_ERROR ( " send_video_command error %d \n " , rc ) ;
return rc ;
2005-04-16 15:20:36 -07:00
}
2011-07-03 12:23:24 -03:00
int send_control_msg ( struct pwc_device * pdev ,
2009-04-21 21:48:09 +02:00
u8 request , u16 value , void * buf , int buflen )
{
2012-01-10 17:02:04 -03:00
return usb_control_msg ( pdev - > udev , usb_sndctrlpipe ( pdev - > udev , 0 ) ,
request ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
value , pdev - > vcinterface ,
buf , buflen , USB_CTRL_SET_TIMEOUT ) ;
2009-04-21 21:48:09 +02:00
}
2012-01-10 13:01:41 -03:00
static int set_video_mode_Nala ( struct pwc_device * pdev , int size , int pixfmt ,
2012-01-10 13:14:46 -03:00
int frames , int * compression , int send_to_cam )
2005-04-16 15:20:36 -07:00
{
2012-01-10 13:14:46 -03:00
int fps , ret = 0 ;
2005-04-16 15:20:36 -07:00
struct Nala_table_entry * pEntry ;
int frames2frames [ 31 ] =
{ /* closest match of framerate */
0 , 0 , 0 , 0 , 4 , /* 0-4 */
5 , 5 , 7 , 7 , 10 , /* 5-9 */
2006-03-25 09:19:53 -03:00
10 , 10 , 12 , 12 , 15 , /* 10-14 */
15 , 15 , 15 , 20 , 20 , /* 15-19 */
20 , 20 , 20 , 24 , 24 , /* 20-24 */
24 , 24 , 24 , 24 , 24 , /* 25-29 */
24 /* 30 */
2005-04-16 15:20:36 -07:00
} ;
2006-03-25 09:19:53 -03:00
int frames2table [ 31 ] =
2005-04-16 15:20:36 -07:00
{ 0 , 0 , 0 , 0 , 0 , /* 0-4 */
1 , 1 , 1 , 2 , 2 , /* 5-9 */
3 , 3 , 4 , 4 , 4 , /* 10-14 */
5 , 5 , 5 , 5 , 5 , /* 15-19 */
6 , 6 , 6 , 6 , 7 , /* 20-24 */
7 , 7 , 7 , 7 , 7 , /* 25-29 */
7 /* 30 */
} ;
2006-03-25 09:19:53 -03:00
2012-01-08 07:19:29 -03:00
if ( size < 0 | | size > PSZ_CIF )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2012-01-08 07:19:29 -03:00
if ( frames < 4 )
frames = 4 ;
2012-10-08 06:05:24 -03:00
else if ( size > PSZ_QCIF & & frames > 15 )
frames = 15 ;
2012-01-08 07:19:29 -03:00
else if ( frames > 25 )
frames = 25 ;
2005-04-16 15:20:36 -07:00
frames = frames2frames [ frames ] ;
fps = frames2table [ frames ] ;
pEntry = & Nala_table [ size ] [ fps ] ;
if ( pEntry - > alternate = = 0 )
return - EINVAL ;
2012-01-10 13:14:46 -03:00
if ( send_to_cam )
2012-01-10 17:02:04 -03:00
ret = send_video_command ( pdev , pdev - > vendpoint ,
pEntry - > mode , 3 ) ;
if ( ret < 0 )
2005-04-16 15:20:36 -07:00
return ret ;
2006-03-25 09:19:53 -03:00
2012-01-10 17:02:04 -03:00
if ( pEntry - > compressed & & pixfmt = = V4L2_PIX_FMT_YUV420 )
pwc_dec1_init ( pdev , pEntry - > mode ) ;
2005-04-16 15:20:36 -07:00
/* Set various parameters */
2012-01-10 13:01:41 -03:00
pdev - > pixfmt = pixfmt ;
2005-04-16 15:20:36 -07:00
pdev - > vframes = frames ;
pdev - > valternate = pEntry - > alternate ;
2012-01-04 16:58:44 -03:00
pdev - > width = pwc_image_sizes [ size ] [ 0 ] ;
pdev - > height = pwc_image_sizes [ size ] [ 1 ] ;
pdev - > frame_size = ( pdev - > width * pdev - > height * 3 ) / 2 ;
2005-04-16 15:20:36 -07:00
if ( pEntry - > compressed ) {
if ( pdev - > release < 5 ) { /* 4 fold compression */
pdev - > vbandlength = 528 ;
pdev - > frame_size / = 4 ;
}
else {
pdev - > vbandlength = 704 ;
pdev - > frame_size / = 3 ;
}
}
else
pdev - > vbandlength = 0 ;
2012-01-04 18:48:05 -03:00
/* Let pwc-if.c:isoc_init know we don't support higher compression */
* compression = 3 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2012-01-10 13:01:41 -03:00
static int set_video_mode_Timon ( struct pwc_device * pdev , int size , int pixfmt ,
2012-01-10 13:14:46 -03:00
int frames , int * compression , int send_to_cam )
2005-04-16 15:20:36 -07:00
{
const struct Timon_table_entry * pChoose ;
2012-01-10 13:14:46 -03:00
int fps , ret = 0 ;
2005-04-16 15:20:36 -07:00
2012-01-08 07:19:29 -03:00
if ( size > = PSZ_MAX | | * compression < 0 | | * compression > 3 )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2012-01-08 07:19:29 -03:00
if ( frames < 5 )
frames = 5 ;
else if ( size = = PSZ_VGA & & frames > 15 )
frames = 15 ;
else if ( frames > 30 )
frames = 30 ;
2005-04-16 15:20:36 -07:00
fps = ( frames / 5 ) - 1 ;
2012-01-04 18:48:05 -03:00
/* Find a supported framerate with progressively higher compression */
2005-04-16 15:20:36 -07:00
pChoose = NULL ;
2012-01-04 18:48:05 -03:00
while ( * compression < = 3 ) {
pChoose = & Timon_table [ size ] [ fps ] [ * compression ] ;
if ( pChoose - > alternate ! = 0 )
break ;
( * compression ) + + ;
2005-04-16 15:20:36 -07:00
}
if ( pChoose = = NULL | | pChoose - > alternate = = 0 )
return - ENOENT ; /* Not supported. */
2012-01-10 13:14:46 -03:00
if ( send_to_cam )
2012-01-10 17:02:04 -03:00
ret = send_video_command ( pdev , pdev - > vendpoint ,
pChoose - > mode , 13 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
2012-01-10 13:01:41 -03:00
if ( pChoose - > bandlength > 0 & & pixfmt = = V4L2_PIX_FMT_YUV420 )
2012-01-10 17:02:04 -03:00
pwc_dec23_init ( pdev , pChoose - > mode ) ;
2005-04-16 15:20:36 -07:00
/* Set various parameters */
2012-01-10 13:01:41 -03:00
pdev - > pixfmt = pixfmt ;
2012-01-08 07:19:29 -03:00
pdev - > vframes = ( fps + 1 ) * 5 ;
2005-04-16 15:20:36 -07:00
pdev - > valternate = pChoose - > alternate ;
2012-01-04 16:58:44 -03:00
pdev - > width = pwc_image_sizes [ size ] [ 0 ] ;
pdev - > height = pwc_image_sizes [ size ] [ 1 ] ;
2005-04-16 15:20:36 -07:00
pdev - > vbandlength = pChoose - > bandlength ;
if ( pChoose - > bandlength > 0 )
2012-01-04 16:58:44 -03:00
pdev - > frame_size = ( pChoose - > bandlength * pdev - > height ) / 4 ;
2005-04-16 15:20:36 -07:00
else
2012-01-04 16:58:44 -03:00
pdev - > frame_size = ( pdev - > width * pdev - > height * 12 ) / 8 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2012-01-10 13:01:41 -03:00
static int set_video_mode_Kiara ( struct pwc_device * pdev , int size , int pixfmt ,
2012-01-10 13:14:46 -03:00
int frames , int * compression , int send_to_cam )
2005-04-16 15:20:36 -07:00
{
const struct Kiara_table_entry * pChoose = NULL ;
2012-01-10 13:14:46 -03:00
int fps , ret = 0 ;
2005-04-16 15:20:36 -07:00
2012-01-08 07:19:29 -03:00
if ( size > = PSZ_MAX | | * compression < 0 | | * compression > 3 )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2012-01-08 07:19:29 -03:00
if ( frames < 5 )
frames = 5 ;
else if ( size = = PSZ_VGA & & frames > 15 )
frames = 15 ;
else if ( frames > 30 )
frames = 30 ;
2005-04-16 15:20:36 -07:00
fps = ( frames / 5 ) - 1 ;
2012-01-04 18:48:05 -03:00
/* Find a supported framerate with progressively higher compression */
while ( * compression < = 3 ) {
pChoose = & Kiara_table [ size ] [ fps ] [ * compression ] ;
2011-12-31 10:52:02 -03:00
if ( pChoose - > alternate ! = 0 )
break ;
2012-01-04 18:48:05 -03:00
( * compression ) + + ;
2005-04-16 15:20:36 -07:00
}
if ( pChoose = = NULL | | pChoose - > alternate = = 0 )
return - ENOENT ; /* Not supported. */
/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
2012-01-10 13:14:46 -03:00
if ( send_to_cam )
2012-01-10 17:02:04 -03:00
ret = send_video_command ( pdev , 4 , pChoose - > mode , 12 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
2012-01-10 13:01:41 -03:00
if ( pChoose - > bandlength > 0 & & pixfmt = = V4L2_PIX_FMT_YUV420 )
2012-01-10 17:02:04 -03:00
pwc_dec23_init ( pdev , pChoose - > mode ) ;
2005-04-16 15:20:36 -07:00
/* All set and go */
2012-01-10 13:01:41 -03:00
pdev - > pixfmt = pixfmt ;
2012-01-08 07:19:29 -03:00
pdev - > vframes = ( fps + 1 ) * 5 ;
2005-04-16 15:20:36 -07:00
pdev - > valternate = pChoose - > alternate ;
2012-01-04 16:58:44 -03:00
pdev - > width = pwc_image_sizes [ size ] [ 0 ] ;
pdev - > height = pwc_image_sizes [ size ] [ 1 ] ;
2005-04-16 15:20:36 -07:00
pdev - > vbandlength = pChoose - > bandlength ;
if ( pdev - > vbandlength > 0 )
2012-01-04 16:58:44 -03:00
pdev - > frame_size = ( pdev - > vbandlength * pdev - > height ) / 4 ;
2005-04-16 15:20:36 -07:00
else
2012-01-04 16:58:44 -03:00
pdev - > frame_size = ( pdev - > width * pdev - > height * 12 ) / 8 ;
2011-12-31 10:52:02 -03:00
PWC_TRACE ( " frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d \n " ,
pdev - > frame_size , pdev - > vframes , size , pdev - > vbandlength ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2011-12-31 10:52:02 -03:00
int pwc_set_video_mode ( struct pwc_device * pdev , int width , int height ,
2012-01-10 13:14:46 -03:00
int pixfmt , int frames , int * compression , int send_to_cam )
2005-04-16 15:20:36 -07:00
{
2006-03-25 09:19:53 -03:00
int ret , size ;
2005-04-16 15:20:36 -07:00
2012-01-08 11:29:19 -03:00
PWC_DEBUG_FLOW ( " set_video_mode(%dx%d @ %d, pixfmt %08x). \n " ,
2012-01-10 13:01:41 -03:00
width , height , frames , pixfmt ) ;
2012-01-04 16:58:44 -03:00
size = pwc_get_size ( pdev , width , height ) ;
2006-04-24 10:29:46 -03:00
PWC_TRACE ( " decode_size = %d. \n " , size ) ;
2005-04-16 15:20:36 -07:00
2006-04-24 10:29:46 -03:00
if ( DEVICE_USE_CODEC1 ( pdev - > type ) ) {
2012-01-10 13:01:41 -03:00
ret = set_video_mode_Nala ( pdev , size , pixfmt , frames ,
2012-01-10 13:14:46 -03:00
compression , send_to_cam ) ;
2006-04-24 10:29:46 -03:00
} else if ( DEVICE_USE_CODEC3 ( pdev - > type ) ) {
2012-01-10 13:01:41 -03:00
ret = set_video_mode_Kiara ( pdev , size , pixfmt , frames ,
2012-01-10 13:14:46 -03:00
compression , send_to_cam ) ;
2006-04-24 10:29:46 -03:00
} else {
2012-01-10 13:01:41 -03:00
ret = set_video_mode_Timon ( pdev , size , pixfmt , frames ,
2012-01-10 13:14:46 -03:00
compression , send_to_cam ) ;
2005-04-16 15:20:36 -07:00
}
if ( ret < 0 ) {
2006-04-24 10:29:46 -03:00
PWC_ERROR ( " Failed to set video mode %s@%d fps; return code = %d \n " , size2name [ size ] , frames , ret ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
pdev - > frame_total_size = pdev - > frame_size + pdev - > frame_header_size + pdev - > frame_trailer_size ;
2012-01-04 16:58:44 -03:00
PWC_DEBUG_SIZE ( " Set resolution to %dx%d \n " , pdev - > width , pdev - > height ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-04-22 23:54:36 -03:00
static unsigned int pwc_get_fps_Nala ( struct pwc_device * pdev , unsigned int index , unsigned int size )
{
unsigned int i ;
for ( i = 0 ; i < PWC_FPS_MAX_NALA ; i + + ) {
if ( Nala_table [ size ] [ i ] . alternate ) {
if ( index - - = = 0 ) return Nala_fps_vector [ i ] ;
}
}
return 0 ;
}
static unsigned int pwc_get_fps_Kiara ( struct pwc_device * pdev , unsigned int index , unsigned int size )
{
unsigned int i ;
for ( i = 0 ; i < PWC_FPS_MAX_KIARA ; i + + ) {
if ( Kiara_table [ size ] [ i ] [ 3 ] . alternate ) {
if ( index - - = = 0 ) return Kiara_fps_vector [ i ] ;
}
}
return 0 ;
}
static unsigned int pwc_get_fps_Timon ( struct pwc_device * pdev , unsigned int index , unsigned int size )
{
unsigned int i ;
for ( i = 0 ; i < PWC_FPS_MAX_TIMON ; i + + ) {
if ( Timon_table [ size ] [ i ] [ 3 ] . alternate ) {
if ( index - - = = 0 ) return Timon_fps_vector [ i ] ;
}
}
return 0 ;
}
unsigned int pwc_get_fps ( struct pwc_device * pdev , unsigned int index , unsigned int size )
{
unsigned int ret ;
if ( DEVICE_USE_CODEC1 ( pdev - > type ) ) {
ret = pwc_get_fps_Nala ( pdev , index , size ) ;
} else if ( DEVICE_USE_CODEC3 ( pdev - > type ) ) {
ret = pwc_get_fps_Kiara ( pdev , index , size ) ;
} else {
ret = pwc_get_fps_Timon ( pdev , index , size ) ;
}
return ret ;
}
2011-06-26 12:52:01 -03:00
int pwc_get_u8_ctrl ( struct pwc_device * pdev , u8 request , u16 value , int * data )
2005-04-16 15:20:36 -07:00
{
int ret ;
2012-01-10 17:02:04 -03:00
ret = recv_control_msg ( pdev , request , value , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
2012-01-10 17:02:04 -03:00
* data = pdev - > ctrl_buf [ 0 ] ;
2011-06-26 12:52:01 -03:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2011-06-26 12:52:01 -03:00
int pwc_set_u8_ctrl ( struct pwc_device * pdev , u8 request , u16 value , u8 data )
2005-04-16 15:20:36 -07:00
{
int ret ;
2012-01-10 17:02:04 -03:00
pdev - > ctrl_buf [ 0 ] = data ;
ret = send_control_msg ( pdev , request , value , pdev - > ctrl_buf , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
2011-06-26 12:52:01 -03:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2011-06-26 12:52:01 -03:00
int pwc_get_s8_ctrl ( struct pwc_device * pdev , u8 request , u16 value , int * data )
2005-04-16 15:20:36 -07:00
{
int ret ;
2006-03-25 09:19:53 -03:00
2012-01-10 17:02:04 -03:00
ret = recv_control_msg ( pdev , request , value , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
2012-01-10 17:02:04 -03:00
* data = ( ( s8 * ) pdev - > ctrl_buf ) [ 0 ] ;
2006-04-24 10:29:46 -03:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2011-06-26 12:52:01 -03:00
int pwc_get_u16_ctrl ( struct pwc_device * pdev , u8 request , u16 value , int * data )
2005-04-16 15:20:36 -07:00
{
int ret ;
2006-03-25 09:19:53 -03:00
2012-01-10 17:02:04 -03:00
ret = recv_control_msg ( pdev , request , value , 2 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
2011-06-26 12:52:01 -03:00
2012-01-10 17:02:04 -03:00
* data = ( pdev - > ctrl_buf [ 1 ] < < 8 ) | pdev - > ctrl_buf [ 0 ] ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2011-06-26 12:52:01 -03:00
int pwc_set_u16_ctrl ( struct pwc_device * pdev , u8 request , u16 value , u16 data )
2005-04-16 15:20:36 -07:00
{
int ret ;
2006-03-25 09:19:53 -03:00
2012-01-10 17:02:04 -03:00
pdev - > ctrl_buf [ 0 ] = data & 0xff ;
pdev - > ctrl_buf [ 1 ] = data > > 8 ;
ret = send_control_msg ( pdev , request , value , pdev - > ctrl_buf , 2 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
return 0 ;
}
2011-06-26 12:52:01 -03:00
int pwc_button_ctrl ( struct pwc_device * pdev , u16 value )
2005-04-16 15:20:36 -07:00
{
2006-04-24 10:29:46 -03:00
int ret ;
2011-06-26 12:52:01 -03:00
ret = send_control_msg ( pdev , SET_STATUS_CTL , value , NULL , 0 ) ;
2006-04-24 10:29:46 -03:00
if ( ret < 0 )
return ret ;
2011-06-26 12:52:01 -03:00
2006-04-24 10:29:46 -03:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
/* POWER */
2011-06-26 03:51:19 -03:00
void pwc_camera_power ( struct pwc_device * pdev , int power )
2005-04-16 15:20:36 -07:00
{
2011-06-26 03:51:19 -03:00
int r ;
if ( ! pdev - > power_save )
return ;
2005-04-16 15:20:36 -07:00
if ( pdev - > type < 675 | | ( pdev - > type < 730 & & pdev - > release < 6 ) )
2011-06-26 03:51:19 -03:00
return ; /* Not supported by Nala or Timon < release 6 */
2005-04-16 15:20:36 -07:00
if ( power )
2012-01-10 17:02:04 -03:00
pdev - > ctrl_buf [ 0 ] = 0x00 ; /* active */
2005-04-16 15:20:36 -07:00
else
2012-01-10 17:02:04 -03:00
pdev - > ctrl_buf [ 0 ] = 0xFF ; /* power save */
r = send_control_msg ( pdev , SET_STATUS_CTL ,
SET_POWER_SAVE_MODE_FORMATTER , pdev - > ctrl_buf , 1 ) ;
2011-06-26 03:51:19 -03:00
if ( r < 0 )
PWC_ERROR ( " Failed to power %s camera (%d) \n " ,
power ? " on " : " off " , r ) ;
}
2005-04-16 15:20:36 -07:00
int pwc_set_leds ( struct pwc_device * pdev , int on_value , int off_value )
{
2011-06-26 03:51:19 -03:00
int r ;
2005-04-16 15:20:36 -07:00
if ( pdev - > type < 730 )
return 0 ;
on_value / = 100 ;
off_value / = 100 ;
if ( on_value < 0 )
on_value = 0 ;
if ( on_value > 0xff )
on_value = 0xff ;
if ( off_value < 0 )
off_value = 0 ;
if ( off_value > 0xff )
off_value = 0xff ;
2012-01-10 17:02:04 -03:00
pdev - > ctrl_buf [ 0 ] = on_value ;
pdev - > ctrl_buf [ 1 ] = off_value ;
2005-04-16 15:20:36 -07:00
2011-06-26 03:51:19 -03:00
r = send_control_msg ( pdev ,
2012-01-10 17:02:04 -03:00
SET_STATUS_CTL , LED_FORMATTER , pdev - > ctrl_buf , 2 ) ;
2011-06-26 03:51:19 -03:00
if ( r < 0 )
PWC_ERROR ( " Failed to set LED on/off time (%d) \n " , r ) ;
return r ;
2005-04-16 15:20:36 -07:00
}
2011-06-26 06:49:59 -03:00
# ifdef CONFIG_USB_PWC_DEBUG
2005-04-16 15:20:36 -07:00
int pwc_get_cmos_sensor ( struct pwc_device * pdev , int * sensor )
{
int ret = - 1 , request ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( pdev - > type < 675 )
request = SENSOR_TYPE_FORMATTER1 ;
else if ( pdev - > type < 730 )
return - 1 ; /* The Vesta series doesn't have this call */
else
request = SENSOR_TYPE_FORMATTER2 ;
2006-03-25 09:19:53 -03:00
2012-01-10 17:02:04 -03:00
ret = recv_control_msg ( pdev , GET_STATUS_CTL , request , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 )
return ret ;
if ( pdev - > type < 675 )
2012-01-10 17:02:04 -03:00
* sensor = pdev - > ctrl_buf [ 0 ] | 0x100 ;
2005-04-16 15:20:36 -07:00
else
2012-01-10 17:02:04 -03:00
* sensor = pdev - > ctrl_buf [ 0 ] ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2011-06-26 06:49:59 -03:00
# endif