2005-04-16 15:20:36 -07:00
/*
* cpia_usb CPiA USB driver
*
* Supports CPiA based parallel port Video Camera ' s .
*
* Copyright ( C ) 1999 Jochen Scharrlach < Jochen . Scharrlach @ schwaben . de >
* Copyright ( C ) 1999 , 2000 Johannes Erdfelt < johannes @ erdfelt . 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
* ( 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 _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
2006-03-25 09:19:53 -03:00
/* #define _CPIA_DEBUG_ 1 */
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/wait.h>
# include <linux/list.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/usb.h>
# include "cpia.h"
# define USB_REQ_CPIA_GRAB_FRAME 0xC1
# define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
# define WAIT_FOR_NEXT_FRAME 0
# define FORCE_FRAME_UPLOAD 1
# define FRAMES_PER_DESC 10
# define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
# define CPIA_NUMSBUF 2
# define STREAM_BUF_SIZE (PAGE_SIZE * 4)
# define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
struct cpia_sbuf {
char * data ;
struct urb * urb ;
} ;
# define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
enum framebuf_status {
FRAME_EMPTY ,
FRAME_READING ,
FRAME_READY ,
FRAME_ERROR ,
} ;
struct framebuf {
int length ;
enum framebuf_status status ;
u8 data [ FRAMEBUF_LEN ] ;
struct framebuf * next ;
} ;
struct usb_cpia {
/* Device structure */
struct usb_device * dev ;
unsigned char iface ;
wait_queue_head_t wq_stream ;
int cursbuf ; /* Current receiving sbuf */
struct cpia_sbuf sbuf [ CPIA_NUMSBUF ] ; /* Double buffering */
int streaming ;
int open ;
int present ;
struct framebuf * buffers [ 3 ] ;
struct framebuf * curbuff , * workbuff ;
} ;
static int cpia_usb_open ( void * privdata ) ;
static int cpia_usb_registerCallback ( void * privdata , void ( * cb ) ( void * cbdata ) ,
2006-03-25 09:19:53 -03:00
void * cbdata ) ;
2005-04-16 15:20:36 -07:00
static int cpia_usb_transferCmd ( void * privdata , u8 * command , u8 * data ) ;
static int cpia_usb_streamStart ( void * privdata ) ;
static int cpia_usb_streamStop ( void * privdata ) ;
static int cpia_usb_streamRead ( void * privdata , u8 * frame , int noblock ) ;
static int cpia_usb_close ( void * privdata ) ;
# define ABOUT "USB driver for Vision CPiA based cameras"
static struct cpia_camera_ops cpia_usb_ops = {
cpia_usb_open ,
cpia_usb_registerCallback ,
cpia_usb_transferCmd ,
cpia_usb_streamStart ,
cpia_usb_streamStop ,
cpia_usb_streamRead ,
cpia_usb_close ,
0 ,
THIS_MODULE
} ;
static LIST_HEAD ( cam_list ) ;
static spinlock_t cam_list_lock_usb ;
static void cpia_usb_complete ( struct urb * urb , struct pt_regs * regs )
{
int i ;
char * cdata ;
struct usb_cpia * ucpia ;
if ( ! urb | | ! urb - > context )
return ;
ucpia = ( struct usb_cpia * ) urb - > context ;
if ( ! ucpia - > dev | | ! ucpia - > streaming | | ! ucpia - > present | | ! ucpia - > open )
return ;
if ( ucpia - > workbuff - > status = = FRAME_EMPTY ) {
ucpia - > workbuff - > status = FRAME_READING ;
ucpia - > workbuff - > length = 0 ;
}
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < urb - > number_of_packets ; i + + ) {
int n = urb - > iso_frame_desc [ i ] . actual_length ;
int st = urb - > iso_frame_desc [ i ] . status ;
cdata = urb - > transfer_buffer + urb - > iso_frame_desc [ i ] . offset ;
if ( st )
printk ( KERN_DEBUG " cpia data error: [%d] len=%d, status=%X \n " , i , n , st ) ;
if ( FRAMEBUF_LEN < ucpia - > workbuff - > length + n ) {
printk ( KERN_DEBUG " cpia: scratch buf overflow!scr_len: %d, n: %d \n " , ucpia - > workbuff - > length , n ) ;
return ;
}
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( n ) {
2006-03-25 09:19:53 -03:00
if ( ( ucpia - > workbuff - > length > 0 ) | |
2005-04-16 15:20:36 -07:00
( 0x19 = = cdata [ 0 ] & & 0x68 = = cdata [ 1 ] ) ) {
memcpy ( ucpia - > workbuff - > data + ucpia - > workbuff - > length , cdata , n ) ;
ucpia - > workbuff - > length + = n ;
} else
DBG ( " Ignoring packet! \n " ) ;
} else {
if ( ucpia - > workbuff - > length > 4 & &
0xff = = ucpia - > workbuff - > data [ ucpia - > workbuff - > length - 1 ] & &
0xff = = ucpia - > workbuff - > data [ ucpia - > workbuff - > length - 2 ] & &
0xff = = ucpia - > workbuff - > data [ ucpia - > workbuff - > length - 3 ] & &
0xff = = ucpia - > workbuff - > data [ ucpia - > workbuff - > length - 4 ] ) {
ucpia - > workbuff - > status = FRAME_READY ;
ucpia - > curbuff = ucpia - > workbuff ;
ucpia - > workbuff = ucpia - > workbuff - > next ;
ucpia - > workbuff - > status = FRAME_EMPTY ;
ucpia - > workbuff - > length = 0 ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( waitqueue_active ( & ucpia - > wq_stream ) )
wake_up_interruptible ( & ucpia - > wq_stream ) ;
}
}
}
/* resubmit */
urb - > dev = ucpia - > dev ;
if ( ( i = usb_submit_urb ( urb , GFP_ATOMIC ) ) ! = 0 )
printk ( KERN_ERR " %s: usb_submit_urb ret %d \n " , __FUNCTION__ , i ) ;
}
static int cpia_usb_open ( void * privdata )
{
struct usb_cpia * ucpia = ( struct usb_cpia * ) privdata ;
struct urb * urb ;
int ret , retval = 0 , fx , err ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( ! ucpia )
return - EINVAL ;
ucpia - > sbuf [ 0 ] . data = kmalloc ( FRAMES_PER_DESC * FRAME_SIZE_PER_DESC , GFP_KERNEL ) ;
if ( ! ucpia - > sbuf [ 0 ] . data )
return - EINVAL ;
ucpia - > sbuf [ 1 ] . data = kmalloc ( FRAMES_PER_DESC * FRAME_SIZE_PER_DESC , GFP_KERNEL ) ;
if ( ! ucpia - > sbuf [ 1 ] . data ) {
retval = - EINVAL ;
goto error_0 ;
}
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
ret = usb_set_interface ( ucpia - > dev , ucpia - > iface , 3 ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " cpia_usb_open: usb_set_interface error (ret = %d) \n " , ret ) ;
retval = - EBUSY ;
goto error_1 ;
}
ucpia - > buffers [ 0 ] - > status = FRAME_EMPTY ;
ucpia - > buffers [ 0 ] - > length = 0 ;
ucpia - > buffers [ 1 ] - > status = FRAME_EMPTY ;
ucpia - > buffers [ 1 ] - > length = 0 ;
ucpia - > buffers [ 2 ] - > status = FRAME_EMPTY ;
ucpia - > buffers [ 2 ] - > length = 0 ;
ucpia - > curbuff = ucpia - > buffers [ 0 ] ;
ucpia - > workbuff = ucpia - > buffers [ 1 ] ;
/* We double buffer the Iso lists, and also know the polling
* interval is every frame ( 1 = = ( 1 < < ( bInterval - 1 ) ) ) .
*/
urb = usb_alloc_urb ( FRAMES_PER_DESC , GFP_KERNEL ) ;
if ( ! urb ) {
printk ( KERN_ERR " cpia_init_isoc: usb_alloc_urb 0 \n " ) ;
retval = - ENOMEM ;
goto error_1 ;
}
ucpia - > sbuf [ 0 ] . urb = urb ;
urb - > dev = ucpia - > dev ;
urb - > context = ucpia ;
urb - > pipe = usb_rcvisocpipe ( ucpia - > dev , 1 ) ;
urb - > transfer_flags = URB_ISO_ASAP ;
urb - > transfer_buffer = ucpia - > sbuf [ 0 ] . data ;
urb - > complete = cpia_usb_complete ;
urb - > number_of_packets = FRAMES_PER_DESC ;
urb - > interval = 1 ;
urb - > transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC ;
for ( fx = 0 ; fx < FRAMES_PER_DESC ; fx + + ) {
urb - > iso_frame_desc [ fx ] . offset = FRAME_SIZE_PER_DESC * fx ;
urb - > iso_frame_desc [ fx ] . length = FRAME_SIZE_PER_DESC ;
}
urb = usb_alloc_urb ( FRAMES_PER_DESC , GFP_KERNEL ) ;
if ( ! urb ) {
printk ( KERN_ERR " cpia_init_isoc: usb_alloc_urb 1 \n " ) ;
retval = - ENOMEM ;
goto error_urb0 ;
}
ucpia - > sbuf [ 1 ] . urb = urb ;
urb - > dev = ucpia - > dev ;
urb - > context = ucpia ;
urb - > pipe = usb_rcvisocpipe ( ucpia - > dev , 1 ) ;
urb - > transfer_flags = URB_ISO_ASAP ;
urb - > transfer_buffer = ucpia - > sbuf [ 1 ] . data ;
urb - > complete = cpia_usb_complete ;
urb - > number_of_packets = FRAMES_PER_DESC ;
urb - > interval = 1 ;
urb - > transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC ;
for ( fx = 0 ; fx < FRAMES_PER_DESC ; fx + + ) {
urb - > iso_frame_desc [ fx ] . offset = FRAME_SIZE_PER_DESC * fx ;
urb - > iso_frame_desc [ fx ] . length = FRAME_SIZE_PER_DESC ;
}
/* queue the ISO urbs, and resubmit in the completion handler */
err = usb_submit_urb ( ucpia - > sbuf [ 0 ] . urb , GFP_KERNEL ) ;
if ( err ) {
printk ( KERN_ERR " cpia_init_isoc: usb_submit_urb 0 ret %d \n " ,
err ) ;
goto error_urb1 ;
}
err = usb_submit_urb ( ucpia - > sbuf [ 1 ] . urb , GFP_KERNEL ) ;
if ( err ) {
printk ( KERN_ERR " cpia_init_isoc: usb_submit_urb 1 ret %d \n " ,
err ) ;
goto error_urb1 ;
}
ucpia - > streaming = 1 ;
ucpia - > open = 1 ;
return 0 ;
error_urb1 : /* free urb 1 */
usb_free_urb ( ucpia - > sbuf [ 1 ] . urb ) ;
ucpia - > sbuf [ 1 ] . urb = NULL ;
error_urb0 : /* free urb 0 */
usb_free_urb ( ucpia - > sbuf [ 0 ] . urb ) ;
ucpia - > sbuf [ 0 ] . urb = NULL ;
error_1 :
kfree ( ucpia - > sbuf [ 1 ] . data ) ;
ucpia - > sbuf [ 1 ] . data = NULL ;
error_0 :
kfree ( ucpia - > sbuf [ 0 ] . data ) ;
ucpia - > sbuf [ 0 ] . data = NULL ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
return retval ;
}
//
// convenience functions
//
/****************************************************************************
*
* WritePacket
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int WritePacket ( struct usb_device * udev , const u8 * packet , u8 * buf , size_t size )
{
if ( ! packet )
return - EINVAL ;
return usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
packet [ 1 ] + ( packet [ 0 ] < < 8 ) ,
USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
2006-03-25 09:19:53 -03:00
packet [ 2 ] + ( packet [ 3 ] < < 8 ) ,
2005-04-16 15:20:36 -07:00
packet [ 4 ] + ( packet [ 5 ] < < 8 ) , buf , size , 1000 ) ;
}
/****************************************************************************
*
* ReadPacket
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int ReadPacket ( struct usb_device * udev , u8 * packet , u8 * buf , size_t size )
{
if ( ! packet | | size < = 0 )
return - EINVAL ;
return usb_control_msg ( udev , usb_rcvctrlpipe ( udev , 0 ) ,
packet [ 1 ] + ( packet [ 0 ] < < 8 ) ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
2006-03-25 09:19:53 -03:00
packet [ 2 ] + ( packet [ 3 ] < < 8 ) ,
2005-04-16 15:20:36 -07:00
packet [ 4 ] + ( packet [ 5 ] < < 8 ) , buf , size , 1000 ) ;
}
static int cpia_usb_transferCmd ( void * privdata , u8 * command , u8 * data )
{
int err = 0 ;
int databytes ;
struct usb_cpia * ucpia = ( struct usb_cpia * ) privdata ;
struct usb_device * udev = ucpia - > dev ;
if ( ! udev ) {
DBG ( " Internal driver error: udev is NULL \n " ) ;
return - EINVAL ;
}
if ( ! command ) {
DBG ( " Internal driver error: command is NULL \n " ) ;
return - EINVAL ;
}
databytes = ( ( ( int ) command [ 7 ] ) < < 8 ) | command [ 6 ] ;
if ( command [ 0 ] = = DATA_IN ) {
u8 buffer [ 8 ] ;
if ( ! data ) {
DBG ( " Internal driver error: data is NULL \n " ) ;
return - EINVAL ;
}
err = ReadPacket ( udev , command , buffer , 8 ) ;
if ( err < 0 )
return err ;
memcpy ( data , buffer , databytes ) ;
} else if ( command [ 0 ] = = DATA_OUT )
WritePacket ( udev , command , data , databytes ) ;
else {
DBG ( " Unexpected first byte of command: %x \n " , command [ 0 ] ) ;
err = - EINVAL ;
}
return 0 ;
}
static int cpia_usb_registerCallback ( void * privdata , void ( * cb ) ( void * cbdata ) ,
void * cbdata )
{
return - ENODEV ;
}
static int cpia_usb_streamStart ( void * privdata )
{
return - ENODEV ;
}
static int cpia_usb_streamStop ( void * privdata )
{
return - ENODEV ;
}
static int cpia_usb_streamRead ( void * privdata , u8 * frame , int noblock )
{
struct usb_cpia * ucpia = ( struct usb_cpia * ) privdata ;
struct framebuf * mybuff ;
if ( ! ucpia | | ! ucpia - > present )
return - 1 ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( ucpia - > curbuff - > status ! = FRAME_READY )
interruptible_sleep_on ( & ucpia - > wq_stream ) ;
else
DBG ( " Frame already waiting! \n " ) ;
mybuff = ucpia - > curbuff ;
if ( ! mybuff )
return - 1 ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( mybuff - > status ! = FRAME_READY | | mybuff - > length < 4 ) {
DBG ( " Something went wrong! \n " ) ;
return - 1 ;
}
memcpy ( frame , mybuff - > data , mybuff - > length ) ;
mybuff - > status = FRAME_EMPTY ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
/* mybuff->length, frame[0], frame[1], */
/* frame[mybuff->length-4], frame[mybuff->length-3], */
/* frame[mybuff->length-2], frame[mybuff->length-1]); */
return mybuff - > length ;
}
static void cpia_usb_free_resources ( struct usb_cpia * ucpia , int try )
{
if ( ! ucpia - > streaming )
return ;
ucpia - > streaming = 0 ;
/* Set packet size to 0 */
if ( try ) {
int ret ;
ret = usb_set_interface ( ucpia - > dev , ucpia - > iface , 0 ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " usb_set_interface error (ret = %d) \n " , ret ) ;
return ;
}
}
/* Unschedule all of the iso td's */
if ( ucpia - > sbuf [ 1 ] . urb ) {
usb_kill_urb ( ucpia - > sbuf [ 1 ] . urb ) ;
usb_free_urb ( ucpia - > sbuf [ 1 ] . urb ) ;
ucpia - > sbuf [ 1 ] . urb = NULL ;
}
2005-09-10 00:26:54 -07:00
kfree ( ucpia - > sbuf [ 1 ] . data ) ;
ucpia - > sbuf [ 1 ] . data = NULL ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( ucpia - > sbuf [ 0 ] . urb ) {
usb_kill_urb ( ucpia - > sbuf [ 0 ] . urb ) ;
usb_free_urb ( ucpia - > sbuf [ 0 ] . urb ) ;
ucpia - > sbuf [ 0 ] . urb = NULL ;
}
2005-09-10 00:26:54 -07:00
kfree ( ucpia - > sbuf [ 0 ] . data ) ;
ucpia - > sbuf [ 0 ] . data = NULL ;
2005-04-16 15:20:36 -07:00
}
static int cpia_usb_close ( void * privdata )
{
struct usb_cpia * ucpia = ( struct usb_cpia * ) privdata ;
if ( ! ucpia )
return - ENODEV ;
ucpia - > open = 0 ;
/* ucpia->present = 0 protects against trying to reset the
* alt setting if camera is physically disconnected while open */
cpia_usb_free_resources ( ucpia , ucpia - > present ) ;
return 0 ;
}
/* Probing and initializing */
static int cpia_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_device * udev = interface_to_usbdev ( intf ) ;
struct usb_host_interface * interface ;
struct usb_cpia * ucpia ;
struct cam_data * cam ;
int ret ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
/* A multi-config CPiA camera? */
if ( udev - > descriptor . bNumConfigurations ! = 1 )
return - ENODEV ;
interface = intf - > cur_altsetting ;
printk ( KERN_INFO " USB CPiA camera found \n " ) ;
2006-01-11 19:40:56 -02:00
ucpia = kzalloc ( sizeof ( * ucpia ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! ucpia ) {
printk ( KERN_ERR " couldn't kmalloc cpia struct \n " ) ;
return - ENOMEM ;
}
ucpia - > dev = udev ;
ucpia - > iface = interface - > desc . bInterfaceNumber ;
init_waitqueue_head ( & ucpia - > wq_stream ) ;
ucpia - > buffers [ 0 ] = vmalloc ( sizeof ( * ucpia - > buffers [ 0 ] ) ) ;
if ( ! ucpia - > buffers [ 0 ] ) {
printk ( KERN_ERR " couldn't vmalloc frame buffer 0 \n " ) ;
goto fail_alloc_0 ;
}
ucpia - > buffers [ 1 ] = vmalloc ( sizeof ( * ucpia - > buffers [ 1 ] ) ) ;
if ( ! ucpia - > buffers [ 1 ] ) {
printk ( KERN_ERR " couldn't vmalloc frame buffer 1 \n " ) ;
goto fail_alloc_1 ;
}
ucpia - > buffers [ 2 ] = vmalloc ( sizeof ( * ucpia - > buffers [ 2 ] ) ) ;
if ( ! ucpia - > buffers [ 2 ] ) {
printk ( KERN_ERR " couldn't vmalloc frame buffer 2 \n " ) ;
goto fail_alloc_2 ;
}
ucpia - > buffers [ 0 ] - > next = ucpia - > buffers [ 1 ] ;
ucpia - > buffers [ 1 ] - > next = ucpia - > buffers [ 2 ] ;
ucpia - > buffers [ 2 ] - > next = ucpia - > buffers [ 0 ] ;
ret = usb_set_interface ( udev , ucpia - > iface , 0 ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " cpia_probe: usb_set_interface error (ret = %d) \n " , ret ) ;
/* goto fail_all; */
}
/* Before register_camera, important */
ucpia - > present = 1 ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
cam = cpia_register_camera ( & cpia_usb_ops , ucpia ) ;
if ( ! cam ) {
LOG ( " failed to cpia_register_camera \n " ) ;
goto fail_all ;
}
spin_lock ( & cam_list_lock_usb ) ;
list_add ( & cam - > cam_data_list , & cam_list ) ;
spin_unlock ( & cam_list_lock_usb ) ;
usb_set_intfdata ( intf , cam ) ;
return 0 ;
fail_all :
vfree ( ucpia - > buffers [ 2 ] ) ;
ucpia - > buffers [ 2 ] = NULL ;
fail_alloc_2 :
vfree ( ucpia - > buffers [ 1 ] ) ;
ucpia - > buffers [ 1 ] = NULL ;
fail_alloc_1 :
vfree ( ucpia - > buffers [ 0 ] ) ;
ucpia - > buffers [ 0 ] = NULL ;
fail_alloc_0 :
kfree ( ucpia ) ;
return - EIO ;
}
static void cpia_disconnect ( struct usb_interface * intf ) ;
static struct usb_device_id cpia_id_table [ ] = {
{ USB_DEVICE ( 0x0553 , 0x0002 ) } ,
{ USB_DEVICE ( 0x0813 , 0x0001 ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , cpia_id_table ) ;
MODULE_LICENSE ( " GPL " ) ;
static struct usb_driver cpia_driver = {
. name = " cpia " ,
. probe = cpia_probe ,
. disconnect = cpia_disconnect ,
. id_table = cpia_id_table ,
} ;
static void cpia_disconnect ( struct usb_interface * intf )
{
struct cam_data * cam = usb_get_intfdata ( intf ) ;
struct usb_cpia * ucpia ;
struct usb_device * udev ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
usb_set_intfdata ( intf , NULL ) ;
if ( ! cam )
return ;
ucpia = ( struct usb_cpia * ) cam - > lowlevel_data ;
spin_lock ( & cam_list_lock_usb ) ;
list_del ( & cam - > cam_data_list ) ;
spin_unlock ( & cam_list_lock_usb ) ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
ucpia - > present = 0 ;
cpia_unregister_camera ( cam ) ;
if ( ucpia - > open )
cpia_usb_close ( cam - > lowlevel_data ) ;
ucpia - > curbuff - > status = FRAME_ERROR ;
if ( waitqueue_active ( & ucpia - > wq_stream ) )
wake_up_interruptible ( & ucpia - > wq_stream ) ;
udev = interface_to_usbdev ( intf ) ;
ucpia - > curbuff = ucpia - > workbuff = NULL ;
2005-09-10 00:26:54 -07:00
vfree ( ucpia - > buffers [ 2 ] ) ;
ucpia - > buffers [ 2 ] = NULL ;
2005-04-16 15:20:36 -07:00
2005-09-10 00:26:54 -07:00
vfree ( ucpia - > buffers [ 1 ] ) ;
ucpia - > buffers [ 1 ] = NULL ;
2005-04-16 15:20:36 -07:00
2005-09-10 00:26:54 -07:00
vfree ( ucpia - > buffers [ 0 ] ) ;
ucpia - > buffers [ 0 ] = NULL ;
2005-04-16 15:20:36 -07:00
cam - > lowlevel_data = NULL ;
kfree ( ucpia ) ;
}
static int __init usb_cpia_init ( void )
{
2006-03-25 09:19:53 -03:00
printk ( KERN_INFO " %s v%d.%d.%d \n " , ABOUT ,
2005-04-16 15:20:36 -07:00
CPIA_USB_MAJ_VER , CPIA_USB_MIN_VER , CPIA_USB_PATCH_VER ) ;
spin_lock_init ( & cam_list_lock_usb ) ;
return usb_register ( & cpia_driver ) ;
}
static void __exit usb_cpia_cleanup ( void )
{
usb_deregister ( & cpia_driver ) ;
}
module_init ( usb_cpia_init ) ;
module_exit ( usb_cpia_cleanup ) ;