2011-06-05 07:44:34 -03:00
/*
* GSPCA Endpoints ( formerly known as AOX ) se401 USB Camera sub Driver
*
* Copyright ( C ) 2011 Hans de Goede < hdegoede @ redhat . com >
*
* Based on the v4l1 se401 driver which is :
*
* Copyright ( c ) 2000 Jeroen B . Vreeken ( pe1rxq @ amsat . org )
*
* 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 .
*
*/
2011-08-21 19:56:57 -03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2011-06-05 07:44:34 -03:00
# define MODULE_NAME "se401"
# define BULK_SIZE 4096
# define PACKET_SIZE 1024
# define READ_REQ_SIZE 64
# define MAX_MODES ((READ_REQ_SIZE - 6) / 4)
/* The se401 compression algorithm uses a fixed quant factor, which
can be configured by setting the high nibble of the SE401_OPERATINGMODE
feature . This needs to exactly match what is in libv4l ! */
# define SE401_QUANT_FACT 8
# include <linux/input.h>
# include <linux/slab.h>
# include "gspca.h"
# include "se401.h"
MODULE_AUTHOR ( " Hans de Goede <hdegoede@redhat.com> " ) ;
MODULE_DESCRIPTION ( " Endpoints se401 " ) ;
MODULE_LICENSE ( " GPL " ) ;
/* exposure change state machine states */
enum {
EXPO_CHANGED ,
EXPO_DROP_FRAME ,
EXPO_NO_CHANGE ,
} ;
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev ; /* !! must be the first item */
2012-05-16 07:14:14 -03:00
struct { /* exposure/freq control cluster */
struct v4l2_ctrl * exposure ;
struct v4l2_ctrl * freq ;
} ;
bool has_brightness ;
2011-06-05 07:44:34 -03:00
struct v4l2_pix_format fmts [ MAX_MODES ] ;
int pixels_read ;
int packet_read ;
u8 packet [ PACKET_SIZE ] ;
u8 restart_stream ;
u8 button_state ;
u8 resetlevel ;
u8 resetlevel_frame_count ;
int resetlevel_adjust_dir ;
int expo_change_state ;
} ;
static void se401_write_req ( struct gspca_dev * gspca_dev , u16 req , u16 value ,
int silent )
{
int err ;
if ( gspca_dev - > usb_err < 0 )
return ;
err = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) , req ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
value , 0 , NULL , 0 , 1000 ) ;
if ( err < 0 ) {
if ( ! silent )
2011-08-21 19:56:57 -03:00
pr_err ( " write req failed req %#04x val %#04x error %d \n " ,
req , value , err ) ;
2011-06-05 07:44:34 -03:00
gspca_dev - > usb_err = err ;
}
}
static void se401_read_req ( struct gspca_dev * gspca_dev , u16 req , int silent )
{
int err ;
if ( gspca_dev - > usb_err < 0 )
return ;
if ( USB_BUF_SZ < READ_REQ_SIZE ) {
2011-08-21 19:56:57 -03:00
pr_err ( " USB_BUF_SZ too small!! \n " ) ;
2011-06-05 07:44:34 -03:00
gspca_dev - > usb_err = - ENOBUFS ;
return ;
}
err = usb_control_msg ( gspca_dev - > dev ,
usb_rcvctrlpipe ( gspca_dev - > dev , 0 ) , req ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
0 , 0 , gspca_dev - > usb_buf , READ_REQ_SIZE , 1000 ) ;
if ( err < 0 ) {
if ( ! silent )
2011-08-21 19:56:57 -03:00
pr_err ( " read req failed req %#04x error %d \n " ,
req , err ) ;
2011-06-05 07:44:34 -03:00
gspca_dev - > usb_err = err ;
}
}
static void se401_set_feature ( struct gspca_dev * gspca_dev ,
u16 selector , u16 param )
{
int err ;
if ( gspca_dev - > usb_err < 0 )
return ;
err = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) ,
SE401_REQ_SET_EXT_FEATURE ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
param , selector , NULL , 0 , 1000 ) ;
if ( err < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " set feature failed sel %#04x param %#04x error %d \n " ,
selector , param , err ) ;
2011-06-05 07:44:34 -03:00
gspca_dev - > usb_err = err ;
}
}
static int se401_get_feature ( struct gspca_dev * gspca_dev , u16 selector )
{
int err ;
if ( gspca_dev - > usb_err < 0 )
return gspca_dev - > usb_err ;
if ( USB_BUF_SZ < 2 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " USB_BUF_SZ too small!! \n " ) ;
2011-06-05 07:44:34 -03:00
gspca_dev - > usb_err = - ENOBUFS ;
return gspca_dev - > usb_err ;
}
err = usb_control_msg ( gspca_dev - > dev ,
usb_rcvctrlpipe ( gspca_dev - > dev , 0 ) ,
SE401_REQ_GET_EXT_FEATURE ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
0 , selector , gspca_dev - > usb_buf , 2 , 1000 ) ;
if ( err < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " get feature failed sel %#04x error %d \n " ,
selector , err ) ;
2011-06-05 07:44:34 -03:00
gspca_dev - > usb_err = err ;
return err ;
}
return gspca_dev - > usb_buf [ 0 ] | ( gspca_dev - > usb_buf [ 1 ] < < 8 ) ;
}
2012-05-16 07:14:14 -03:00
static void setbrightness ( struct gspca_dev * gspca_dev , s32 val )
2011-06-05 07:44:34 -03:00
{
/* HDG: this does not seem to do anything on my cam */
2012-05-16 07:14:14 -03:00
se401_write_req ( gspca_dev , SE401_REQ_SET_BRT , val , 0 ) ;
2011-06-05 07:44:34 -03:00
}
2012-05-16 07:14:14 -03:00
static void setgain ( struct gspca_dev * gspca_dev , s32 val )
2011-06-05 07:44:34 -03:00
{
2012-05-16 07:14:14 -03:00
u16 gain = 63 - val ;
2011-06-05 07:44:34 -03:00
/* red color gain */
se401_set_feature ( gspca_dev , HV7131_REG_ARCG , gain ) ;
/* green color gain */
se401_set_feature ( gspca_dev , HV7131_REG_AGCG , gain ) ;
/* blue color gain */
se401_set_feature ( gspca_dev , HV7131_REG_ABCG , gain ) ;
}
2012-05-16 07:14:14 -03:00
static void setexposure ( struct gspca_dev * gspca_dev , s32 val , s32 freq )
2011-06-05 07:44:34 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2012-05-16 07:14:14 -03:00
int integration = val < < 6 ;
2011-06-05 07:44:34 -03:00
u8 expose_h , expose_m , expose_l ;
/* Do this before the set_feature calls, for proper timing wrt
the interrupt driven pkt_scan . Note we may still race but that
is not a big issue , the expo change state machine is merely for
avoiding underexposed frames getting send out , if one sneaks
through so be it */
sd - > expo_change_state = EXPO_CHANGED ;
2012-05-16 07:14:14 -03:00
if ( freq = = V4L2_CID_POWER_LINE_FREQUENCY_50HZ )
2011-06-05 07:44:34 -03:00
integration = integration - integration % 106667 ;
2012-05-16 07:14:14 -03:00
if ( freq = = V4L2_CID_POWER_LINE_FREQUENCY_60HZ )
2011-06-05 07:44:34 -03:00
integration = integration - integration % 88889 ;
expose_h = ( integration > > 16 ) ;
expose_m = ( integration > > 8 ) ;
expose_l = integration ;
/* integration time low */
se401_set_feature ( gspca_dev , HV7131_REG_TITL , expose_l ) ;
/* integration time mid */
se401_set_feature ( gspca_dev , HV7131_REG_TITM , expose_m ) ;
/* integration time high */
se401_set_feature ( gspca_dev , HV7131_REG_TITU , expose_h ) ;
}
static int sd_config ( struct gspca_dev * gspca_dev ,
const struct usb_device_id * id )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
struct cam * cam = & gspca_dev - > cam ;
u8 * cd = gspca_dev - > usb_buf ;
int i , j , n ;
int widths [ MAX_MODES ] , heights [ MAX_MODES ] ;
/* Read the camera descriptor */
se401_read_req ( gspca_dev , SE401_REQ_GET_CAMERA_DESCRIPTOR , 1 ) ;
if ( gspca_dev - > usb_err ) {
/* Sometimes after being idle for a while the se401 won't
respond and needs a good kicking */
usb_reset_device ( gspca_dev - > dev ) ;
gspca_dev - > usb_err = 0 ;
se401_read_req ( gspca_dev , SE401_REQ_GET_CAMERA_DESCRIPTOR , 0 ) ;
}
/* Some cameras start with their LED on */
se401_write_req ( gspca_dev , SE401_REQ_LED_CONTROL , 0 , 0 ) ;
if ( gspca_dev - > usb_err )
return gspca_dev - > usb_err ;
if ( cd [ 1 ] ! = 0x41 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Wrong descriptor type \n " ) ;
2011-06-05 07:44:34 -03:00
return - ENODEV ;
}
if ( ! ( cd [ 2 ] & SE401_FORMAT_BAYER ) ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Bayer format not supported! \n " ) ;
2011-06-05 07:44:34 -03:00
return - ENODEV ;
}
if ( cd [ 3 ] )
2011-08-21 19:56:57 -03:00
pr_info ( " ExtraFeatures: %d \n " , cd [ 3 ] ) ;
2011-06-05 07:44:34 -03:00
n = cd [ 4 ] | ( cd [ 5 ] < < 8 ) ;
if ( n > MAX_MODES ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Too many frame sizes \n " ) ;
2011-06-05 07:44:34 -03:00
return - ENODEV ;
}
for ( i = 0 ; i < n ; i + + ) {
widths [ i ] = cd [ 6 + i * 4 + 0 ] | ( cd [ 6 + i * 4 + 1 ] < < 8 ) ;
heights [ i ] = cd [ 6 + i * 4 + 2 ] | ( cd [ 6 + i * 4 + 3 ] < < 8 ) ;
}
for ( i = 0 ; i < n ; i + + ) {
sd - > fmts [ i ] . width = widths [ i ] ;
sd - > fmts [ i ] . height = heights [ i ] ;
sd - > fmts [ i ] . field = V4L2_FIELD_NONE ;
sd - > fmts [ i ] . colorspace = V4L2_COLORSPACE_SRGB ;
sd - > fmts [ i ] . priv = 1 ;
/* janggu compression only works for 1/4th or 1/16th res */
for ( j = 0 ; j < n ; j + + ) {
if ( widths [ j ] / 2 = = widths [ i ] & &
heights [ j ] / 2 = = heights [ i ] ) {
sd - > fmts [ i ] . priv = 2 ;
break ;
}
}
/* 1/16th if available too is better then 1/4th, because
we then use a larger area of the sensor */
for ( j = 0 ; j < n ; j + + ) {
if ( widths [ j ] / 4 = = widths [ i ] & &
heights [ j ] / 4 = = heights [ i ] ) {
sd - > fmts [ i ] . priv = 4 ;
break ;
}
}
if ( sd - > fmts [ i ] . priv = = 1 ) {
/* Not a 1/4th or 1/16th res, use bayer */
sd - > fmts [ i ] . pixelformat = V4L2_PIX_FMT_SBGGR8 ;
sd - > fmts [ i ] . bytesperline = widths [ i ] ;
sd - > fmts [ i ] . sizeimage = widths [ i ] * heights [ i ] ;
2011-08-21 19:56:57 -03:00
pr_info ( " Frame size: %dx%d bayer \n " ,
widths [ i ] , heights [ i ] ) ;
2011-06-05 07:44:34 -03:00
} else {
/* Found a match use janggu compression */
sd - > fmts [ i ] . pixelformat = V4L2_PIX_FMT_SE401 ;
sd - > fmts [ i ] . bytesperline = 0 ;
sd - > fmts [ i ] . sizeimage = widths [ i ] * heights [ i ] * 3 ;
2011-08-21 19:56:57 -03:00
pr_info ( " Frame size: %dx%d 1/%dth janggu \n " ,
widths [ i ] , heights [ i ] ,
sd - > fmts [ i ] . priv * sd - > fmts [ i ] . priv ) ;
2011-06-05 07:44:34 -03:00
}
}
cam - > cam_mode = sd - > fmts ;
cam - > nmodes = n ;
cam - > bulk = 1 ;
cam - > bulk_size = BULK_SIZE ;
cam - > bulk_nurbs = 4 ;
sd - > resetlevel = 0x2d ; /* Set initial resetlevel */
/* See if the camera supports brightness */
se401_read_req ( gspca_dev , SE401_REQ_GET_BRT , 1 ) ;
2012-05-16 07:14:14 -03:00
sd - > has_brightness = ! ! gspca_dev - > usb_err ;
gspca_dev - > usb_err = 0 ;
2011-06-05 07:44:34 -03:00
return 0 ;
}
/* this function is called at probe and resume time */
static int sd_init ( struct gspca_dev * gspca_dev )
{
return 0 ;
}
2011-11-30 05:54:16 -03:00
/* function called at start time before URB creation */
static int sd_isoc_init ( struct gspca_dev * gspca_dev )
{
gspca_dev - > alt = 1 ; /* Ignore the bogus isoc alt settings */
return gspca_dev - > usb_err ;
}
2011-06-05 07:44:34 -03:00
/* -- start the camera -- */
static int sd_start ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int mult = gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . priv ;
int mode = 0 ;
se401_write_req ( gspca_dev , SE401_REQ_CAMERA_POWER , 1 , 1 ) ;
if ( gspca_dev - > usb_err ) {
/* Sometimes after being idle for a while the se401 won't
respond and needs a good kicking */
usb_reset_device ( gspca_dev - > dev ) ;
gspca_dev - > usb_err = 0 ;
se401_write_req ( gspca_dev , SE401_REQ_CAMERA_POWER , 1 , 0 ) ;
}
se401_write_req ( gspca_dev , SE401_REQ_LED_CONTROL , 1 , 0 ) ;
se401_set_feature ( gspca_dev , HV7131_REG_MODE_B , 0x05 ) ;
/* set size + mode */
se401_write_req ( gspca_dev , SE401_REQ_SET_WIDTH ,
2013-08-30 17:54:23 -03:00
gspca_dev - > pixfmt . width * mult , 0 ) ;
2011-06-05 07:44:34 -03:00
se401_write_req ( gspca_dev , SE401_REQ_SET_HEIGHT ,
2013-08-30 17:54:23 -03:00
gspca_dev - > pixfmt . height * mult , 0 ) ;
2011-06-05 07:44:34 -03:00
/*
* HDG : disabled this as it does not seem to do anything
* se401_write_req ( gspca_dev , SE401_REQ_SET_OUTPUT_MODE ,
* SE401_FORMAT_BAYER , 0 ) ;
*/
switch ( mult ) {
case 1 : /* Raw bayer */
mode = 0x03 ; break ;
case 2 : /* 1/4th janggu */
mode = SE401_QUANT_FACT < < 4 ; break ;
case 4 : /* 1/16th janggu */
mode = ( SE401_QUANT_FACT < < 4 ) | 0x02 ; break ;
}
se401_set_feature ( gspca_dev , SE401_OPERATINGMODE , mode ) ;
se401_set_feature ( gspca_dev , HV7131_REG_ARLV , sd - > resetlevel ) ;
sd - > packet_read = 0 ;
sd - > pixels_read = 0 ;
sd - > restart_stream = 0 ;
sd - > resetlevel_frame_count = 0 ;
sd - > resetlevel_adjust_dir = 0 ;
sd - > expo_change_state = EXPO_NO_CHANGE ;
se401_write_req ( gspca_dev , SE401_REQ_START_CONTINUOUS_CAPTURE , 0 , 0 ) ;
return gspca_dev - > usb_err ;
}
static void sd_stopN ( struct gspca_dev * gspca_dev )
{
se401_write_req ( gspca_dev , SE401_REQ_STOP_CONTINUOUS_CAPTURE , 0 , 0 ) ;
se401_write_req ( gspca_dev , SE401_REQ_LED_CONTROL , 0 , 0 ) ;
se401_write_req ( gspca_dev , SE401_REQ_CAMERA_POWER , 0 , 0 ) ;
}
static void sd_dq_callback ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
unsigned int ahrc , alrc ;
int oldreset , adjust_dir ;
/* Restart the stream if requested do so by pkt_scan */
if ( sd - > restart_stream ) {
sd_stopN ( gspca_dev ) ;
sd_start ( gspca_dev ) ;
sd - > restart_stream = 0 ;
}
/* Automatically adjust sensor reset level
Hyundai have some really nice docs about this and other sensor
related stuff on their homepage : www . hei . co . kr */
sd - > resetlevel_frame_count + + ;
if ( sd - > resetlevel_frame_count < 20 )
return ;
/* For some reason this normally read-only register doesn't get reset
to zero after reading them just once . . . */
se401_get_feature ( gspca_dev , HV7131_REG_HIREFNOH ) ;
se401_get_feature ( gspca_dev , HV7131_REG_HIREFNOL ) ;
se401_get_feature ( gspca_dev , HV7131_REG_LOREFNOH ) ;
se401_get_feature ( gspca_dev , HV7131_REG_LOREFNOL ) ;
ahrc = 256 * se401_get_feature ( gspca_dev , HV7131_REG_HIREFNOH ) +
se401_get_feature ( gspca_dev , HV7131_REG_HIREFNOL ) ;
alrc = 256 * se401_get_feature ( gspca_dev , HV7131_REG_LOREFNOH ) +
se401_get_feature ( gspca_dev , HV7131_REG_LOREFNOL ) ;
/* Not an exact science, but it seems to work pretty well... */
oldreset = sd - > resetlevel ;
if ( alrc > 10 ) {
while ( alrc > = 10 & & sd - > resetlevel < 63 ) {
sd - > resetlevel + + ;
alrc / = 2 ;
}
} else if ( ahrc > 20 ) {
while ( ahrc > = 20 & & sd - > resetlevel > 0 ) {
sd - > resetlevel - - ;
ahrc / = 2 ;
}
}
/* Detect ping-pong-ing and halve adjustment to avoid overshoot */
if ( sd - > resetlevel > oldreset )
adjust_dir = 1 ;
else
adjust_dir = - 1 ;
if ( sd - > resetlevel_adjust_dir & &
sd - > resetlevel_adjust_dir ! = adjust_dir )
sd - > resetlevel = oldreset + ( sd - > resetlevel - oldreset ) / 2 ;
if ( sd - > resetlevel ! = oldreset ) {
sd - > resetlevel_adjust_dir = adjust_dir ;
se401_set_feature ( gspca_dev , HV7131_REG_ARLV , sd - > resetlevel ) ;
}
sd - > resetlevel_frame_count = 0 ;
}
static void sd_complete_frame ( struct gspca_dev * gspca_dev , u8 * data , int len )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
switch ( sd - > expo_change_state ) {
case EXPO_CHANGED :
/* The exposure was changed while this frame
was being send , so this frame is ok */
sd - > expo_change_state = EXPO_DROP_FRAME ;
break ;
case EXPO_DROP_FRAME :
/* The exposure was changed while this frame
was being captured , drop it ! */
gspca_dev - > last_packet_type = DISCARD_PACKET ;
sd - > expo_change_state = EXPO_NO_CHANGE ;
break ;
case EXPO_NO_CHANGE :
break ;
}
gspca_frame_add ( gspca_dev , LAST_PACKET , data , len ) ;
}
static void sd_pkt_scan_janggu ( struct gspca_dev * gspca_dev , u8 * data , int len )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2013-08-30 17:54:23 -03:00
int imagesize = gspca_dev - > pixfmt . width * gspca_dev - > pixfmt . height ;
2011-06-05 07:44:34 -03:00
int i , plen , bits , pixels , info , count ;
if ( sd - > restart_stream )
return ;
/* Sometimes a 1024 bytes garbage bulk packet is send between frames */
if ( gspca_dev - > last_packet_type = = LAST_PACKET & & len = = 1024 ) {
gspca_dev - > last_packet_type = DISCARD_PACKET ;
return ;
}
i = 0 ;
while ( i < len ) {
/* Read header if not already be present from prev bulk pkt */
if ( sd - > packet_read < 4 ) {
count = 4 - sd - > packet_read ;
if ( count > len - i )
count = len - i ;
memcpy ( & sd - > packet [ sd - > packet_read ] , & data [ i ] , count ) ;
sd - > packet_read + = count ;
i + = count ;
if ( sd - > packet_read < 4 )
break ;
}
bits = sd - > packet [ 3 ] + ( sd - > packet [ 2 ] < < 8 ) ;
pixels = sd - > packet [ 1 ] + ( ( sd - > packet [ 0 ] & 0x3f ) < < 8 ) ;
info = ( sd - > packet [ 0 ] & 0xc0 ) > > 6 ;
plen = ( ( bits + 47 ) > > 4 ) < < 1 ;
/* Sanity checks */
if ( plen > 1024 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " invalid packet len %d restarting stream \n " ,
plen ) ;
2011-06-05 07:44:34 -03:00
goto error ;
}
if ( info = = 3 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " unknown frame info value restarting stream \n " ) ;
2011-06-05 07:44:34 -03:00
goto error ;
}
/* Read (remainder of) packet contents */
count = plen - sd - > packet_read ;
if ( count > len - i )
count = len - i ;
memcpy ( & sd - > packet [ sd - > packet_read ] , & data [ i ] , count ) ;
sd - > packet_read + = count ;
i + = count ;
if ( sd - > packet_read < plen )
break ;
sd - > pixels_read + = pixels ;
sd - > packet_read = 0 ;
switch ( info ) {
case 0 : /* Frame data */
gspca_frame_add ( gspca_dev , INTER_PACKET , sd - > packet ,
plen ) ;
break ;
case 1 : /* EOF */
if ( sd - > pixels_read ! = imagesize ) {
2011-08-21 19:56:57 -03:00
pr_err ( " frame size %d expected %d \n " ,
sd - > pixels_read , imagesize ) ;
2011-06-05 07:44:34 -03:00
goto error ;
}
sd_complete_frame ( gspca_dev , sd - > packet , plen ) ;
return ; /* Discard the rest of the bulk packet !! */
case 2 : /* SOF */
gspca_frame_add ( gspca_dev , FIRST_PACKET , sd - > packet ,
plen ) ;
sd - > pixels_read = pixels ;
break ;
}
}
return ;
error :
sd - > restart_stream = 1 ;
/* Give userspace a 0 bytes frame, so our dq callback gets
called and it can restart the stream */
gspca_frame_add ( gspca_dev , FIRST_PACKET , NULL , 0 ) ;
gspca_frame_add ( gspca_dev , LAST_PACKET , NULL , 0 ) ;
}
static void sd_pkt_scan_bayer ( struct gspca_dev * gspca_dev , u8 * data , int len )
{
struct cam * cam = & gspca_dev - > cam ;
int imagesize = cam - > cam_mode [ gspca_dev - > curr_mode ] . sizeimage ;
if ( gspca_dev - > image_len = = 0 ) {
gspca_frame_add ( gspca_dev , FIRST_PACKET , data , len ) ;
return ;
}
if ( gspca_dev - > image_len + len > = imagesize ) {
sd_complete_frame ( gspca_dev , data , len ) ;
return ;
}
gspca_frame_add ( gspca_dev , INTER_PACKET , data , len ) ;
}
static void sd_pkt_scan ( struct gspca_dev * gspca_dev , u8 * data , int len )
{
int mult = gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . priv ;
if ( len = = 0 )
return ;
if ( mult = = 1 ) /* mult == 1 means raw bayer */
sd_pkt_scan_bayer ( gspca_dev , data , len ) ;
else
sd_pkt_scan_janggu ( gspca_dev , data , len ) ;
}
2013-01-24 19:29:05 -03:00
# if IS_ENABLED(CONFIG_INPUT)
2011-06-05 07:44:34 -03:00
static int sd_int_pkt_scan ( struct gspca_dev * gspca_dev , u8 * data , int len )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
u8 state ;
if ( len ! = 2 )
return - EINVAL ;
switch ( data [ 0 ] ) {
case 0 :
case 1 :
state = data [ 0 ] ;
break ;
default :
return - EINVAL ;
}
if ( sd - > button_state ! = state ) {
input_report_key ( gspca_dev - > input_dev , KEY_CAMERA , state ) ;
input_sync ( gspca_dev - > input_dev ) ;
sd - > button_state = state ;
}
return 0 ;
}
# endif
2012-05-16 07:14:14 -03:00
static int sd_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct gspca_dev * gspca_dev =
container_of ( ctrl - > handler , struct gspca_dev , ctrl_handler ) ;
struct sd * sd = ( struct sd * ) gspca_dev ;
gspca_dev - > usb_err = 0 ;
if ( ! gspca_dev - > streaming )
return 0 ;
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
setbrightness ( gspca_dev , ctrl - > val ) ;
break ;
case V4L2_CID_GAIN :
setgain ( gspca_dev , ctrl - > val ) ;
break ;
case V4L2_CID_EXPOSURE :
setexposure ( gspca_dev , ctrl - > val , sd - > freq - > val ) ;
break ;
}
return gspca_dev - > usb_err ;
}
static const struct v4l2_ctrl_ops sd_ctrl_ops = {
. s_ctrl = sd_s_ctrl ,
} ;
static int sd_init_controls ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
struct v4l2_ctrl_handler * hdl = & gspca_dev - > ctrl_handler ;
gspca_dev - > vdev . ctrl_handler = hdl ;
v4l2_ctrl_handler_init ( hdl , 4 ) ;
if ( sd - > has_brightness )
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_BRIGHTNESS , 0 , 255 , 1 , 15 ) ;
/* max is really 63 but > 50 is not pretty */
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_GAIN , 0 , 50 , 1 , 25 ) ;
sd - > exposure = v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_EXPOSURE , 0 , 32767 , 1 , 15000 ) ;
sd - > freq = v4l2_ctrl_new_std_menu ( hdl , & sd_ctrl_ops ,
V4L2_CID_POWER_LINE_FREQUENCY ,
V4L2_CID_POWER_LINE_FREQUENCY_60HZ , 0 , 0 ) ;
if ( hdl - > error ) {
pr_err ( " Could not initialize controls \n " ) ;
return hdl - > error ;
}
v4l2_ctrl_cluster ( 2 , & sd - > exposure ) ;
return 0 ;
}
2011-06-05 07:44:34 -03:00
/* sub-driver description */
static const struct sd_desc sd_desc = {
. name = MODULE_NAME ,
. config = sd_config ,
. init = sd_init ,
2012-05-16 07:14:14 -03:00
. init_controls = sd_init_controls ,
2011-11-30 05:54:16 -03:00
. isoc_init = sd_isoc_init ,
2011-06-05 07:44:34 -03:00
. start = sd_start ,
. stopN = sd_stopN ,
. dq_callback = sd_dq_callback ,
. pkt_scan = sd_pkt_scan ,
2013-01-24 19:29:05 -03:00
# if IS_ENABLED(CONFIG_INPUT)
2011-06-05 07:44:34 -03:00
. int_pkt_scan = sd_int_pkt_scan ,
# endif
} ;
/* -- module initialisation -- */
static const struct usb_device_id device_table [ ] = {
{ USB_DEVICE ( 0x03e8 , 0x0004 ) } , /* Endpoints/Aox SE401 */
{ USB_DEVICE ( 0x0471 , 0x030b ) } , /* Philips PCVC665K */
{ USB_DEVICE ( 0x047d , 0x5001 ) } , /* Kensington 67014 */
{ USB_DEVICE ( 0x047d , 0x5002 ) } , /* Kensington 6701(5/7) */
{ USB_DEVICE ( 0x047d , 0x5003 ) } , /* Kensington 67016 */
{ }
} ;
MODULE_DEVICE_TABLE ( usb , device_table ) ;
/* -- device connect -- */
static int sd_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
return gspca_dev_probe ( intf , id , & sd_desc , sizeof ( struct sd ) ,
THIS_MODULE ) ;
}
static int sd_pre_reset ( struct usb_interface * intf )
{
return 0 ;
}
static int sd_post_reset ( struct usb_interface * intf )
{
return 0 ;
}
static struct usb_driver sd_driver = {
. name = MODULE_NAME ,
. id_table = device_table ,
. probe = sd_probe ,
. disconnect = gspca_disconnect ,
# ifdef CONFIG_PM
. suspend = gspca_suspend ,
. resume = gspca_resume ,
2012-06-30 06:44:47 -03:00
. reset_resume = gspca_resume ,
2011-06-05 07:44:34 -03:00
# endif
. pre_reset = sd_pre_reset ,
. post_reset = sd_post_reset ,
} ;
2011-11-18 09:46:12 -08:00
module_usb_driver ( sd_driver ) ;