2008-04-12 09:58:09 -03:00
/*
* Main USB camera driver
*
* V4L2 by Jean - Francois Moine < http : //moinejf.free.fr>
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# define MODULE_NAME "gspca"
# include <linux/init.h>
# include <linux/fs.h>
# include <linux/vmalloc.h>
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/string.h>
# include <linux/pagemap.h>
2008-07-01 10:03:42 -03:00
# include <linux/io.h>
2008-04-12 09:58:09 -03:00
# include <asm/page.h>
2008-07-01 10:03:42 -03:00
# include <linux/uaccess.h>
2008-04-12 09:58:09 -03:00
# include <linux/jiffies.h>
# include "gspca.h"
2008-06-12 10:58:58 -03:00
/* global values */
2008-07-08 06:58:15 -03:00
# define DEF_NURBS 2 /* default number of URBs */
2008-06-12 10:58:58 -03:00
2008-04-12 09:58:09 -03:00
MODULE_AUTHOR ( " Jean-Francois Moine <http://moinejf.free.fr> " ) ;
MODULE_DESCRIPTION ( " GSPCA USB Camera Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-07-12 09:28:04 -03:00
# define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
static const char version [ ] = " 2.1.7 " ;
2008-04-12 09:58:09 -03:00
static int video_nr = - 1 ;
2008-07-03 06:48:22 -03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2008-04-12 09:58:09 -03:00
int gspca_debug = D_ERR | D_PROBE ;
EXPORT_SYMBOL ( gspca_debug ) ;
static void PDEBUG_MODE ( char * txt , __u32 pixfmt , int w , int h )
{
if ( ( pixfmt > > 24 ) > = ' 0 ' & & ( pixfmt > > 24 ) < = ' z ' ) {
PDEBUG ( D_CONF | D_STREAM , " %s %c%c%c%c %dx%d " ,
txt ,
pixfmt & 0xff ,
( pixfmt > > 8 ) & 0xff ,
( pixfmt > > 16 ) & 0xff ,
pixfmt > > 24 ,
w , h ) ;
} else {
PDEBUG ( D_CONF | D_STREAM , " %s 0x%08x %dx%d " ,
txt ,
pixfmt ,
w , h ) ;
}
}
# else
# define PDEBUG_MODE(txt, pixfmt, w, h)
# endif
2008-06-12 10:58:58 -03:00
/* specific memory types - !! should different from V4L2_MEMORY_xxx */
# define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */
# define GSPCA_MEMORY_READ 7
# define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
2008-04-12 09:58:09 -03:00
/*
* VMA operations .
*/
static void gspca_vm_open ( struct vm_area_struct * vma )
{
struct gspca_frame * frame = vma - > vm_private_data ;
frame - > vma_use_count + + ;
frame - > v4l2_buf . flags | = V4L2_BUF_FLAG_MAPPED ;
}
static void gspca_vm_close ( struct vm_area_struct * vma )
{
struct gspca_frame * frame = vma - > vm_private_data ;
if ( - - frame - > vma_use_count < = 0 )
frame - > v4l2_buf . flags & = ~ V4L2_BUF_FLAG_MAPPED ;
}
static struct vm_operations_struct gspca_vm_ops = {
. open = gspca_vm_open ,
. close = gspca_vm_close ,
} ;
/*
2008-06-12 10:58:58 -03:00
* fill a video frame from an URB and resubmit
2008-04-12 09:58:09 -03:00
*/
2008-06-12 10:58:58 -03:00
static void fill_frame ( struct gspca_dev * gspca_dev ,
struct urb * urb )
2008-04-12 09:58:09 -03:00
{
struct gspca_frame * frame ;
2008-06-30 15:50:11 -03:00
__u8 * data ; /* address of data in the iso message */
2008-04-12 09:58:09 -03:00
int i , j , len , st ;
cam_pkt_op pkt_scan ;
2008-06-30 15:50:11 -03:00
if ( urb - > status ! = 0 ) {
PDEBUG ( D_ERR | D_PACK , " urb status: %d " , urb - > status ) ;
return ; /* disconnection ? */
}
2008-04-12 09:58:09 -03:00
pkt_scan = gspca_dev - > sd_desc - > pkt_scan ;
for ( i = 0 ; i < urb - > number_of_packets ; i + + ) {
/* check the availability of the frame buffer */
j = gspca_dev - > fr_i ;
j = gspca_dev - > fr_queue [ j ] ;
frame = & gspca_dev - > frame [ j ] ;
2008-06-12 10:58:58 -03:00
if ( ( frame - > v4l2_buf . flags & BUF_ALL_FLAGS )
2008-04-12 09:58:09 -03:00
! = V4L2_BUF_FLAG_QUEUED ) {
gspca_dev - > last_packet_type = DISCARD_PACKET ;
break ;
}
/* check the packet status and length */
len = urb - > iso_frame_desc [ i ] . actual_length ;
2008-06-30 15:50:11 -03:00
if ( len = = 0 )
continue ;
2008-04-12 09:58:09 -03:00
st = urb - > iso_frame_desc [ i ] . status ;
if ( st ) {
2008-06-30 15:50:11 -03:00
PDEBUG ( D_ERR ,
" ISOC data error: [%d] len=%d, status=%d " ,
2008-04-12 09:58:09 -03:00
i , len , st ) ;
gspca_dev - > last_packet_type = DISCARD_PACKET ;
continue ;
}
/* let the packet be analyzed by the subdriver */
PDEBUG ( D_PACK , " packet [%d] o:%d l:%d " ,
i , urb - > iso_frame_desc [ i ] . offset , len ) ;
2008-06-30 15:50:11 -03:00
data = ( __u8 * ) urb - > transfer_buffer
2008-04-12 09:58:09 -03:00
+ urb - > iso_frame_desc [ i ] . offset ;
pkt_scan ( gspca_dev , frame , data , len ) ;
}
/* resubmit the URB */
urb - > status = 0 ;
st = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( st < 0 )
PDEBUG ( D_ERR | D_PACK , " usb_submit_urb() ret %d " , st ) ;
}
2008-06-12 10:58:58 -03:00
/*
* ISOC message interrupt from the USB device
*
2008-07-08 06:58:15 -03:00
* Analyse each packet and call the subdriver for copy to the frame buffer .
2008-06-12 10:58:58 -03:00
*/
2008-07-08 06:58:15 -03:00
static void isoc_irq ( struct urb * urb
2008-06-30 15:50:11 -03:00
)
2008-06-12 10:58:58 -03:00
{
struct gspca_dev * gspca_dev = ( struct gspca_dev * ) urb - > context ;
2008-07-15 05:36:30 -03:00
PDEBUG ( D_PACK , " isoc irq " ) ;
2008-06-12 10:58:58 -03:00
if ( ! gspca_dev - > streaming )
return ;
fill_frame ( gspca_dev , urb ) ;
}
2008-04-12 09:58:09 -03:00
/*
* add data to the current frame
*
2008-07-08 06:58:15 -03:00
* This function is called by the subdrivers at interrupt level .
*
2008-04-12 09:58:09 -03:00
* To build a frame , these ones must add
* - one FIRST_PACKET
* - 0 or many INTER_PACKETs
* - one LAST_PACKET
* DISCARD_PACKET invalidates the whole frame .
* On LAST_PACKET , a new frame is returned .
*/
struct gspca_frame * gspca_frame_add ( struct gspca_dev * gspca_dev ,
int packet_type ,
struct gspca_frame * frame ,
2008-07-04 11:16:16 -03:00
const __u8 * data ,
2008-04-12 09:58:09 -03:00
int len )
{
int i , j ;
2008-04-23 08:09:12 -03:00
PDEBUG ( D_PACK , " add t:%d l:%d " , packet_type , len ) ;
2008-04-12 09:58:09 -03:00
/* when start of a new frame, if the current frame buffer
* is not queued , discard the whole frame */
if ( packet_type = = FIRST_PACKET ) {
2008-06-12 10:58:58 -03:00
if ( ( frame - > v4l2_buf . flags & BUF_ALL_FLAGS )
! = V4L2_BUF_FLAG_QUEUED ) {
2008-04-12 09:58:09 -03:00
gspca_dev - > last_packet_type = DISCARD_PACKET ;
return frame ;
}
frame - > data_end = frame - > data ;
jiffies_to_timeval ( get_jiffies_64 ( ) ,
& frame - > v4l2_buf . timestamp ) ;
frame - > v4l2_buf . sequence = + + gspca_dev - > sequence ;
2008-06-12 10:58:58 -03:00
} else if ( gspca_dev - > last_packet_type = = DISCARD_PACKET ) {
2008-04-12 09:58:09 -03:00
return frame ;
2008-06-12 10:58:58 -03:00
}
2008-04-12 09:58:09 -03:00
2008-06-12 10:58:58 -03:00
/* append the packet to the frame buffer */
2008-04-12 09:58:09 -03:00
if ( len > 0 ) {
if ( frame - > data_end - frame - > data + len
> frame - > v4l2_buf . length ) {
2008-07-09 05:26:26 -03:00
PDEBUG ( D_ERR | D_PACK , " frame overflow %zd > %d " ,
2008-04-12 09:58:09 -03:00
frame - > data_end - frame - > data + len ,
frame - > v4l2_buf . length ) ;
packet_type = DISCARD_PACKET ;
} else {
2008-07-08 06:58:15 -03:00
memcpy ( frame - > data_end , data , len ) ;
2008-04-12 09:58:09 -03:00
frame - > data_end + = len ;
}
}
gspca_dev - > last_packet_type = packet_type ;
/* if last packet, wake the application and advance in the queue */
if ( packet_type = = LAST_PACKET ) {
frame - > v4l2_buf . bytesused = frame - > data_end - frame - > data ;
frame - > v4l2_buf . flags & = ~ V4L2_BUF_FLAG_QUEUED ;
frame - > v4l2_buf . flags | = V4L2_BUF_FLAG_DONE ;
atomic_inc ( & gspca_dev - > nevent ) ;
wake_up_interruptible ( & gspca_dev - > wq ) ; /* event = new frame */
2008-06-12 10:58:58 -03:00
i = ( gspca_dev - > fr_i + 1 ) % gspca_dev - > nframes ;
gspca_dev - > fr_i = i ;
2008-04-12 09:58:09 -03:00
PDEBUG ( D_FRAM , " frame complete len:%d q:%d i:%d o:%d " ,
frame - > v4l2_buf . bytesused ,
gspca_dev - > fr_q ,
i ,
gspca_dev - > fr_o ) ;
j = gspca_dev - > fr_queue [ i ] ;
frame = & gspca_dev - > frame [ j ] ;
}
return frame ;
}
EXPORT_SYMBOL ( gspca_frame_add ) ;
static int gspca_is_compressed ( __u32 format )
{
switch ( format ) {
case V4L2_PIX_FMT_MJPEG :
case V4L2_PIX_FMT_JPEG :
2008-06-30 19:47:33 -03:00
case V4L2_PIX_FMT_SPCA561 :
2008-07-04 18:29:32 -03:00
case V4L2_PIX_FMT_PAC207 :
2008-04-12 09:58:09 -03:00
return 1 ;
}
return 0 ;
}
static void * rvmalloc ( unsigned long size )
{
void * mem ;
unsigned long adr ;
2008-06-12 10:58:58 -03:00
/* size = PAGE_ALIGN(size); (already done) */
2008-04-12 09:58:09 -03:00
mem = vmalloc_32 ( size ) ;
2008-07-05 06:12:47 -03:00
if ( mem ! = NULL ) {
2008-04-12 09:58:09 -03:00
adr = ( unsigned long ) mem ;
while ( ( long ) size > 0 ) {
SetPageReserved ( vmalloc_to_page ( ( void * ) adr ) ) ;
adr + = PAGE_SIZE ;
size - = PAGE_SIZE ;
}
}
return mem ;
}
2008-07-08 06:58:15 -03:00
static void rvfree ( void * mem , long size )
2008-04-12 09:58:09 -03:00
{
unsigned long adr ;
adr = ( unsigned long ) mem ;
2008-07-08 06:58:15 -03:00
while ( size > 0 ) {
2008-04-12 09:58:09 -03:00
ClearPageReserved ( vmalloc_to_page ( ( void * ) adr ) ) ;
adr + = PAGE_SIZE ;
size - = PAGE_SIZE ;
}
vfree ( mem ) ;
}
static int frame_alloc ( struct gspca_dev * gspca_dev ,
2008-06-12 10:58:58 -03:00
unsigned int count )
2008-04-12 09:58:09 -03:00
{
2008-06-12 10:58:58 -03:00
struct gspca_frame * frame ;
unsigned int frsz ;
int i ;
2008-04-12 09:58:09 -03:00
2008-07-05 11:49:20 -03:00
i = gspca_dev - > curr_mode ;
frsz = gspca_dev - > cam . cam_mode [ i ] . sizeimage ;
2008-04-12 09:58:09 -03:00
PDEBUG ( D_STREAM , " frame alloc frsz: %d " , frsz ) ;
frsz = PAGE_ALIGN ( frsz ) ;
gspca_dev - > frsz = frsz ;
2008-07-05 11:49:20 -03:00
if ( count > GSPCA_MAX_FRAMES )
count = GSPCA_MAX_FRAMES ;
2008-07-08 06:58:15 -03:00
gspca_dev - > frbuf = rvmalloc ( frsz * count ) ;
if ( ! gspca_dev - > frbuf ) {
err ( " frame alloc failed " ) ;
return - ENOMEM ;
2008-04-12 09:58:09 -03:00
}
gspca_dev - > nframes = count ;
for ( i = 0 ; i < count ; i + + ) {
2008-06-12 10:58:58 -03:00
frame = & gspca_dev - > frame [ i ] ;
frame - > v4l2_buf . index = i ;
frame - > v4l2_buf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
frame - > v4l2_buf . flags = 0 ;
frame - > v4l2_buf . field = V4L2_FIELD_NONE ;
frame - > v4l2_buf . length = frsz ;
frame - > v4l2_buf . memory = gspca_dev - > memory ;
frame - > v4l2_buf . sequence = 0 ;
2008-07-08 06:58:15 -03:00
frame - > data = frame - > data_end =
2008-06-12 10:58:58 -03:00
gspca_dev - > frbuf + i * frsz ;
2008-07-08 06:58:15 -03:00
frame - > v4l2_buf . m . offset = i * frsz ;
2008-04-12 09:58:09 -03:00
}
gspca_dev - > fr_i = gspca_dev - > fr_o = gspca_dev - > fr_q = 0 ;
gspca_dev - > last_packet_type = DISCARD_PACKET ;
gspca_dev - > sequence = 0 ;
atomic_set ( & gspca_dev - > nevent , 0 ) ;
2008-06-12 10:58:58 -03:00
return 0 ;
2008-04-12 09:58:09 -03:00
}
static void frame_free ( struct gspca_dev * gspca_dev )
{
int i ;
PDEBUG ( D_STREAM , " frame free " ) ;
2008-07-05 06:12:47 -03:00
if ( gspca_dev - > frbuf ! = NULL ) {
2008-04-12 09:58:09 -03:00
rvfree ( gspca_dev - > frbuf ,
gspca_dev - > nframes * gspca_dev - > frsz ) ;
gspca_dev - > frbuf = NULL ;
for ( i = 0 ; i < gspca_dev - > nframes ; i + + )
gspca_dev - > frame [ i ] . data = NULL ;
}
gspca_dev - > nframes = 0 ;
}
2008-06-12 10:58:58 -03:00
static void destroy_urbs ( struct gspca_dev * gspca_dev )
2008-04-12 09:58:09 -03:00
{
struct urb * urb ;
unsigned int i ;
PDEBUG ( D_STREAM , " kill transfer " ) ;
2008-06-12 10:58:58 -03:00
for ( i = 0 ; i < MAX_NURBS ; + + i ) {
2008-05-04 06:46:21 -03:00
urb = gspca_dev - > urb [ i ] ;
2008-04-12 09:58:09 -03:00
if ( urb = = NULL )
2008-06-12 10:58:58 -03:00
break ;
2008-04-12 09:58:09 -03:00
2008-05-04 06:46:21 -03:00
gspca_dev - > urb [ i ] = NULL ;
2008-04-12 09:58:09 -03:00
usb_kill_urb ( urb ) ;
2008-07-05 06:12:47 -03:00
if ( urb - > transfer_buffer ! = NULL )
2008-04-12 09:58:09 -03:00
usb_buffer_free ( gspca_dev - > dev ,
urb - > transfer_buffer_length ,
2008-05-04 06:46:21 -03:00
urb - > transfer_buffer ,
2008-04-12 09:58:09 -03:00
urb - > transfer_dma ) ;
usb_free_urb ( urb ) ;
}
}
/*
* search an input isochronous endpoint in an alternate setting
*/
static struct usb_host_endpoint * alt_isoc ( struct usb_host_interface * alt ,
__u8 epaddr )
{
struct usb_host_endpoint * ep ;
int i , attr ;
epaddr | = USB_DIR_IN ;
for ( i = 0 ; i < alt - > desc . bNumEndpoints ; i + + ) {
ep = & alt - > endpoint [ i ] ;
if ( ep - > desc . bEndpointAddress = = epaddr ) {
attr = ep - > desc . bmAttributes
& USB_ENDPOINT_XFERTYPE_MASK ;
if ( attr = = USB_ENDPOINT_XFER_ISOC )
return ep ;
break ;
}
}
return NULL ;
}
/*
* search an input isochronous endpoint
*
* The endpoint is defined by the subdriver .
* Use only the first isoc ( some Zoran - 0x0572 : 0x0001 - have two such ep ) .
* This routine may be called many times when the bandwidth is too small
* ( the bandwidth is checked on urb submit ) .
*/
struct usb_host_endpoint * get_isoc_ep ( struct gspca_dev * gspca_dev )
{
struct usb_interface * intf ;
struct usb_host_endpoint * ep ;
int i , ret ;
intf = usb_ifnum_to_if ( gspca_dev - > dev , gspca_dev - > iface ) ;
2008-06-30 15:50:11 -03:00
ep = NULL ;
2008-04-12 09:58:09 -03:00
i = gspca_dev - > alt ; /* previous alt setting */
while ( - - i > 0 ) { /* alt 0 is unusable */
ep = alt_isoc ( & intf - > altsetting [ i ] , gspca_dev - > cam . epaddr ) ;
if ( ep )
break ;
}
2008-06-30 15:50:11 -03:00
if ( ep = = NULL ) {
2008-04-12 09:58:09 -03:00
err ( " no ISOC endpoint found " ) ;
return NULL ;
}
PDEBUG ( D_STREAM , " use ISOC alt %d ep 0x%02x " ,
i , ep - > desc . bEndpointAddress ) ;
ret = usb_set_interface ( gspca_dev - > dev , gspca_dev - > iface , i ) ;
if ( ret < 0 ) {
err ( " set interface err %d " , ret ) ;
return NULL ;
}
2008-06-12 10:58:58 -03:00
gspca_dev - > alt = i ; /* memorize the current alt setting */
2008-04-12 09:58:09 -03:00
return ep ;
}
/*
* create the isochronous URBs
*/
static int create_urbs ( struct gspca_dev * gspca_dev ,
struct usb_host_endpoint * ep )
{
struct urb * urb ;
2008-06-12 10:58:58 -03:00
int n , nurbs , i , psize , npkt , bsize ;
2008-04-12 09:58:09 -03:00
/* calculate the packet size and the number of packets */
psize = le16_to_cpu ( ep - > desc . wMaxPacketSize ) ;
2008-06-12 10:58:58 -03:00
2008-04-12 09:58:09 -03:00
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
psize = ( psize & 0x07ff ) * ( 1 + ( ( psize > > 11 ) & 3 ) ) ;
npkt = ISO_MAX_SIZE / psize ;
if ( npkt > ISO_MAX_PKT )
npkt = ISO_MAX_PKT ;
bsize = psize * npkt ;
PDEBUG ( D_STREAM ,
" isoc %d pkts size %d (bsize:%d) " , npkt , psize , bsize ) ;
2008-07-08 06:58:15 -03:00
nurbs = DEF_NURBS ;
2008-06-30 15:50:11 -03:00
gspca_dev - > nurbs = nurbs ;
2008-06-12 10:58:58 -03:00
for ( n = 0 ; n < nurbs ; n + + ) {
2008-04-12 09:58:09 -03:00
urb = usb_alloc_urb ( npkt , GFP_KERNEL ) ;
if ( ! urb ) {
err ( " usb_alloc_urb failed " ) ;
return - ENOMEM ;
}
2008-05-04 06:46:21 -03:00
urb - > transfer_buffer = usb_buffer_alloc ( gspca_dev - > dev ,
2008-04-12 09:58:09 -03:00
bsize ,
GFP_KERNEL ,
& urb - > transfer_dma ) ;
2008-05-04 06:46:21 -03:00
if ( urb - > transfer_buffer = = NULL ) {
2008-04-12 09:58:09 -03:00
usb_free_urb ( urb ) ;
2008-06-12 10:58:58 -03:00
destroy_urbs ( gspca_dev ) ;
2008-04-12 09:58:09 -03:00
err ( " usb_buffer_urb failed " ) ;
return - ENOMEM ;
}
2008-05-04 06:46:21 -03:00
gspca_dev - > urb [ n ] = urb ;
2008-04-12 09:58:09 -03:00
urb - > dev = gspca_dev - > dev ;
urb - > context = gspca_dev ;
urb - > pipe = usb_rcvisocpipe ( gspca_dev - > dev ,
ep - > desc . bEndpointAddress ) ;
2008-05-04 06:46:21 -03:00
urb - > transfer_flags = URB_ISO_ASAP
| URB_NO_TRANSFER_DMA_MAP ;
2008-04-12 09:58:09 -03:00
urb - > interval = ep - > desc . bInterval ;
2008-07-08 06:58:15 -03:00
urb - > complete = isoc_irq ;
2008-04-12 09:58:09 -03:00
urb - > number_of_packets = npkt ;
urb - > transfer_buffer_length = bsize ;
for ( i = 0 ; i < npkt ; i + + ) {
urb - > iso_frame_desc [ i ] . length = psize ;
urb - > iso_frame_desc [ i ] . offset = psize * i ;
}
}
return 0 ;
}
/*
* start the USB transfer
*/
static int gspca_init_transfer ( struct gspca_dev * gspca_dev )
{
struct usb_host_endpoint * ep ;
int n , ret ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
2008-06-12 10:58:58 -03:00
/* set the higher alternate setting and
* loop until urb submit succeeds */
gspca_dev - > alt = gspca_dev - > nbalt ;
2008-04-12 09:58:09 -03:00
for ( ; ; ) {
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " init transfer alt %d " , gspca_dev - > alt ) ;
2008-04-12 09:58:09 -03:00
ep = get_isoc_ep ( gspca_dev ) ;
if ( ep = = NULL ) {
ret = - EIO ;
goto out ;
}
ret = create_urbs ( gspca_dev , ep ) ;
if ( ret < 0 )
goto out ;
/* start the cam */
gspca_dev - > sd_desc - > start ( gspca_dev ) ;
gspca_dev - > streaming = 1 ;
atomic_set ( & gspca_dev - > nevent , 0 ) ;
/* submit the URBs */
2008-06-12 10:58:58 -03:00
for ( n = 0 ; n < gspca_dev - > nurbs ; n + + ) {
2008-05-04 06:46:21 -03:00
ret = usb_submit_urb ( gspca_dev - > urb [ n ] , GFP_KERNEL ) ;
2008-04-12 09:58:09 -03:00
if ( ret < 0 ) {
PDEBUG ( D_ERR | D_STREAM ,
" usb_submit_urb [%d] err %d " , n , ret ) ;
2008-04-23 08:09:12 -03:00
gspca_dev - > streaming = 0 ;
2008-06-12 10:58:58 -03:00
destroy_urbs ( gspca_dev ) ;
2008-04-12 09:58:09 -03:00
if ( ret = = - ENOSPC )
break ; /* try the previous alt */
goto out ;
}
}
if ( ret > = 0 )
break ;
}
out :
mutex_unlock ( & gspca_dev - > usb_lock ) ;
return ret ;
}
static int gspca_set_alt0 ( struct gspca_dev * gspca_dev )
{
int ret ;
ret = usb_set_interface ( gspca_dev - > dev , gspca_dev - > iface , 0 ) ;
if ( ret < 0 )
PDEBUG ( D_ERR | D_STREAM , " set interface 0 err %d " , ret ) ;
return ret ;
}
2008-04-23 08:09:12 -03:00
/* Note both the queue and the usb lock should be hold when calling this */
2008-04-12 09:58:09 -03:00
static void gspca_stream_off ( struct gspca_dev * gspca_dev )
{
gspca_dev - > streaming = 0 ;
2008-06-12 10:58:58 -03:00
atomic_set ( & gspca_dev - > nevent , 0 ) ;
2008-04-12 09:58:09 -03:00
if ( gspca_dev - > present ) {
gspca_dev - > sd_desc - > stopN ( gspca_dev ) ;
2008-06-12 10:58:58 -03:00
destroy_urbs ( gspca_dev ) ;
2008-04-12 09:58:09 -03:00
gspca_set_alt0 ( gspca_dev ) ;
gspca_dev - > sd_desc - > stop0 ( gspca_dev ) ;
PDEBUG ( D_STREAM , " stream off OK " ) ;
}
}
2008-06-12 10:58:58 -03:00
static void gspca_set_default_mode ( struct gspca_dev * gspca_dev )
2008-04-12 09:58:09 -03:00
{
int i ;
i = gspca_dev - > cam . nmodes - 1 ; /* take the highest mode */
gspca_dev - > curr_mode = i ;
gspca_dev - > width = gspca_dev - > cam . cam_mode [ i ] . width ;
gspca_dev - > height = gspca_dev - > cam . cam_mode [ i ] . height ;
2008-07-05 11:49:20 -03:00
gspca_dev - > pixfmt = gspca_dev - > cam . cam_mode [ i ] . pixelformat ;
2008-04-12 09:58:09 -03:00
}
static int wxh_to_mode ( struct gspca_dev * gspca_dev ,
int width , int height )
{
int i ;
2008-06-12 10:58:58 -03:00
for ( i = gspca_dev - > cam . nmodes ; - - i > 0 ; ) {
if ( width > = gspca_dev - > cam . cam_mode [ i ] . width
& & height > = gspca_dev - > cam . cam_mode [ i ] . height )
2008-04-12 09:58:09 -03:00
break ;
}
return i ;
}
/*
* search a mode with the right pixel format
*/
static int gspca_get_mode ( struct gspca_dev * gspca_dev ,
int mode ,
int pixfmt )
{
int modeU , modeD ;
modeU = modeD = mode ;
while ( ( modeU < gspca_dev - > cam . nmodes ) | | modeD > = 0 ) {
if ( - - modeD > = 0 ) {
2008-07-05 11:49:20 -03:00
if ( gspca_dev - > cam . cam_mode [ modeD ] . pixelformat
= = pixfmt )
2008-04-12 09:58:09 -03:00
return modeD ;
}
if ( + + modeU < gspca_dev - > cam . nmodes ) {
2008-07-05 11:49:20 -03:00
if ( gspca_dev - > cam . cam_mode [ modeU ] . pixelformat
= = pixfmt )
2008-04-12 09:58:09 -03:00
return modeU ;
}
}
return - EINVAL ;
}
2008-07-01 04:06:22 -03:00
static int vidioc_enum_fmt_vid_cap ( struct file * file , void * priv ,
2008-04-12 09:58:09 -03:00
struct v4l2_fmtdesc * fmtdesc )
{
struct gspca_dev * gspca_dev = priv ;
2008-06-30 15:50:11 -03:00
int i , j , index ;
2008-04-12 09:58:09 -03:00
__u32 fmt_tb [ 8 ] ;
/* give an index to each format */
index = 0 ;
j = 0 ;
for ( i = gspca_dev - > cam . nmodes ; - - i > = 0 ; ) {
2008-07-05 11:49:20 -03:00
fmt_tb [ index ] = gspca_dev - > cam . cam_mode [ i ] . pixelformat ;
2008-04-12 09:58:09 -03:00
j = 0 ;
for ( ; ; ) {
if ( fmt_tb [ j ] = = fmt_tb [ index ] )
break ;
j + + ;
}
if ( j = = index ) {
if ( fmtdesc - > index = = index )
break ; /* new format */
index + + ;
if ( index > = sizeof fmt_tb / sizeof fmt_tb [ 0 ] )
return - EINVAL ;
}
}
if ( i < 0 )
return - EINVAL ; /* no more format */
fmtdesc - > pixelformat = fmt_tb [ index ] ;
if ( gspca_is_compressed ( fmt_tb [ index ] ) )
fmtdesc - > flags = V4L2_FMT_FLAG_COMPRESSED ;
2008-06-12 10:58:58 -03:00
fmtdesc - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2008-04-12 09:58:09 -03:00
fmtdesc - > description [ 0 ] = fmtdesc - > pixelformat & 0xff ;
fmtdesc - > description [ 1 ] = ( fmtdesc - > pixelformat > > 8 ) & 0xff ;
fmtdesc - > description [ 2 ] = ( fmtdesc - > pixelformat > > 16 ) & 0xff ;
fmtdesc - > description [ 3 ] = fmtdesc - > pixelformat > > 24 ;
fmtdesc - > description [ 4 ] = ' \0 ' ;
return 0 ;
}
2008-07-01 04:06:22 -03:00
static int vidioc_g_fmt_vid_cap ( struct file * file , void * priv ,
2008-04-12 09:58:09 -03:00
struct v4l2_format * fmt )
{
struct gspca_dev * gspca_dev = priv ;
2008-07-05 11:49:20 -03:00
int mode ;
2008-04-12 09:58:09 -03:00
2008-06-30 15:50:11 -03:00
if ( fmt - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2008-07-05 11:49:20 -03:00
mode = gspca_dev - > curr_mode ;
memcpy ( & fmt - > fmt . pix , & gspca_dev - > cam . cam_mode [ mode ] ,
sizeof fmt - > fmt . pix ) ;
2008-04-12 09:58:09 -03:00
return 0 ;
}
2008-07-01 04:06:22 -03:00
static int try_fmt_vid_cap ( struct gspca_dev * gspca_dev ,
2008-04-12 09:58:09 -03:00
struct v4l2_format * fmt )
{
2008-07-04 17:55:18 -03:00
int w , h , mode , mode2 ;
2008-04-12 09:58:09 -03:00
2008-06-30 15:50:11 -03:00
if ( fmt - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2008-05-04 06:46:21 -03:00
w = fmt - > fmt . pix . width ;
h = fmt - > fmt . pix . height ;
2008-06-12 10:58:58 -03:00
2008-07-03 06:48:22 -03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2008-04-12 09:58:09 -03:00
if ( gspca_debug & D_CONF )
PDEBUG_MODE ( " try fmt cap " , fmt - > fmt . pix . pixelformat , w , h ) ;
# endif
/* search the closest mode for width and height */
mode = wxh_to_mode ( gspca_dev , w , h ) ;
/* OK if right palette */
2008-07-05 11:49:20 -03:00
if ( gspca_dev - > cam . cam_mode [ mode ] . pixelformat
! = fmt - > fmt . pix . pixelformat ) {
2008-04-12 09:58:09 -03:00
/* else, search the closest mode with the same pixel format */
mode2 = gspca_get_mode ( gspca_dev , mode ,
fmt - > fmt . pix . pixelformat ) ;
2008-07-05 11:49:20 -03:00
if ( mode2 > = 0 )
2008-04-12 09:58:09 -03:00
mode = mode2 ;
2008-07-05 11:49:20 -03:00
/* else
; * no chance , return this mode */
2008-04-12 09:58:09 -03:00
}
2008-07-05 11:49:20 -03:00
memcpy ( & fmt - > fmt . pix , & gspca_dev - > cam . cam_mode [ mode ] ,
sizeof fmt - > fmt . pix ) ;
2008-04-12 09:58:09 -03:00
return mode ; /* used when s_fmt */
}
2008-07-01 04:06:22 -03:00
static int vidioc_try_fmt_vid_cap ( struct file * file ,
2008-04-12 09:58:09 -03:00
void * priv ,
struct v4l2_format * fmt )
{
2008-05-04 06:46:21 -03:00
struct gspca_dev * gspca_dev = priv ;
2008-04-12 09:58:09 -03:00
int ret ;
2008-07-01 04:06:22 -03:00
ret = try_fmt_vid_cap ( gspca_dev , fmt ) ;
2008-04-12 09:58:09 -03:00
if ( ret < 0 )
return ret ;
return 0 ;
}
2008-07-01 04:06:22 -03:00
static int vidioc_s_fmt_vid_cap ( struct file * file , void * priv ,
2008-04-12 09:58:09 -03:00
struct v4l2_format * fmt )
{
struct gspca_dev * gspca_dev = priv ;
2008-06-12 10:58:58 -03:00
int ret ;
2008-04-12 09:58:09 -03:00
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-06-12 10:58:58 -03:00
2008-07-01 04:06:22 -03:00
ret = try_fmt_vid_cap ( gspca_dev , fmt ) ;
2008-04-12 09:58:09 -03:00
if ( ret < 0 )
goto out ;
2008-06-12 10:58:58 -03:00
if ( gspca_dev - > nframes ! = 0
& & fmt - > fmt . pix . sizeimage > gspca_dev - > frsz ) {
ret = - EINVAL ;
goto out ;
}
2008-06-30 19:47:33 -03:00
if ( ret = = gspca_dev - > curr_mode ) {
ret = 0 ;
2008-04-12 09:58:09 -03:00
goto out ; /* same mode */
2008-06-30 19:47:33 -03:00
}
2008-06-12 10:58:58 -03:00
if ( gspca_dev - > streaming ) {
ret = - EBUSY ;
goto out ;
2008-04-23 08:09:12 -03:00
}
2008-05-04 06:46:21 -03:00
gspca_dev - > width = fmt - > fmt . pix . width ;
gspca_dev - > height = fmt - > fmt . pix . height ;
2008-04-12 09:58:09 -03:00
gspca_dev - > pixfmt = fmt - > fmt . pix . pixelformat ;
gspca_dev - > curr_mode = ret ;
2008-06-12 10:58:58 -03:00
ret = 0 ;
2008-04-12 09:58:09 -03:00
out :
mutex_unlock ( & gspca_dev - > queue_lock ) ;
return ret ;
}
static int dev_open ( struct inode * inode , struct file * file )
{
struct gspca_dev * gspca_dev ;
int ret ;
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " %s open " , current - > comm ) ;
2008-04-12 09:58:09 -03:00
gspca_dev = ( struct gspca_dev * ) video_devdata ( file ) ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
if ( ! gspca_dev - > present ) {
ret = - ENODEV ;
goto out ;
}
/* if not done yet, initialize the sensor */
if ( gspca_dev - > users = = 0 ) {
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) ) {
ret = - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
goto out ;
2008-04-23 08:09:12 -03:00
}
2008-04-12 09:58:09 -03:00
ret = gspca_dev - > sd_desc - > open ( gspca_dev ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
if ( ret ! = 0 ) {
PDEBUG ( D_ERR | D_CONF , " init device failed %d " , ret ) ;
goto out ;
}
2008-04-23 08:09:12 -03:00
} else if ( gspca_dev - > users > 4 ) { /* (arbitrary value) */
2008-04-12 09:58:09 -03:00
ret = - EBUSY ;
goto out ;
}
gspca_dev - > users + + ;
file - > private_data = gspca_dev ;
2008-07-03 06:48:22 -03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2008-04-12 09:58:09 -03:00
/* activate the v4l2 debug */
2008-06-12 10:58:58 -03:00
if ( gspca_debug & D_V4L2 )
2008-04-12 09:58:09 -03:00
gspca_dev - > vdev . debug | = 3 ;
else
gspca_dev - > vdev . debug & = ~ 3 ;
# endif
out :
mutex_unlock ( & gspca_dev - > queue_lock ) ;
if ( ret ! = 0 )
PDEBUG ( D_ERR | D_STREAM , " open failed err %d " , ret ) ;
else
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " open done " ) ;
2008-04-12 09:58:09 -03:00
return ret ;
}
static int dev_close ( struct inode * inode , struct file * file )
{
struct gspca_dev * gspca_dev = file - > private_data ;
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " %s close " , current - > comm ) ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
gspca_dev - > users - - ;
2008-07-12 09:28:04 -03:00
/* if the file did the capture, free the streaming resources */
2008-05-04 06:46:21 -03:00
if ( gspca_dev - > capt_file = = file ) {
mutex_lock ( & gspca_dev - > usb_lock ) ;
if ( gspca_dev - > streaming )
gspca_stream_off ( gspca_dev ) ;
gspca_dev - > sd_desc - > close ( gspca_dev ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
frame_free ( gspca_dev ) ;
2008-07-05 06:12:47 -03:00
gspca_dev - > capt_file = NULL ;
2008-06-12 10:58:58 -03:00
gspca_dev - > memory = GSPCA_MEMORY_NO ;
2008-05-04 06:46:21 -03:00
}
2008-06-12 10:58:58 -03:00
file - > private_data = NULL ;
2008-04-12 09:58:09 -03:00
mutex_unlock ( & gspca_dev - > queue_lock ) ;
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " close done " ) ;
2008-04-12 09:58:09 -03:00
return 0 ;
}
static int vidioc_querycap ( struct file * file , void * priv ,
struct v4l2_capability * cap )
{
struct gspca_dev * gspca_dev = priv ;
memset ( cap , 0 , sizeof * cap ) ;
strncpy ( cap - > driver , gspca_dev - > sd_desc - > name , sizeof cap - > driver ) ;
strncpy ( cap - > card , gspca_dev - > cam . dev_name , sizeof cap - > card ) ;
strncpy ( cap - > bus_info , gspca_dev - > dev - > bus - > bus_name ,
sizeof cap - > bus_info ) ;
cap - > version = DRIVER_VERSION_NUMBER ;
cap - > capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
| V4L2_CAP_READWRITE ;
return 0 ;
}
2008-06-30 15:50:11 -03:00
/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
2008-04-12 09:58:09 -03:00
static int vidioc_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * q_ctrl )
{
struct gspca_dev * gspca_dev = priv ;
int i ;
2008-06-30 15:50:11 -03:00
u32 id ;
id = q_ctrl - > id ;
if ( id & V4L2_CTRL_FLAG_NEXT_CTRL ) {
id & = V4L2_CTRL_ID_MASK ;
id + + ;
for ( i = 0 ; i < gspca_dev - > sd_desc - > nctrls ; i + + ) {
if ( id > = gspca_dev - > sd_desc - > ctrls [ i ] . qctrl . id ) {
memcpy ( q_ctrl ,
& gspca_dev - > sd_desc - > ctrls [ i ] . qctrl ,
sizeof * q_ctrl ) ;
return 0 ;
}
}
return - EINVAL ;
}
2008-04-12 09:58:09 -03:00
for ( i = 0 ; i < gspca_dev - > sd_desc - > nctrls ; i + + ) {
2008-06-30 15:50:11 -03:00
if ( id = = gspca_dev - > sd_desc - > ctrls [ i ] . qctrl . id ) {
2008-04-12 09:58:09 -03:00
memcpy ( q_ctrl ,
& gspca_dev - > sd_desc - > ctrls [ i ] . qctrl ,
sizeof * q_ctrl ) ;
return 0 ;
}
}
2008-06-30 15:50:11 -03:00
if ( id > = V4L2_CID_BASE
& & id < = V4L2_CID_LASTP1 ) {
2008-04-12 09:58:09 -03:00
q_ctrl - > flags | = V4L2_CTRL_FLAG_DISABLED ;
return 0 ;
}
return - EINVAL ;
}
static int vidioc_s_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
{
struct gspca_dev * gspca_dev = priv ;
2008-07-04 11:16:16 -03:00
const struct ctrl * ctrls ;
2008-04-12 09:58:09 -03:00
int i , ret ;
for ( i = 0 , ctrls = gspca_dev - > sd_desc - > ctrls ;
i < gspca_dev - > sd_desc - > nctrls ;
i + + , ctrls + + ) {
if ( ctrl - > id ! = ctrls - > qctrl . id )
continue ;
if ( ctrl - > value < ctrls - > qctrl . minimum
& & ctrl - > value > ctrls - > qctrl . maximum )
return - ERANGE ;
PDEBUG ( D_CONF , " set ctrl [%08x] = %d " , ctrl - > id , ctrl - > value ) ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
ret = ctrls - > set ( gspca_dev , ctrl - > value ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
return ret ;
}
return - EINVAL ;
}
static int vidioc_g_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
{
struct gspca_dev * gspca_dev = priv ;
2008-07-04 11:16:16 -03:00
const struct ctrl * ctrls ;
2008-04-12 09:58:09 -03:00
int i , ret ;
for ( i = 0 , ctrls = gspca_dev - > sd_desc - > ctrls ;
i < gspca_dev - > sd_desc - > nctrls ;
i + + , ctrls + + ) {
if ( ctrl - > id ! = ctrls - > qctrl . id )
continue ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
ret = ctrls - > get ( gspca_dev , & ctrl - > value ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
return ret ;
}
return - EINVAL ;
}
static int vidioc_querymenu ( struct file * file , void * priv ,
struct v4l2_querymenu * qmenu )
{
struct gspca_dev * gspca_dev = priv ;
if ( ! gspca_dev - > sd_desc - > querymenu )
return - EINVAL ;
return gspca_dev - > sd_desc - > querymenu ( gspca_dev , qmenu ) ;
}
static int vidioc_enum_input ( struct file * file , void * priv ,
struct v4l2_input * input )
{
struct gspca_dev * gspca_dev = priv ;
if ( input - > index ! = 0 )
return - EINVAL ;
memset ( input , 0 , sizeof * input ) ;
input - > type = V4L2_INPUT_TYPE_CAMERA ;
strncpy ( input - > name , gspca_dev - > sd_desc - > name ,
sizeof input - > name ) ;
return 0 ;
}
static int vidioc_g_input ( struct file * file , void * priv , unsigned int * i )
{
* i = 0 ;
return 0 ;
}
static int vidioc_s_input ( struct file * file , void * priv , unsigned int i )
{
if ( i > 0 )
return - EINVAL ;
return ( 0 ) ;
}
static int vidioc_reqbufs ( struct file * file , void * priv ,
struct v4l2_requestbuffers * rb )
{
struct gspca_dev * gspca_dev = priv ;
2008-06-12 10:58:58 -03:00
int i , ret = 0 ;
2008-04-12 09:58:09 -03:00
if ( rb - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2008-06-12 10:58:58 -03:00
switch ( rb - > memory ) {
2008-07-12 09:28:04 -03:00
case GSPCA_MEMORY_READ : /* (internal call) */
2008-06-12 10:58:58 -03:00
case V4L2_MEMORY_MMAP :
case V4L2_MEMORY_USERPTR :
2008-06-30 15:50:11 -03:00
break ;
2008-06-12 10:58:58 -03:00
default :
2008-04-12 09:58:09 -03:00
return - EINVAL ;
2008-06-12 10:58:58 -03:00
}
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-06-12 10:58:58 -03:00
2008-07-12 09:28:04 -03:00
if ( gspca_dev - > memory ! = GSPCA_MEMORY_NO
& & gspca_dev - > memory ! = rb - > memory ) {
2008-05-04 06:46:21 -03:00
ret = - EBUSY ;
goto out ;
}
2008-06-12 10:58:58 -03:00
2008-07-12 09:28:04 -03:00
/* only one file may do the capture */
if ( gspca_dev - > capt_file ! = NULL
& & gspca_dev - > capt_file ! = file ) {
ret = - EBUSY ;
goto out ;
}
/* if allocated, the buffers must not be mapped */
for ( i = 0 ; i < gspca_dev - > nframes ; i + + ) {
if ( gspca_dev - > frame [ i ] . vma_use_count ) {
2008-07-08 06:58:15 -03:00
ret = - EBUSY ;
goto out ;
}
2008-07-12 09:28:04 -03:00
}
/* stop streaming */
if ( gspca_dev - > streaming ) {
mutex_lock ( & gspca_dev - > usb_lock ) ;
gspca_stream_off ( gspca_dev ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
}
/* free the previous allocated buffers, if any */
if ( gspca_dev - > nframes ! = 0 ) {
frame_free ( gspca_dev ) ;
gspca_dev - > capt_file = NULL ;
}
if ( rb - > count = = 0 ) /* unrequest */
goto out ;
gspca_dev - > memory = rb - > memory ;
ret = frame_alloc ( gspca_dev , rb - > count ) ;
if ( ret = = 0 ) {
rb - > count = gspca_dev - > nframes ;
gspca_dev - > capt_file = file ;
2008-05-04 06:46:21 -03:00
}
out :
2008-04-12 09:58:09 -03:00
mutex_unlock ( & gspca_dev - > queue_lock ) ;
PDEBUG ( D_STREAM , " reqbufs st:%d c:%d " , ret , rb - > count ) ;
return ret ;
}
static int vidioc_querybuf ( struct file * file , void * priv ,
struct v4l2_buffer * v4l2_buf )
{
struct gspca_dev * gspca_dev = priv ;
struct gspca_frame * frame ;
if ( v4l2_buf - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE
| | v4l2_buf - > index < 0
| | v4l2_buf - > index > = gspca_dev - > nframes )
return - EINVAL ;
frame = & gspca_dev - > frame [ v4l2_buf - > index ] ;
memcpy ( v4l2_buf , & frame - > v4l2_buf , sizeof * v4l2_buf ) ;
return 0 ;
}
static int vidioc_streamon ( struct file * file , void * priv ,
enum v4l2_buf_type buf_type )
{
struct gspca_dev * gspca_dev = priv ;
int ret ;
if ( buf_type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
if ( ! gspca_dev - > present ) {
ret = - ENODEV ;
goto out ;
}
if ( gspca_dev - > nframes = = 0 ) {
ret = - EINVAL ;
goto out ;
}
if ( ! gspca_dev - > streaming ) {
ret = gspca_init_transfer ( gspca_dev ) ;
if ( ret < 0 )
goto out ;
}
2008-07-03 06:48:22 -03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2008-04-12 09:58:09 -03:00
if ( gspca_debug & D_STREAM ) {
PDEBUG_MODE ( " stream on OK " ,
gspca_dev - > pixfmt ,
gspca_dev - > width ,
gspca_dev - > height ) ;
}
# endif
2008-04-23 08:09:12 -03:00
ret = 0 ;
2008-04-12 09:58:09 -03:00
out :
mutex_unlock ( & gspca_dev - > queue_lock ) ;
return ret ;
}
static int vidioc_streamoff ( struct file * file , void * priv ,
enum v4l2_buf_type buf_type )
{
struct gspca_dev * gspca_dev = priv ;
2008-07-12 09:28:04 -03:00
int i , ret ;
2008-04-12 09:58:09 -03:00
if ( buf_type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2008-05-04 06:46:21 -03:00
if ( ! gspca_dev - > streaming )
return 0 ;
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-07-12 09:28:04 -03:00
/* stop streaming */
2008-05-04 06:46:21 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) ) {
ret = - ERESTARTSYS ;
goto out ;
2008-04-12 09:58:09 -03:00
}
2008-05-04 06:46:21 -03:00
gspca_stream_off ( gspca_dev ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
2008-07-12 09:28:04 -03:00
/* empty the application queues */
for ( i = 0 ; i < gspca_dev - > nframes ; i + + )
gspca_dev - > frame [ i ] . v4l2_buf . flags & = ~ BUF_ALL_FLAGS ;
gspca_dev - > fr_i = gspca_dev - > fr_o = gspca_dev - > fr_q = 0 ;
gspca_dev - > last_packet_type = DISCARD_PACKET ;
gspca_dev - > sequence = 0 ;
atomic_set ( & gspca_dev - > nevent , 0 ) ;
ret = 0 ;
2008-05-04 06:46:21 -03:00
out :
mutex_unlock ( & gspca_dev - > queue_lock ) ;
return ret ;
2008-04-12 09:58:09 -03:00
}
static int vidioc_g_jpegcomp ( struct file * file , void * priv ,
struct v4l2_jpegcompression * jpegcomp )
{
struct gspca_dev * gspca_dev = priv ;
int ret ;
if ( ! gspca_dev - > sd_desc - > get_jcomp )
return - EINVAL ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
ret = gspca_dev - > sd_desc - > get_jcomp ( gspca_dev , jpegcomp ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
return ret ;
}
static int vidioc_s_jpegcomp ( struct file * file , void * priv ,
struct v4l2_jpegcompression * jpegcomp )
{
struct gspca_dev * gspca_dev = priv ;
int ret ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > usb_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
if ( ! gspca_dev - > sd_desc - > set_jcomp )
return - EINVAL ;
ret = gspca_dev - > sd_desc - > set_jcomp ( gspca_dev , jpegcomp ) ;
mutex_unlock ( & gspca_dev - > usb_lock ) ;
return ret ;
}
static int vidioc_g_parm ( struct file * filp , void * priv ,
struct v4l2_streamparm * parm )
{
struct gspca_dev * gspca_dev = priv ;
2008-06-30 15:50:11 -03:00
memset ( parm , 0 , sizeof * parm ) ;
2008-04-12 09:58:09 -03:00
parm - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
parm - > parm . capture . readbuffers = gspca_dev - > nbufread ;
return 0 ;
}
static int vidioc_s_parm ( struct file * filp , void * priv ,
struct v4l2_streamparm * parm )
{
struct gspca_dev * gspca_dev = priv ;
int n ;
n = parm - > parm . capture . readbuffers ;
if ( n = = 0 | | n > GSPCA_MAX_FRAMES )
parm - > parm . capture . readbuffers = gspca_dev - > nbufread ;
else
gspca_dev - > nbufread = n ;
return 0 ;
}
2008-06-30 15:50:11 -03:00
static int vidioc_s_std ( struct file * filp , void * priv ,
v4l2_std_id * parm )
{
return 0 ;
}
2008-04-12 09:58:09 -03:00
# ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf ( struct file * file , void * priv ,
struct video_mbuf * mbuf )
{
struct gspca_dev * gspca_dev = file - > private_data ;
int i ;
PDEBUG ( D_STREAM , " cgmbuf " ) ;
if ( gspca_dev - > nframes = = 0 ) {
int ret ;
2008-06-30 15:50:11 -03:00
{
struct v4l2_format fmt ;
memset ( & fmt , 0 , sizeof fmt ) ;
fmt . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
i = gspca_dev - > cam . nmodes - 1 ; /* highest mode */
fmt . fmt . pix . width = gspca_dev - > cam . cam_mode [ i ] . width ;
fmt . fmt . pix . height = gspca_dev - > cam . cam_mode [ i ] . height ;
fmt . fmt . pix . pixelformat = V4L2_PIX_FMT_BGR24 ;
2008-07-01 04:06:22 -03:00
ret = vidioc_s_fmt_vid_cap ( file , priv , & fmt ) ;
2008-06-30 15:50:11 -03:00
if ( ret ! = 0 )
return ret ;
}
{
struct v4l2_requestbuffers rb ;
memset ( & rb , 0 , sizeof rb ) ;
rb . count = 4 ;
rb . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
rb . memory = V4L2_MEMORY_MMAP ;
ret = vidioc_reqbufs ( file , priv , & rb ) ;
if ( ret ! = 0 )
return ret ;
}
2008-04-12 09:58:09 -03:00
}
mbuf - > frames = gspca_dev - > nframes ;
mbuf - > size = gspca_dev - > frsz * gspca_dev - > nframes ;
for ( i = 0 ; i < mbuf - > frames ; i + + )
mbuf - > offsets [ i ] = gspca_dev - > frame [ i ] . v4l2_buf . m . offset ;
return 0 ;
}
# endif
static int dev_mmap ( struct file * file , struct vm_area_struct * vma )
{
struct gspca_dev * gspca_dev = file - > private_data ;
2008-07-05 06:12:47 -03:00
struct gspca_frame * frame ;
2008-04-12 09:58:09 -03:00
struct page * page ;
unsigned long addr , start , size ;
int i , ret ;
start = vma - > vm_start ;
size = vma - > vm_end - vma - > vm_start ;
PDEBUG ( D_STREAM , " mmap start:%08x size:%d " , ( int ) start , ( int ) size ) ;
2008-04-23 08:09:12 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
if ( ! gspca_dev - > present ) {
ret = - ENODEV ;
2008-05-04 06:46:21 -03:00
goto out ;
}
if ( gspca_dev - > capt_file ! = file ) {
ret = - EINVAL ;
goto out ;
2008-04-12 09:58:09 -03:00
}
2008-07-05 06:12:47 -03:00
frame = NULL ;
2008-04-12 09:58:09 -03:00
for ( i = 0 ; i < gspca_dev - > nframes ; + + i ) {
if ( gspca_dev - > frame [ i ] . v4l2_buf . memory ! = V4L2_MEMORY_MMAP ) {
PDEBUG ( D_STREAM , " mmap bad memory type " ) ;
break ;
}
if ( ( gspca_dev - > frame [ i ] . v4l2_buf . m . offset > > PAGE_SHIFT )
= = vma - > vm_pgoff ) {
frame = & gspca_dev - > frame [ i ] ;
break ;
}
}
2008-07-05 06:12:47 -03:00
if ( frame = = NULL ) {
2008-04-12 09:58:09 -03:00
PDEBUG ( D_STREAM , " mmap no frame buffer found " ) ;
ret = - EINVAL ;
2008-05-04 06:46:21 -03:00
goto out ;
2008-04-12 09:58:09 -03:00
}
# ifdef CONFIG_VIDEO_V4L1_COMPAT
2008-07-08 06:58:15 -03:00
/* v4l1 maps all the buffers */
if ( i ! = 0
| | size ! = frame - > v4l2_buf . length * gspca_dev - > nframes )
2008-04-12 09:58:09 -03:00
# endif
2008-07-08 06:58:15 -03:00
if ( size ! = frame - > v4l2_buf . length ) {
2008-04-12 09:58:09 -03:00
PDEBUG ( D_STREAM , " mmap bad size " ) ;
ret = - EINVAL ;
2008-05-04 06:46:21 -03:00
goto out ;
2008-04-12 09:58:09 -03:00
}
/*
* - VM_IO marks the area as being a mmaped region for I / O to a
* device . It also prevents the region from being core dumped .
*/
vma - > vm_flags | = VM_IO ;
addr = ( unsigned long ) frame - > data ;
while ( size > 0 ) {
page = vmalloc_to_page ( ( void * ) addr ) ;
ret = vm_insert_page ( vma , start , page ) ;
if ( ret < 0 )
2008-05-04 06:46:21 -03:00
goto out ;
2008-04-12 09:58:09 -03:00
start + = PAGE_SIZE ;
addr + = PAGE_SIZE ;
size - = PAGE_SIZE ;
}
vma - > vm_ops = & gspca_vm_ops ;
vma - > vm_private_data = frame ;
gspca_vm_open ( vma ) ;
2008-04-23 08:09:12 -03:00
ret = 0 ;
2008-05-04 06:46:21 -03:00
out :
2008-04-12 09:58:09 -03:00
mutex_unlock ( & gspca_dev - > queue_lock ) ;
return ret ;
}
/*
* wait for a video frame
*
* If a frame is ready , its index is returned .
*/
2008-06-12 10:58:58 -03:00
static int frame_wait ( struct gspca_dev * gspca_dev ,
2008-04-12 09:58:09 -03:00
int nonblock_ing )
{
struct gspca_frame * frame ;
int i , j , ret ;
2008-06-12 10:58:58 -03:00
/* check if a frame is ready */
2008-04-12 09:58:09 -03:00
i = gspca_dev - > fr_o ;
j = gspca_dev - > fr_queue [ i ] ;
frame = & gspca_dev - > frame [ j ] ;
2008-07-02 09:14:56 -03:00
if ( frame - > v4l2_buf . flags & V4L2_BUF_FLAG_DONE ) {
atomic_dec ( & gspca_dev - > nevent ) ;
2008-04-12 09:58:09 -03:00
goto ok ;
2008-07-02 09:14:56 -03:00
}
2008-04-12 09:58:09 -03:00
if ( nonblock_ing ) /* no frame yet */
return - EAGAIN ;
/* wait till a frame is ready */
for ( ; ; ) {
2008-05-04 06:46:21 -03:00
ret = wait_event_interruptible_timeout ( gspca_dev - > wq ,
atomic_read ( & gspca_dev - > nevent ) > 0 ,
msecs_to_jiffies ( 3000 ) ) ;
if ( ret < = 0 ) {
if ( ret < 0 )
2008-07-02 09:14:56 -03:00
return ret ; /* interrupt */
return - EIO ; /* timeout */
2008-05-04 06:46:21 -03:00
}
2008-07-02 09:14:56 -03:00
atomic_dec ( & gspca_dev - > nevent ) ;
2008-04-23 08:09:12 -03:00
if ( ! gspca_dev - > streaming | | ! gspca_dev - > present )
return - EIO ;
2008-04-12 09:58:09 -03:00
i = gspca_dev - > fr_o ;
j = gspca_dev - > fr_queue [ i ] ;
frame = & gspca_dev - > frame [ j ] ;
if ( frame - > v4l2_buf . flags & V4L2_BUF_FLAG_DONE )
break ;
}
ok :
gspca_dev - > fr_o = ( i + 1 ) % gspca_dev - > nframes ;
PDEBUG ( D_FRAM , " frame wait q:%d i:%d o:%d " ,
gspca_dev - > fr_q ,
gspca_dev - > fr_i ,
gspca_dev - > fr_o ) ;
2008-04-23 08:09:12 -03:00
2008-07-14 09:38:29 -03:00
if ( gspca_dev - > sd_desc - > dq_callback ) {
mutex_lock ( & gspca_dev - > usb_lock ) ;
2008-04-23 08:09:12 -03:00
gspca_dev - > sd_desc - > dq_callback ( gspca_dev ) ;
2008-07-14 09:38:29 -03:00
mutex_unlock ( & gspca_dev - > usb_lock ) ;
}
2008-04-12 09:58:09 -03:00
return j ;
}
/*
* dequeue a video buffer
*
* If nonblock_ing is false , block until a buffer is available .
*/
static int vidioc_dqbuf ( struct file * file , void * priv ,
struct v4l2_buffer * v4l2_buf )
{
struct gspca_dev * gspca_dev = priv ;
struct gspca_frame * frame ;
int i , ret ;
PDEBUG ( D_FRAM , " dqbuf " ) ;
2008-07-08 06:58:15 -03:00
if ( v4l2_buf - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
if ( v4l2_buf - > memory ! = gspca_dev - > memory )
2008-04-12 09:58:09 -03:00
return - EINVAL ;
2008-07-12 09:28:04 -03:00
/* if not streaming, be sure the application will not loop forever */
if ( ! ( file - > f_flags & O_NONBLOCK )
& & ! gspca_dev - > streaming & & gspca_dev - > users = = 1 )
2008-04-12 09:58:09 -03:00
return - EINVAL ;
2008-07-12 09:28:04 -03:00
/* only the capturing file may dequeue */
if ( gspca_dev - > capt_file ! = file )
return - EINVAL ;
/* only one dequeue / read at a time */
2008-04-12 09:58:09 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > read_lock ) )
return - ERESTARTSYS ;
2008-06-12 10:58:58 -03:00
ret = frame_wait ( gspca_dev , file - > f_flags & O_NONBLOCK ) ;
2008-04-12 09:58:09 -03:00
if ( ret < 0 )
2008-05-04 06:46:21 -03:00
goto out ;
2008-04-12 09:58:09 -03:00
i = ret ; /* frame index */
frame = & gspca_dev - > frame [ i ] ;
2008-07-08 06:58:15 -03:00
if ( gspca_dev - > memory = = V4L2_MEMORY_USERPTR ) {
if ( copy_to_user ( ( __u8 * ) frame - > v4l2_buf . m . userptr ,
frame - > data ,
frame - > v4l2_buf . bytesused ) ) {
PDEBUG ( D_ERR | D_STREAM ,
" dqbuf cp to user failed " ) ;
ret = - EFAULT ;
goto out ;
}
}
2008-04-12 09:58:09 -03:00
frame - > v4l2_buf . flags & = ~ V4L2_BUF_FLAG_DONE ;
memcpy ( v4l2_buf , & frame - > v4l2_buf , sizeof * v4l2_buf ) ;
PDEBUG ( D_FRAM , " dqbuf %d " , i ) ;
ret = 0 ;
2008-05-04 06:46:21 -03:00
out :
2008-04-12 09:58:09 -03:00
mutex_unlock ( & gspca_dev - > read_lock ) ;
return ret ;
}
/*
* queue a video buffer
*
* Attempting to queue a buffer that has already been
* queued will return - EINVAL .
*/
static int vidioc_qbuf ( struct file * file , void * priv ,
struct v4l2_buffer * v4l2_buf )
{
struct gspca_dev * gspca_dev = priv ;
struct gspca_frame * frame ;
int i , index , ret ;
PDEBUG ( D_FRAM , " qbuf %d " , v4l2_buf - > index ) ;
if ( v4l2_buf - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
2008-07-12 09:28:04 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) )
return - ERESTARTSYS ;
2008-04-12 09:58:09 -03:00
index = v4l2_buf - > index ;
if ( ( unsigned ) index > = gspca_dev - > nframes ) {
2008-06-12 10:58:58 -03:00
PDEBUG ( D_FRAM ,
2008-04-12 09:58:09 -03:00
" qbuf idx %d >= %d " , index , gspca_dev - > nframes ) ;
2008-07-12 09:28:04 -03:00
ret = - EINVAL ;
goto out ;
2008-04-12 09:58:09 -03:00
}
2008-07-12 09:28:04 -03:00
if ( v4l2_buf - > memory ! = gspca_dev - > memory ) {
2008-06-12 10:58:58 -03:00
PDEBUG ( D_FRAM , " qbuf bad memory type " ) ;
2008-07-12 09:28:04 -03:00
ret = - EINVAL ;
goto out ;
2008-04-12 09:58:09 -03:00
}
2008-04-23 08:09:12 -03:00
2008-07-12 09:28:04 -03:00
frame = & gspca_dev - > frame [ index ] ;
2008-06-12 10:58:58 -03:00
if ( frame - > v4l2_buf . flags & BUF_ALL_FLAGS ) {
PDEBUG ( D_FRAM , " qbuf bad state " ) ;
2008-04-12 09:58:09 -03:00
ret = - EINVAL ;
goto out ;
}
frame - > v4l2_buf . flags | = V4L2_BUF_FLAG_QUEUED ;
2008-06-12 10:58:58 -03:00
/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
2008-04-12 09:58:09 -03:00
2008-06-12 10:58:58 -03:00
if ( frame - > v4l2_buf . memory = = V4L2_MEMORY_USERPTR ) {
2008-04-12 09:58:09 -03:00
frame - > v4l2_buf . m . userptr = v4l2_buf - > m . userptr ;
frame - > v4l2_buf . length = v4l2_buf - > length ;
}
/* put the buffer in the 'queued' queue */
i = gspca_dev - > fr_q ;
gspca_dev - > fr_queue [ i ] = index ;
gspca_dev - > fr_q = ( i + 1 ) % gspca_dev - > nframes ;
PDEBUG ( D_FRAM , " qbuf q:%d i:%d o:%d " ,
gspca_dev - > fr_q ,
gspca_dev - > fr_i ,
gspca_dev - > fr_o ) ;
v4l2_buf - > flags | = V4L2_BUF_FLAG_QUEUED ;
v4l2_buf - > flags & = ~ V4L2_BUF_FLAG_DONE ;
ret = 0 ;
out :
mutex_unlock ( & gspca_dev - > queue_lock ) ;
return ret ;
}
2008-06-12 10:58:58 -03:00
/*
* allocate the resources for read ( )
*/
static int read_alloc ( struct gspca_dev * gspca_dev ,
struct file * file )
2008-04-12 09:58:09 -03:00
{
struct v4l2_buffer v4l2_buf ;
2008-06-12 10:58:58 -03:00
int i , ret ;
2008-04-12 09:58:09 -03:00
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " read alloc " ) ;
2008-04-12 09:58:09 -03:00
if ( gspca_dev - > nframes = = 0 ) {
struct v4l2_requestbuffers rb ;
memset ( & rb , 0 , sizeof rb ) ;
rb . count = gspca_dev - > nbufread ;
rb . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2008-07-08 06:58:15 -03:00
rb . memory = GSPCA_MEMORY_READ ;
2008-04-12 09:58:09 -03:00
ret = vidioc_reqbufs ( file , gspca_dev , & rb ) ;
if ( ret ! = 0 ) {
2008-06-12 10:58:58 -03:00
PDEBUG ( D_STREAM , " read reqbuf err %d " , ret ) ;
2008-04-12 09:58:09 -03:00
return ret ;
}
memset ( & v4l2_buf , 0 , sizeof v4l2_buf ) ;
v4l2_buf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2008-07-08 06:58:15 -03:00
v4l2_buf . memory = GSPCA_MEMORY_READ ;
2008-04-12 09:58:09 -03:00
for ( i = 0 ; i < gspca_dev - > nbufread ; i + + ) {
v4l2_buf . index = i ;
ret = vidioc_qbuf ( file , gspca_dev , & v4l2_buf ) ;
if ( ret ! = 0 ) {
PDEBUG ( D_STREAM , " read qbuf err: %d " , ret ) ;
return ret ;
}
}
2008-06-12 10:58:58 -03:00
gspca_dev - > memory = GSPCA_MEMORY_READ ;
}
2008-05-04 06:46:21 -03:00
2008-06-12 10:58:58 -03:00
/* start streaming */
ret = vidioc_streamon ( file , gspca_dev , V4L2_BUF_TYPE_VIDEO_CAPTURE ) ;
if ( ret ! = 0 )
PDEBUG ( D_STREAM , " read streamon err %d " , ret ) ;
return ret ;
}
static unsigned int dev_poll ( struct file * file , poll_table * wait )
{
struct gspca_dev * gspca_dev = file - > private_data ;
int i , ret ;
PDEBUG ( D_FRAM , " poll " ) ;
poll_wait ( file , & gspca_dev - > wq , wait ) ;
if ( ! gspca_dev - > present )
return POLLERR ;
2008-07-12 09:28:04 -03:00
/* if reqbufs is not done, the user would use read() */
if ( gspca_dev - > nframes = = 0 ) {
if ( gspca_dev - > memory ! = GSPCA_MEMORY_NO )
return POLLERR ; /* not the 1st time */
2008-06-12 10:58:58 -03:00
ret = read_alloc ( gspca_dev , file ) ;
2008-07-12 09:28:04 -03:00
if ( ret ! = 0 )
return POLLERR ;
2008-04-12 09:58:09 -03:00
}
2008-06-12 10:58:58 -03:00
if ( mutex_lock_interruptible ( & gspca_dev - > queue_lock ) ! = 0 )
return POLLERR ;
if ( ! gspca_dev - > present ) {
ret = POLLERR ;
goto out ;
}
2008-07-12 09:28:04 -03:00
/* check the next incoming buffer */
2008-06-12 10:58:58 -03:00
i = gspca_dev - > fr_o ;
i = gspca_dev - > fr_queue [ i ] ;
if ( gspca_dev - > frame [ i ] . v4l2_buf . flags & V4L2_BUF_FLAG_DONE )
ret = POLLIN | POLLRDNORM ; /* something to read */
else
ret = 0 ;
out :
mutex_unlock ( & gspca_dev - > queue_lock ) ;
return ret ;
}
static ssize_t dev_read ( struct file * file , char __user * data ,
size_t count , loff_t * ppos )
{
struct gspca_dev * gspca_dev = file - > private_data ;
struct gspca_frame * frame ;
struct v4l2_buffer v4l2_buf ;
struct timeval timestamp ;
2008-07-02 09:14:56 -03:00
int n , ret , ret2 ;
2008-06-12 10:58:58 -03:00
2008-07-09 05:26:26 -03:00
PDEBUG ( D_FRAM , " read (%zd) " , count ) ;
2008-06-12 10:58:58 -03:00
if ( ! gspca_dev - > present )
return - ENODEV ;
switch ( gspca_dev - > memory ) {
case GSPCA_MEMORY_NO : /* first time */
ret = read_alloc ( gspca_dev , file ) ;
if ( ret ! = 0 )
return ret ;
break ;
case GSPCA_MEMORY_READ :
2008-07-02 09:14:56 -03:00
if ( gspca_dev - > capt_file = = file )
break ;
/* fall thru */
2008-06-12 10:58:58 -03:00
default :
return - EINVAL ;
}
2008-04-12 09:58:09 -03:00
/* get a frame */
jiffies_to_timeval ( get_jiffies_64 ( ) , & timestamp ) ;
timestamp . tv_sec - - ;
2008-07-02 09:14:56 -03:00
n = 2 ;
for ( ; ; ) {
2008-04-12 09:58:09 -03:00
memset ( & v4l2_buf , 0 , sizeof v4l2_buf ) ;
v4l2_buf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2008-07-08 06:58:15 -03:00
v4l2_buf . memory = GSPCA_MEMORY_READ ;
2008-04-12 09:58:09 -03:00
ret = vidioc_dqbuf ( file , gspca_dev , & v4l2_buf ) ;
if ( ret ! = 0 ) {
PDEBUG ( D_STREAM , " read dqbuf err %d " , ret ) ;
return ret ;
}
/* if the process slept for more than 1 second,
2008-07-02 09:14:56 -03:00
* get anewer frame */
2008-04-12 09:58:09 -03:00
frame = & gspca_dev - > frame [ v4l2_buf . index ] ;
2008-07-02 09:14:56 -03:00
if ( - - n < 0 )
break ; /* avoid infinite loop */
2008-04-12 09:58:09 -03:00
if ( frame - > v4l2_buf . timestamp . tv_sec > = timestamp . tv_sec )
break ;
ret = vidioc_qbuf ( file , gspca_dev , & v4l2_buf ) ;
if ( ret ! = 0 ) {
PDEBUG ( D_STREAM , " read qbuf err %d " , ret ) ;
return ret ;
}
}
/* copy the frame */
2008-07-08 06:58:15 -03:00
if ( count > frame - > v4l2_buf . bytesused )
count = frame - > v4l2_buf . bytesused ;
2008-04-12 09:58:09 -03:00
ret = copy_to_user ( data , frame - > data , count ) ;
if ( ret ! = 0 ) {
PDEBUG ( D_ERR | D_STREAM ,
2008-07-09 05:26:26 -03:00
" read cp to user lack %d / %zd " , ret , count ) ;
2008-04-12 09:58:09 -03:00
ret = - EFAULT ;
goto out ;
}
ret = count ;
out :
/* in each case, requeue the buffer */
ret2 = vidioc_qbuf ( file , gspca_dev , & v4l2_buf ) ;
if ( ret2 ! = 0 )
return ret2 ;
return ret ;
}
2008-06-12 10:58:58 -03:00
static void dev_release ( struct video_device * vfd )
2008-04-12 09:58:09 -03:00
{
/* nothing */
}
static struct file_operations dev_fops = {
. owner = THIS_MODULE ,
. open = dev_open ,
. release = dev_close ,
. read = dev_read ,
. mmap = dev_mmap ,
. ioctl = video_ioctl2 ,
2008-06-30 15:50:11 -03:00
# ifdef CONFIG_COMPAT
. compat_ioctl = v4l_compat_ioctl32 ,
# endif
2008-04-12 09:58:09 -03:00
. llseek = no_llseek ,
. poll = dev_poll ,
} ;
static struct video_device gspca_template = {
. name = " gspca main driver " ,
. type = VID_TYPE_CAPTURE ,
. fops = & dev_fops ,
2008-06-12 10:58:58 -03:00
. release = dev_release , /* mandatory */
2008-04-12 09:58:09 -03:00
. minor = - 1 ,
. vidioc_querycap = vidioc_querycap ,
. vidioc_dqbuf = vidioc_dqbuf ,
. vidioc_qbuf = vidioc_qbuf ,
2008-07-01 04:06:22 -03:00
. vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap ,
. vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap ,
. vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap ,
. vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap ,
2008-04-12 09:58:09 -03:00
. vidioc_streamon = vidioc_streamon ,
. vidioc_queryctrl = vidioc_queryctrl ,
. vidioc_g_ctrl = vidioc_g_ctrl ,
. vidioc_s_ctrl = vidioc_s_ctrl ,
. vidioc_querymenu = vidioc_querymenu ,
. vidioc_enum_input = vidioc_enum_input ,
. vidioc_g_input = vidioc_g_input ,
. vidioc_s_input = vidioc_s_input ,
. vidioc_reqbufs = vidioc_reqbufs ,
. vidioc_querybuf = vidioc_querybuf ,
. vidioc_streamoff = vidioc_streamoff ,
. vidioc_g_jpegcomp = vidioc_g_jpegcomp ,
. vidioc_s_jpegcomp = vidioc_s_jpegcomp ,
. vidioc_g_parm = vidioc_g_parm ,
. vidioc_s_parm = vidioc_s_parm ,
2008-06-30 15:50:11 -03:00
. vidioc_s_std = vidioc_s_std ,
2008-04-12 09:58:09 -03:00
# ifdef CONFIG_VIDEO_V4L1_COMPAT
. vidiocgmbuf = vidiocgmbuf ,
# endif
} ;
/*
* probe and create a new gspca device
*
* This function must be called by the sub - driver when it is
* called for probing a new device .
*/
int gspca_dev_probe ( struct usb_interface * intf ,
const struct usb_device_id * id ,
const struct sd_desc * sd_desc ,
2008-06-12 10:58:58 -03:00
int dev_size ,
struct module * module )
2008-04-12 09:58:09 -03:00
{
struct usb_interface_descriptor * interface ;
struct gspca_dev * gspca_dev ;
struct usb_device * dev = interface_to_usbdev ( intf ) ;
int ret ;
2008-06-30 15:50:11 -03:00
PDEBUG ( D_PROBE , " probing %04x:%04x " , id - > idVendor , id - > idProduct ) ;
2008-04-12 09:58:09 -03:00
/* we don't handle multi-config cameras */
if ( dev - > descriptor . bNumConfigurations ! = 1 )
return - ENODEV ;
interface = & intf - > cur_altsetting - > desc ;
if ( interface - > bInterfaceNumber > 0 )
return - ENODEV ;
/* create the device */
if ( dev_size < sizeof * gspca_dev )
dev_size = sizeof * gspca_dev ;
gspca_dev = kzalloc ( dev_size , GFP_KERNEL ) ;
if ( gspca_dev = = NULL ) {
err ( " couldn't kzalloc gspca struct " ) ;
return - EIO ;
}
gspca_dev - > dev = dev ;
gspca_dev - > iface = interface - > bInterfaceNumber ;
2008-06-12 10:58:58 -03:00
gspca_dev - > nbalt = intf - > num_altsetting ;
2008-04-12 09:58:09 -03:00
gspca_dev - > sd_desc = sd_desc ;
/* gspca_dev->users = 0; (done by kzalloc) */
gspca_dev - > nbufread = 2 ;
/* configure the subdriver */
ret = gspca_dev - > sd_desc - > config ( gspca_dev , id ) ;
if ( ret < 0 )
goto out ;
ret = gspca_set_alt0 ( gspca_dev ) ;
if ( ret < 0 )
goto out ;
gspca_set_default_mode ( gspca_dev ) ;
mutex_init ( & gspca_dev - > usb_lock ) ;
mutex_init ( & gspca_dev - > read_lock ) ;
mutex_init ( & gspca_dev - > queue_lock ) ;
init_waitqueue_head ( & gspca_dev - > wq ) ;
/* init video stuff */
memcpy ( & gspca_dev - > vdev , & gspca_template , sizeof gspca_template ) ;
2008-07-20 06:31:39 -03:00
gspca_dev - > vdev . parent = & dev - > dev ;
2008-06-12 10:58:58 -03:00
memcpy ( & gspca_dev - > fops , & dev_fops , sizeof gspca_dev - > fops ) ;
gspca_dev - > vdev . fops = & gspca_dev - > fops ;
gspca_dev - > fops . owner = module ; /* module protection */
2008-04-12 09:58:09 -03:00
ret = video_register_device ( & gspca_dev - > vdev ,
VFL_TYPE_GRABBER ,
video_nr ) ;
if ( ret < 0 ) {
err ( " video_register_device err %d " , ret ) ;
goto out ;
}
gspca_dev - > present = 1 ;
usb_set_intfdata ( intf , gspca_dev ) ;
PDEBUG ( D_PROBE , " probe ok " ) ;
return 0 ;
out :
kfree ( gspca_dev ) ;
return ret ;
}
EXPORT_SYMBOL ( gspca_dev_probe ) ;
/*
* USB disconnection
*
* This function must be called by the sub - driver
* when the device disconnects , after the specific resources are freed .
*/
void gspca_disconnect ( struct usb_interface * intf )
{
2008-05-04 06:46:21 -03:00
struct gspca_dev * gspca_dev = usb_get_intfdata ( intf ) ;
2008-04-12 09:58:09 -03:00
if ( ! gspca_dev )
return ;
gspca_dev - > present = 0 ;
2008-04-23 08:09:12 -03:00
mutex_lock ( & gspca_dev - > queue_lock ) ;
mutex_lock ( & gspca_dev - > usb_lock ) ;
gspca_dev - > streaming = 0 ;
2008-06-12 10:58:58 -03:00
destroy_urbs ( gspca_dev ) ;
2008-04-12 09:58:09 -03:00
mutex_unlock ( & gspca_dev - > usb_lock ) ;
2008-04-23 08:09:12 -03:00
mutex_unlock ( & gspca_dev - > queue_lock ) ;
2008-04-12 09:58:09 -03:00
while ( gspca_dev - > users ! = 0 ) { /* wait until fully closed */
atomic_inc ( & gspca_dev - > nevent ) ;
wake_up_interruptible ( & gspca_dev - > wq ) ; /* wake processes */
schedule ( ) ;
}
/* We don't want people trying to open up the device */
video_unregister_device ( & gspca_dev - > vdev ) ;
/* Free the memory */
kfree ( gspca_dev ) ;
PDEBUG ( D_PROBE , " disconnect complete " ) ;
}
EXPORT_SYMBOL ( gspca_disconnect ) ;
2008-07-10 10:40:53 -03:00
/* -- cam driver utility functions -- */
/* auto gain and exposure algorithm based on the knee algorithm described here:
http : //ytse.tricolour.net/docs/LowLightOptimization.html
Returns 0 if no changes were made , 1 if the gain and or exposure settings
where changed . */
int gspca_auto_gain_n_exposure ( struct gspca_dev * gspca_dev , int avg_lum ,
int desired_avg_lum , int deadzone , int gain_knee , int exposure_knee )
{
int i , steps , gain , orig_gain , exposure , orig_exposure , autogain ;
const struct ctrl * gain_ctrl = NULL ;
const struct ctrl * exposure_ctrl = NULL ;
const struct ctrl * autogain_ctrl = NULL ;
int retval = 0 ;
for ( i = 0 ; i < gspca_dev - > sd_desc - > nctrls ; i + + ) {
if ( gspca_dev - > sd_desc - > ctrls [ i ] . qctrl . id = = V4L2_CID_GAIN )
gain_ctrl = & gspca_dev - > sd_desc - > ctrls [ i ] ;
if ( gspca_dev - > sd_desc - > ctrls [ i ] . qctrl . id = = V4L2_CID_EXPOSURE )
exposure_ctrl = & gspca_dev - > sd_desc - > ctrls [ i ] ;
if ( gspca_dev - > sd_desc - > ctrls [ i ] . qctrl . id = = V4L2_CID_AUTOGAIN )
autogain_ctrl = & gspca_dev - > sd_desc - > ctrls [ i ] ;
}
if ( ! gain_ctrl | | ! exposure_ctrl | | ! autogain_ctrl ) {
PDEBUG ( D_ERR , " Error: gspca_auto_gain_n_exposure called "
" on cam without (auto)gain/exposure " ) ;
return 0 ;
}
if ( gain_ctrl - > get ( gspca_dev , & gain ) | |
exposure_ctrl - > get ( gspca_dev , & exposure ) | |
autogain_ctrl - > get ( gspca_dev , & autogain ) | | ! autogain )
return 0 ;
orig_gain = gain ;
orig_exposure = exposure ;
/* If we are of a multiple of deadzone, do multiple steps to reach the
desired lumination fast ( with the risc of a slight overshoot ) */
steps = abs ( desired_avg_lum - avg_lum ) / deadzone ;
PDEBUG ( D_FRAM , " autogain: lum: %d, desired: %d, steps: %d \n " ,
avg_lum , desired_avg_lum , steps ) ;
for ( i = 0 ; i < steps ; i + + ) {
if ( avg_lum > desired_avg_lum ) {
if ( gain > gain_knee )
gain - - ;
else if ( exposure > exposure_knee )
exposure - - ;
else if ( gain > gain_ctrl - > qctrl . default_value )
gain - - ;
else if ( exposure > exposure_ctrl - > qctrl . minimum )
exposure - - ;
else if ( gain > gain_ctrl - > qctrl . minimum )
gain - - ;
else
break ;
} else {
if ( gain < gain_ctrl - > qctrl . default_value )
gain + + ;
else if ( exposure < exposure_knee )
exposure + + ;
else if ( gain < gain_knee )
gain + + ;
else if ( exposure < exposure_ctrl - > qctrl . maximum )
exposure + + ;
else if ( gain < gain_ctrl - > qctrl . maximum )
gain + + ;
else
break ;
}
}
if ( gain ! = orig_gain ) {
gain_ctrl - > set ( gspca_dev , gain ) ;
retval = 1 ;
}
if ( exposure ! = orig_exposure ) {
exposure_ctrl - > set ( gspca_dev , exposure ) ;
retval = 1 ;
}
return retval ;
}
EXPORT_SYMBOL ( gspca_auto_gain_n_exposure ) ;
2008-04-12 09:58:09 -03:00
/* -- module insert / remove -- */
static int __init gspca_init ( void )
{
info ( " main v%s registered " , version ) ;
return 0 ;
}
static void __exit gspca_exit ( void )
{
info ( " main deregistered " ) ;
}
module_init ( gspca_init ) ;
module_exit ( gspca_exit ) ;
2008-07-03 06:48:22 -03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2008-04-12 09:58:09 -03:00
module_param_named ( debug , gspca_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug ,
" Debug (bit) 0x01:error 0x02:probe 0x04:config "
2008-06-12 10:58:58 -03:00
" 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout "
" 0x0100: v4l2 " ) ;
2008-06-30 15:50:11 -03:00
# endif