2011-02-21 11:06:29 -03:00
/*
* gspca ViCam subdriver
*
* Copyright ( C ) 2011 Hans de Goede < hdegoede @ redhat . com >
*
* Based on the usbvideo vicam driver , which is :
*
* Copyright ( c ) 2002 Joe Burks ( jburks @ wavicle . org ) ,
2013-08-04 22:37:42 -05:00
* Chris Cheney ( chris . cheney @ gmail . com ) ,
2011-02-21 11:06:29 -03:00
* Pavel Machek ( pavel @ ucw . cz ) ,
* John Tyner ( jtyner @ cs . ucr . edu ) ,
* Monroe Williams ( monroe @ pobox . com )
*
* 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
* 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
*/
2011-08-21 19:56:57 -03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2011-02-21 11:06:29 -03:00
# define MODULE_NAME "vicam"
# define HEADER_SIZE 64
# include <linux/workqueue.h>
# include <linux/slab.h>
# include <linux/firmware.h>
# include <linux/ihex.h>
# include "gspca.h"
2012-04-12 17:23:21 -03:00
# define VICAM_FIRMWARE "vicam / firmware.fw"
2011-02-21 11:06:29 -03:00
MODULE_AUTHOR ( " Hans de Goede <hdegoede@redhat.com> " ) ;
MODULE_DESCRIPTION ( " GSPCA ViCam USB Camera Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-04-12 17:23:21 -03:00
MODULE_FIRMWARE ( VICAM_FIRMWARE ) ;
2011-02-21 11:06:29 -03:00
struct sd {
struct gspca_dev gspca_dev ; /* !! must be the first item */
struct work_struct work_struct ;
struct workqueue_struct * work_thread ;
} ;
/* The vicam sensor has a resolution of 512 x 244, with I believe square
pixels , but this is forced to a 4 : 3 ratio by optics . So it has
non square pixels : ( */
static struct v4l2_pix_format vicam_mode [ ] = {
{ 256 , 122 , V4L2_PIX_FMT_SGRBG8 , V4L2_FIELD_NONE ,
. bytesperline = 256 ,
. sizeimage = 256 * 122 ,
. colorspace = V4L2_COLORSPACE_SRGB , } ,
/* 2 modes with somewhat more square pixels */
{ 256 , 200 , V4L2_PIX_FMT_SGRBG8 , V4L2_FIELD_NONE ,
. bytesperline = 256 ,
. sizeimage = 256 * 200 ,
. colorspace = V4L2_COLORSPACE_SRGB , } ,
{ 256 , 240 , V4L2_PIX_FMT_SGRBG8 , V4L2_FIELD_NONE ,
. bytesperline = 256 ,
. sizeimage = 256 * 240 ,
. colorspace = V4L2_COLORSPACE_SRGB , } ,
#if 0 /* This mode has extremely non square pixels, testing use only */
{ 512 , 122 , V4L2_PIX_FMT_SGRBG8 , V4L2_FIELD_NONE ,
. bytesperline = 512 ,
. sizeimage = 512 * 122 ,
. colorspace = V4L2_COLORSPACE_SRGB , } ,
# endif
{ 512 , 244 , V4L2_PIX_FMT_SGRBG8 , V4L2_FIELD_NONE ,
. bytesperline = 512 ,
. sizeimage = 512 * 244 ,
. colorspace = V4L2_COLORSPACE_SRGB , } ,
} ;
static int vicam_control_msg ( struct gspca_dev * gspca_dev , u8 request ,
u16 value , u16 index , u8 * data , u16 len )
{
int ret ;
ret = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) ,
request ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
value , index , data , len , 1000 ) ;
if ( ret < 0 )
2011-08-21 19:56:57 -03:00
pr_err ( " control msg req %02X error %d \n " , request , ret ) ;
2011-02-21 11:06:29 -03:00
return ret ;
}
static int vicam_set_camera_power ( struct gspca_dev * gspca_dev , int state )
{
int ret ;
ret = vicam_control_msg ( gspca_dev , 0x50 , state , 0 , NULL , 0 ) ;
if ( ret < 0 )
return ret ;
if ( state )
ret = vicam_control_msg ( gspca_dev , 0x55 , 1 , 0 , NULL , 0 ) ;
return ret ;
}
/*
2012-09-09 07:30:02 -03:00
* request and read a block of data
2011-02-21 11:06:29 -03:00
*/
static int vicam_read_frame ( struct gspca_dev * gspca_dev , u8 * data , int size )
{
int ret , unscaled_height , act_len = 0 ;
u8 * req_data = gspca_dev - > usb_buf ;
2012-05-18 05:22:38 -03:00
s32 expo = v4l2_ctrl_g_ctrl ( gspca_dev - > exposure ) ;
s32 gain = v4l2_ctrl_g_ctrl ( gspca_dev - > gain ) ;
2011-02-21 11:06:29 -03:00
memset ( req_data , 0 , 16 ) ;
2012-05-18 05:22:38 -03:00
req_data [ 0 ] = gain ;
2013-08-30 17:54:23 -03:00
if ( gspca_dev - > pixfmt . width = = 256 )
2011-02-21 11:06:29 -03:00
req_data [ 1 ] | = 0x01 ; /* low nibble x-scale */
2013-08-30 17:54:23 -03:00
if ( gspca_dev - > pixfmt . height < = 122 ) {
2011-02-21 11:06:29 -03:00
req_data [ 1 ] | = 0x10 ; /* high nibble y-scale */
2013-08-30 17:54:23 -03:00
unscaled_height = gspca_dev - > pixfmt . height * 2 ;
2011-02-21 11:06:29 -03:00
} else
2013-08-30 17:54:23 -03:00
unscaled_height = gspca_dev - > pixfmt . height ;
2011-02-21 11:06:29 -03:00
req_data [ 2 ] = 0x90 ; /* unknown, does not seem to do anything */
if ( unscaled_height < = 200 )
req_data [ 3 ] = 0x06 ; /* vend? */
else if ( unscaled_height < = 242 ) /* Yes 242 not 240 */
req_data [ 3 ] = 0x07 ; /* vend? */
else /* Up to 244 lines with req_data[3] == 0x08 */
req_data [ 3 ] = 0x08 ; /* vend? */
2012-05-18 05:22:38 -03:00
if ( expo < 256 ) {
2011-02-21 11:06:29 -03:00
/* Frame rate maxed out, use partial frame expo time */
2012-05-18 05:22:38 -03:00
req_data [ 4 ] = 255 - expo ;
2011-02-21 11:06:29 -03:00
req_data [ 5 ] = 0x00 ;
req_data [ 6 ] = 0x00 ;
req_data [ 7 ] = 0x01 ;
} else {
/* Modify frame rate */
req_data [ 4 ] = 0x00 ;
req_data [ 5 ] = 0x00 ;
2012-05-18 05:22:38 -03:00
req_data [ 6 ] = expo & 0xFF ;
req_data [ 7 ] = expo > > 8 ;
2011-02-21 11:06:29 -03:00
}
req_data [ 8 ] = ( ( 244 - unscaled_height ) / 2 ) & ~ 0x01 ; /* vstart */
/* bytes 9-15 do not seem to affect exposure or image quality */
mutex_lock ( & gspca_dev - > usb_lock ) ;
ret = vicam_control_msg ( gspca_dev , 0x51 , 0x80 , 0 , req_data , 16 ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
if ( ret < 0 )
return ret ;
ret = usb_bulk_msg ( gspca_dev - > dev ,
usb_rcvbulkpipe ( gspca_dev - > dev , 0x81 ) ,
data , size , & act_len , 10000 ) ;
/* successful, it returns 0, otherwise negative */
if ( ret < 0 | | act_len ! = size ) {
2011-08-21 19:56:57 -03:00
pr_err ( " bulk read fail (%d) len %d/%d \n " ,
ret , act_len , size ) ;
2011-02-21 11:06:29 -03:00
return - EIO ;
}
return 0 ;
}
2012-09-09 07:30:02 -03:00
/*
* This function is called as a workqueue function and runs whenever the camera
2011-02-21 11:06:29 -03:00
* is streaming data . Because it is a workqueue function it is allowed to sleep
* so we can use synchronous USB calls . To avoid possible collisions with other
2012-09-09 07:30:02 -03:00
* threads attempting to use gspca_dev - > usb_buf we take the usb_lock when
* performing USB operations using it . In practice we don ' t really need this
* as the cameras controls are only written from the workqueue .
2011-02-21 11:06:29 -03:00
*/
static void vicam_dostream ( struct work_struct * work )
{
struct sd * sd = container_of ( work , struct sd , work_struct ) ;
struct gspca_dev * gspca_dev = & sd - > gspca_dev ;
int ret , frame_sz ;
u8 * buffer ;
frame_sz = gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . sizeimage +
HEADER_SIZE ;
buffer = kmalloc ( frame_sz , GFP_KERNEL | GFP_DMA ) ;
if ( ! buffer ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Couldn't allocate USB buffer \n " ) ;
2011-02-21 11:06:29 -03:00
goto exit ;
}
[media] gspca: Don't set gspca_dev->dev to NULL before stop0
In commit a3d6e8cc0e6ddc8b3cfdeb3c979f07ed1aa528b3 gspca_dev->dev is set
to NULL on disconnect, before calling stop0. The plan was to get rid of
gspca_dev->present and instead simply check for gspca_dev->dev everywhere
where we were checking for present. This should be race free since all users
of gspca_dev->dev hold the usb_lock, or so I thought.
But I was wrong, drivers which use a work-queue + synchronous bulk transfers
to get the video data don't hold the usb_lock while doing so, their stop0
callbacks stop the workqueue, so they won't be using gspca_dev->dev anymore
after the stop0 call, but they might be dereferincing it before, so we should
not set gspca_dev->dev to NULL on disconnect before calling stop0.
This also means that the workqueue functions in these drivers cannot
use gspca_dev->dev to check if they need to stop because of disconnection,
so we will need to keep gspca_dev->present around, and set that to 0 on
disconnect, before calling stop0. Unfortunately as part of the plan to remove
gspca_dev->present, these workqueues where already moved over to checking
for gspca_dev->dev instead of gspca_dev->present as part of commit
254902b01d2acc6aced99ec17caa4c6cd890cdea, so this patch also reverts those
parts of that commit.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2012-09-09 06:30:02 -03:00
while ( gspca_dev - > present & & gspca_dev - > streaming ) {
2012-05-18 08:40:42 -03:00
# ifdef CONFIG_PM
if ( gspca_dev - > frozen )
break ;
# endif
2011-02-21 11:06:29 -03:00
ret = vicam_read_frame ( gspca_dev , buffer , frame_sz ) ;
if ( ret < 0 )
break ;
/* Note the frame header contents seem to be completely
constant , they do not change with either image , or
settings . So we simply discard it . The frames have
a very similar 64 byte footer , which we don ' t even
bother reading from the cam */
gspca_frame_add ( gspca_dev , FIRST_PACKET ,
buffer + HEADER_SIZE ,
frame_sz - HEADER_SIZE ) ;
gspca_frame_add ( gspca_dev , LAST_PACKET , NULL , 0 ) ;
}
exit :
kfree ( buffer ) ;
}
/* This function is called at probe time just before sd_init */
static int sd_config ( struct gspca_dev * gspca_dev ,
const struct usb_device_id * id )
{
struct cam * cam = & gspca_dev - > cam ;
struct sd * sd = ( struct sd * ) gspca_dev ;
/* We don't use the buffer gspca allocates so make it small. */
cam - > bulk = 1 ;
cam - > bulk_size = 64 ;
cam - > cam_mode = vicam_mode ;
cam - > nmodes = ARRAY_SIZE ( vicam_mode ) ;
INIT_WORK ( & sd - > work_struct , vicam_dostream ) ;
return 0 ;
}
/* this function is called at probe and resume time */
static int sd_init ( struct gspca_dev * gspca_dev )
{
int ret ;
const struct ihex_binrec * rec ;
const struct firmware * uninitialized_var ( fw ) ;
u8 * firmware_buf ;
2012-04-12 17:23:21 -03:00
ret = request_ihex_firmware ( & fw , VICAM_FIRMWARE ,
2011-02-21 11:06:29 -03:00
& gspca_dev - > dev - > dev ) ;
if ( ret ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Failed to load \" vicam/firmware.fw \" : %d \n " , ret ) ;
2011-02-21 11:06:29 -03:00
return ret ;
}
firmware_buf = kmalloc ( PAGE_SIZE , GFP_KERNEL ) ;
if ( ! firmware_buf ) {
ret = - ENOMEM ;
goto exit ;
}
for ( rec = ( void * ) fw - > data ; rec ; rec = ihex_next_binrec ( rec ) ) {
memcpy ( firmware_buf , rec - > data , be16_to_cpu ( rec - > len ) ) ;
ret = vicam_control_msg ( gspca_dev , 0xff , 0 , 0 , firmware_buf ,
be16_to_cpu ( rec - > len ) ) ;
if ( ret < 0 )
break ;
}
kfree ( firmware_buf ) ;
exit :
release_firmware ( fw ) ;
return ret ;
}
/* Set up for getting frames. */
static int sd_start ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int ret ;
ret = vicam_set_camera_power ( gspca_dev , 1 ) ;
if ( ret < 0 )
return ret ;
/* Start the workqueue function to do the streaming */
sd - > work_thread = create_singlethread_workqueue ( MODULE_NAME ) ;
queue_work ( sd - > work_thread , & sd - > work_struct ) ;
return 0 ;
}
/* called on streamoff with alt==0 and on disconnect */
/* the usb_lock is held at entry - restore on exit */
static void sd_stop0 ( struct gspca_dev * gspca_dev )
{
struct sd * dev = ( struct sd * ) gspca_dev ;
/* wait for the work queue to terminate */
mutex_unlock ( & gspca_dev - > usb_lock ) ;
/* This waits for vicam_dostream to finish */
destroy_workqueue ( dev - > work_thread ) ;
dev - > work_thread = NULL ;
mutex_lock ( & gspca_dev - > usb_lock ) ;
[media] gspca: Don't set gspca_dev->dev to NULL before stop0
In commit a3d6e8cc0e6ddc8b3cfdeb3c979f07ed1aa528b3 gspca_dev->dev is set
to NULL on disconnect, before calling stop0. The plan was to get rid of
gspca_dev->present and instead simply check for gspca_dev->dev everywhere
where we were checking for present. This should be race free since all users
of gspca_dev->dev hold the usb_lock, or so I thought.
But I was wrong, drivers which use a work-queue + synchronous bulk transfers
to get the video data don't hold the usb_lock while doing so, their stop0
callbacks stop the workqueue, so they won't be using gspca_dev->dev anymore
after the stop0 call, but they might be dereferincing it before, so we should
not set gspca_dev->dev to NULL on disconnect before calling stop0.
This also means that the workqueue functions in these drivers cannot
use gspca_dev->dev to check if they need to stop because of disconnection,
so we will need to keep gspca_dev->present around, and set that to 0 on
disconnect, before calling stop0. Unfortunately as part of the plan to remove
gspca_dev->present, these workqueues where already moved over to checking
for gspca_dev->dev instead of gspca_dev->present as part of commit
254902b01d2acc6aced99ec17caa4c6cd890cdea, so this patch also reverts those
parts of that commit.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2012-09-09 06:30:02 -03:00
if ( gspca_dev - > present )
2011-12-29 16:50:57 -03:00
vicam_set_camera_power ( gspca_dev , 0 ) ;
2011-02-21 11:06:29 -03:00
}
2012-05-18 05:22:38 -03:00
static int sd_init_controls ( struct gspca_dev * gspca_dev )
{
struct v4l2_ctrl_handler * hdl = & gspca_dev - > ctrl_handler ;
gspca_dev - > vdev . ctrl_handler = hdl ;
v4l2_ctrl_handler_init ( hdl , 2 ) ;
gspca_dev - > exposure = v4l2_ctrl_new_std ( hdl , NULL ,
V4L2_CID_EXPOSURE , 0 , 2047 , 1 , 256 ) ;
gspca_dev - > gain = v4l2_ctrl_new_std ( hdl , NULL ,
V4L2_CID_GAIN , 0 , 255 , 1 , 200 ) ;
if ( hdl - > error ) {
pr_err ( " Could not initialize controls \n " ) ;
return hdl - > error ;
}
return 0 ;
}
2011-02-21 11:06:29 -03:00
/* Table of supported USB devices */
static const struct usb_device_id device_table [ ] = {
{ USB_DEVICE ( 0x04c1 , 0x009d ) } ,
{ USB_DEVICE ( 0x0602 , 0x1001 ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( usb , device_table ) ;
/* sub-driver description */
static const struct sd_desc sd_desc = {
. name = MODULE_NAME ,
. config = sd_config ,
. init = sd_init ,
2012-05-18 05:22:38 -03:00
. init_controls = sd_init_controls ,
2011-02-21 11:06:29 -03:00
. start = sd_start ,
. stop0 = sd_stop0 ,
} ;
/* -- 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 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-02-21 11:06:29 -03:00
# endif
} ;
2011-11-18 09:46:12 -08:00
module_usb_driver ( sd_driver ) ;