2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-06-30 15:04:50 -03:00
/*
* uvc_isight . c - - USB Video Class driver - iSight support
*
* Copyright ( C ) 2006 - 2007
* Ivan N . Zlatev < contact @ i - nz . net >
2009-01-03 19:12:40 -03:00
* Copyright ( C ) 2008 - 2009
2010-09-20 06:10:10 -03:00
* Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
2008-06-30 15:04:50 -03:00
*/
# include <linux/usb.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include "uvcvideo.h"
/* Built-in iSight webcams implements most of UVC 1.0 except a
* different packet format . Instead of sending a header at the
* beginning of each isochronous transfer payload , the webcam sends a
* single header per image ( on its own in a packet ) , followed by
* packets containing data only .
*
* Offset Size ( bytes ) Description
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-01-04 13:08:56 -05:00
* 0x00 1 Header length
* 0x01 1 Flags ( UVC - compliant )
* 0x02 4 Always equal to ' 11223344 '
* 0x06 8 Always equal to ' deadbeefdeadface '
* 0x0e 16 Unknown
2008-06-30 15:04:50 -03:00
*
* The header can be prefixed by an optional , unknown - purpose byte .
*/
static int isight_decode ( struct uvc_video_queue * queue , struct uvc_buffer * buf ,
2018-01-16 12:45:36 -05:00
const u8 * data , unsigned int len )
2008-06-30 15:04:50 -03:00
{
2018-01-16 12:45:36 -05:00
static const u8 hdr [ ] = {
2008-06-30 15:04:50 -03:00
0x11 , 0x22 , 0x33 , 0x44 ,
0xde , 0xad , 0xbe , 0xef ,
0xde , 0xad , 0xfa , 0xce
} ;
unsigned int maxlen , nbytes ;
2018-01-16 12:45:36 -05:00
u8 * mem ;
2008-06-30 15:04:50 -03:00
int is_header = 0 ;
if ( buf = = NULL )
return 0 ;
if ( ( len > = 14 & & memcmp ( & data [ 2 ] , hdr , 12 ) = = 0 ) | |
( len > = 15 & & memcmp ( & data [ 3 ] , hdr , 12 ) = = 0 ) ) {
uvc_trace ( UVC_TRACE_FRAME , " iSight header found \n " ) ;
is_header = 1 ;
}
/* Synchronize to the input stream by waiting for a header packet. */
if ( buf - > state ! = UVC_BUF_STATE_ACTIVE ) {
if ( ! is_header ) {
uvc_trace ( UVC_TRACE_FRAME , " Dropping packet (out of "
" sync). \n " ) ;
return 0 ;
}
buf - > state = UVC_BUF_STATE_ACTIVE ;
}
/* Mark the buffer as done if we're at the beginning of a new frame.
*
* Empty buffers ( bytesused = = 0 ) don ' t trigger end of frame detection
* as it doesn ' t make sense to return an empty buffer .
*/
2011-10-24 11:49:19 -03:00
if ( is_header & & buf - > bytesused ! = 0 ) {
2008-06-30 15:04:50 -03:00
buf - > state = UVC_BUF_STATE_DONE ;
return - EAGAIN ;
}
/* Copy the video data to the buffer. Skip header packets, as they
* contain no data .
*/
if ( ! is_header ) {
2011-10-24 11:49:19 -03:00
maxlen = buf - > length - buf - > bytesused ;
mem = buf - > mem + buf - > bytesused ;
2008-06-30 15:04:50 -03:00
nbytes = min ( len , maxlen ) ;
memcpy ( mem , data , nbytes ) ;
2011-10-24 11:49:19 -03:00
buf - > bytesused + = nbytes ;
2008-06-30 15:04:50 -03:00
2011-10-24 11:49:19 -03:00
if ( len > maxlen | | buf - > bytesused = = buf - > length ) {
2008-06-30 15:04:50 -03:00
uvc_trace ( UVC_TRACE_FRAME , " Frame complete "
" (overflow). \n " ) ;
buf - > state = UVC_BUF_STATE_DONE ;
}
}
return 0 ;
}
2017-03-15 05:39:14 -04:00
void uvc_video_decode_isight ( struct uvc_urb * uvc_urb , struct uvc_buffer * buf ,
struct uvc_buffer * meta_buf )
2008-06-30 15:04:50 -03:00
{
2017-03-15 05:39:14 -04:00
struct urb * urb = uvc_urb - > urb ;
struct uvc_streaming * stream = uvc_urb - > stream ;
2008-06-30 15:04:50 -03:00
int ret , i ;
for ( i = 0 ; i < urb - > number_of_packets ; + + i ) {
if ( urb - > iso_frame_desc [ i ] . status < 0 ) {
uvc_trace ( UVC_TRACE_FRAME , " USB isochronous frame "
" lost (%d). \n " ,
urb - > iso_frame_desc [ i ] . status ) ;
}
/* Decode the payload packet.
* uvc_video_decode is entered twice when a frame transition
* has been detected because the end of frame can only be
* reliably detected when the first packet of the new frame
* is processed . The first pass detects the transition and
* closes the previous frame ' s buffer , the second pass
* processes the data of the first payload of the new frame .
*/
do {
2009-06-28 08:37:50 -03:00
ret = isight_decode ( & stream - > queue , buf ,
2008-06-30 15:04:50 -03:00
urb - > transfer_buffer +
urb - > iso_frame_desc [ i ] . offset ,
urb - > iso_frame_desc [ i ] . actual_length ) ;
if ( buf = = NULL )
break ;
if ( buf - > state = = UVC_BUF_STATE_DONE | |
buf - > state = = UVC_BUF_STATE_ERROR )
2009-06-28 08:37:50 -03:00
buf = uvc_queue_next_buffer ( & stream - > queue ,
buf ) ;
2008-06-30 15:04:50 -03:00
} while ( ret = = - EAGAIN ) ;
}
}