2005-04-16 15:20:36 -07:00
/*****************************************************************************/
/*
* dabusb . c - - dab usb driver .
*
* Copyright ( C ) 1999 Deti Fliegl ( deti @ fliegl . de )
*
* 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 .
*
*
*
* $ Id : dabusb . c , v 1.54 2000 / 07 / 24 21 : 39 : 39 deti Exp $
*
*/
/*****************************************************************************/
# include <linux/module.h>
# include <linux/socket.h>
# include <linux/list.h>
# include <linux/vmalloc.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <asm/uaccess.h>
# include <asm/atomic.h>
# include <linux/delay.h>
# include <linux/usb.h>
# include <linux/smp_lock.h>
2006-01-11 15:55:29 +01:00
# include <linux/mutex.h>
2005-04-16 15:20:36 -07:00
# include "dabusb.h"
# include "dabfirmware.h"
/*
* Version Information
*/
# define DRIVER_VERSION "v1.54"
# define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
# define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
/* --------------------------------------------------------------------- */
# ifdef CONFIG_USB_DYNAMIC_MINORS
# define NRDABUSB 256
# else
# define NRDABUSB 4
# endif
/*-------------------------------------------------------------------*/
static dabusb_t dabusb [ NRDABUSB ] ;
static int buffers = 256 ;
static struct usb_driver dabusb_driver ;
/*-------------------------------------------------------------------*/
static int dabusb_add_buf_tail ( pdabusb_t s , struct list_head * dst , struct list_head * src )
{
unsigned long flags ;
struct list_head * tmp ;
int ret = 0 ;
spin_lock_irqsave ( & s - > lock , flags ) ;
if ( list_empty ( src ) ) {
// no elements in source buffer
ret = - 1 ;
goto err ;
}
tmp = src - > next ;
list_move_tail ( tmp , dst ) ;
err : spin_unlock_irqrestore ( & s - > lock , flags ) ;
return ret ;
}
/*-------------------------------------------------------------------*/
2006-03-25 09:19:53 -03:00
# ifdef DEBUG
2005-04-16 15:20:36 -07:00
static void dump_urb ( struct urb * urb )
{
dbg ( " urb :%p " , urb ) ;
dbg ( " dev :%p " , urb - > dev ) ;
dbg ( " pipe :%08X " , urb - > pipe ) ;
dbg ( " status :%d " , urb - > status ) ;
dbg ( " transfer_flags :%08X " , urb - > transfer_flags ) ;
dbg ( " transfer_buffer :%p " , urb - > transfer_buffer ) ;
dbg ( " transfer_buffer_length:%d " , urb - > transfer_buffer_length ) ;
dbg ( " actual_length :%d " , urb - > actual_length ) ;
dbg ( " setup_packet :%p " , urb - > setup_packet ) ;
dbg ( " start_frame :%d " , urb - > start_frame ) ;
dbg ( " number_of_packets :%d " , urb - > number_of_packets ) ;
dbg ( " interval :%d " , urb - > interval ) ;
dbg ( " error_count :%d " , urb - > error_count ) ;
dbg ( " context :%p " , urb - > context ) ;
dbg ( " complete :%p " , urb - > complete ) ;
}
# endif
/*-------------------------------------------------------------------*/
static int dabusb_cancel_queue ( pdabusb_t s , struct list_head * q )
{
unsigned long flags ;
pbuff_t b ;
dbg ( " dabusb_cancel_queue " ) ;
spin_lock_irqsave ( & s - > lock , flags ) ;
list_for_each_entry ( b , q , buff_list ) {
# ifdef DEBUG
dump_urb ( b - > purb ) ;
# endif
usb_unlink_urb ( b - > purb ) ;
}
spin_unlock_irqrestore ( & s - > lock , flags ) ;
return 0 ;
}
/*-------------------------------------------------------------------*/
static int dabusb_free_queue ( struct list_head * q )
{
struct list_head * tmp ;
struct list_head * p ;
pbuff_t b ;
dbg ( " dabusb_free_queue " ) ;
for ( p = q - > next ; p ! = q ; ) {
b = list_entry ( p , buff_t , buff_list ) ;
2006-03-25 09:19:53 -03:00
# ifdef DEBUG
2005-04-16 15:20:36 -07:00
dump_urb ( b - > purb ) ;
# endif
2005-04-18 17:39:34 -07:00
kfree ( b - > purb - > transfer_buffer ) ;
2005-04-16 15:20:36 -07:00
usb_free_urb ( b - > purb ) ;
tmp = p - > next ;
list_del ( p ) ;
kfree ( b ) ;
p = tmp ;
}
return 0 ;
}
/*-------------------------------------------------------------------*/
static int dabusb_free_buffers ( pdabusb_t s )
{
unsigned long flags ;
dbg ( " dabusb_free_buffers " ) ;
spin_lock_irqsave ( & s - > lock , flags ) ;
dabusb_free_queue ( & s - > free_buff_list ) ;
dabusb_free_queue ( & s - > rec_buff_list ) ;
spin_unlock_irqrestore ( & s - > lock , flags ) ;
s - > got_mem = 0 ;
return 0 ;
}
/*-------------------------------------------------------------------*/
static void dabusb_iso_complete ( struct urb * purb , struct pt_regs * regs )
{
pbuff_t b = purb - > context ;
pdabusb_t s = b - > s ;
int i ;
int len ;
int dst = 0 ;
void * buf = purb - > transfer_buffer ;
dbg ( " dabusb_iso_complete " ) ;
// process if URB was not killed
if ( purb - > status ! = - ENOENT ) {
unsigned int pipe = usb_rcvisocpipe ( purb - > dev , _DABUSB_ISOPIPE ) ;
int pipesize = usb_maxpacket ( purb - > dev , pipe , usb_pipeout ( pipe ) ) ;
for ( i = 0 ; i < purb - > number_of_packets ; i + + )
if ( ! purb - > iso_frame_desc [ i ] . status ) {
len = purb - > iso_frame_desc [ i ] . actual_length ;
if ( len < = pipesize ) {
memcpy ( buf + dst , buf + purb - > iso_frame_desc [ i ] . offset , len ) ;
dst + = len ;
}
else
err ( " dabusb_iso_complete: invalid len %d " , len ) ;
}
else
warn ( " dabusb_iso_complete: corrupted packet status: %d " , purb - > iso_frame_desc [ i ] . status ) ;
if ( dst ! = purb - > actual_length )
err ( " dst!=purb->actual_length:%d!=%d " , dst , purb - > actual_length ) ;
}
if ( atomic_dec_and_test ( & s - > pending_io ) & & ! s - > remove_pending & & s - > state ! = _stopped ) {
s - > overruns + + ;
err ( " overrun (%d) " , s - > overruns ) ;
}
wake_up ( & s - > wait ) ;
}
/*-------------------------------------------------------------------*/
static int dabusb_alloc_buffers ( pdabusb_t s )
{
int buffers = 0 ;
pbuff_t b ;
unsigned int pipe = usb_rcvisocpipe ( s - > usbdev , _DABUSB_ISOPIPE ) ;
int pipesize = usb_maxpacket ( s - > usbdev , pipe , usb_pipeout ( pipe ) ) ;
int packets = _ISOPIPESIZE / pipesize ;
int transfer_buffer_length = packets * pipesize ;
int i ;
dbg ( " dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d " ,
pipesize , packets , transfer_buffer_length ) ;
while ( buffers < ( s - > total_buffer_size < < 10 ) ) {
2006-01-06 21:01:47 +01:00
b = ( pbuff_t ) kzalloc ( sizeof ( buff_t ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! b ) {
2006-01-06 21:01:47 +01:00
err ( " kzalloc(sizeof(buff_t))==NULL " ) ;
2005-04-16 15:20:36 -07:00
goto err ;
}
b - > s = s ;
b - > purb = usb_alloc_urb ( packets , GFP_KERNEL ) ;
if ( ! b - > purb ) {
err ( " usb_alloc_urb == NULL " ) ;
kfree ( b ) ;
goto err ;
}
b - > purb - > transfer_buffer = kmalloc ( transfer_buffer_length , GFP_KERNEL ) ;
if ( ! b - > purb - > transfer_buffer ) {
kfree ( b - > purb ) ;
kfree ( b ) ;
err ( " kmalloc(%d)==NULL " , transfer_buffer_length ) ;
goto err ;
}
b - > purb - > transfer_buffer_length = transfer_buffer_length ;
b - > purb - > number_of_packets = packets ;
b - > purb - > complete = dabusb_iso_complete ;
b - > purb - > context = b ;
b - > purb - > dev = s - > usbdev ;
b - > purb - > pipe = pipe ;
b - > purb - > transfer_flags = URB_ISO_ASAP ;
for ( i = 0 ; i < packets ; i + + ) {
b - > purb - > iso_frame_desc [ i ] . offset = i * pipesize ;
b - > purb - > iso_frame_desc [ i ] . length = pipesize ;
}
buffers + = transfer_buffer_length ;
list_add_tail ( & b - > buff_list , & s - > free_buff_list ) ;
}
s - > got_mem = buffers ;
return 0 ;
err :
dabusb_free_buffers ( s ) ;
return - ENOMEM ;
}
/*-------------------------------------------------------------------*/
static int dabusb_bulk ( pdabusb_t s , pbulk_transfer_t pb )
{
int ret ;
unsigned int pipe ;
int actual_length ;
dbg ( " dabusb_bulk " ) ;
if ( ! pb - > pipe )
pipe = usb_rcvbulkpipe ( s - > usbdev , 2 ) ;
else
pipe = usb_sndbulkpipe ( s - > usbdev , 2 ) ;
ret = usb_bulk_msg ( s - > usbdev , pipe , pb - > data , pb - > size , & actual_length , 100 ) ;
if ( ret < 0 ) {
err ( " dabusb: usb_bulk_msg failed(%d) " , ret ) ;
if ( usb_set_interface ( s - > usbdev , _DABUSB_IF , 1 ) < 0 ) {
err ( " set_interface failed " ) ;
return - EINVAL ;
}
}
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
if ( ret = = - EPIPE ) {
warn ( " CLEAR_FEATURE request to remove STALL condition. " ) ;
if ( usb_clear_halt ( s - > usbdev , usb_pipeendpoint ( pipe ) ) )
err ( " request failed " ) ;
}
pb - > size = actual_length ;
return ret ;
}
/* --------------------------------------------------------------------- */
static int dabusb_writemem ( pdabusb_t s , int pos , unsigned char * data , int len )
{
int ret ;
unsigned char * transfer_buffer = kmalloc ( len , GFP_KERNEL ) ;
if ( ! transfer_buffer ) {
err ( " dabusb_writemem: kmalloc(%d) failed. " , len ) ;
return - ENOMEM ;
}
memcpy ( transfer_buffer , data , len ) ;
ret = usb_control_msg ( s - > usbdev , usb_sndctrlpipe ( s - > usbdev , 0 ) , 0xa0 , 0x40 , pos , 0 , transfer_buffer , len , 300 ) ;
kfree ( transfer_buffer ) ;
return ret ;
}
/* --------------------------------------------------------------------- */
static int dabusb_8051_reset ( pdabusb_t s , unsigned char reset_bit )
{
dbg ( " dabusb_8051_reset: %d " , reset_bit ) ;
return dabusb_writemem ( s , CPUCS_REG , & reset_bit , 1 ) ;
}
/* --------------------------------------------------------------------- */
static int dabusb_loadmem ( pdabusb_t s , const char * fname )
{
int ret ;
PINTEL_HEX_RECORD ptr = firmware ;
dbg ( " Enter dabusb_loadmem (internal) " ) ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
ret = dabusb_8051_reset ( s , 1 ) ;
while ( ptr - > Type = = 0 ) {
dbg ( " dabusb_writemem: %04X %p %d) " , ptr - > Address , ptr - > Data , ptr - > Length ) ;
ret = dabusb_writemem ( s , ptr - > Address , ptr - > Data , ptr - > Length ) ;
if ( ret < 0 ) {
err ( " dabusb_writemem failed (%d %04X %p %d) " , ret , ptr - > Address , ptr - > Data , ptr - > Length ) ;
break ;
}
ptr + + ;
}
ret = dabusb_8051_reset ( s , 0 ) ;
dbg ( " dabusb_loadmem: exit " ) ;
return ret ;
}
/* --------------------------------------------------------------------- */
static int dabusb_fpga_clear ( pdabusb_t s , pbulk_transfer_t b )
{
b - > size = 4 ;
b - > data [ 0 ] = 0x2a ;
b - > data [ 1 ] = 0 ;
b - > data [ 2 ] = 0 ;
b - > data [ 3 ] = 0 ;
dbg ( " dabusb_fpga_clear " ) ;
return dabusb_bulk ( s , b ) ;
}
/* --------------------------------------------------------------------- */
static int dabusb_fpga_init ( pdabusb_t s , pbulk_transfer_t b )
{
b - > size = 4 ;
b - > data [ 0 ] = 0x2c ;
b - > data [ 1 ] = 0 ;
b - > data [ 2 ] = 0 ;
b - > data [ 3 ] = 0 ;
dbg ( " dabusb_fpga_init " ) ;
return dabusb_bulk ( s , b ) ;
}
/* --------------------------------------------------------------------- */
static int dabusb_fpga_download ( pdabusb_t s , const char * fname )
{
pbulk_transfer_t b = kmalloc ( sizeof ( bulk_transfer_t ) , GFP_KERNEL ) ;
unsigned int blen , n ;
int ret ;
unsigned char * buf = bitstream ;
dbg ( " Enter dabusb_fpga_download (internal) " ) ;
if ( ! b ) {
err ( " kmalloc(sizeof(bulk_transfer_t))==NULL " ) ;
return - ENOMEM ;
}
b - > pipe = 1 ;
ret = dabusb_fpga_clear ( s , b ) ;
mdelay ( 10 ) ;
blen = buf [ 73 ] + ( buf [ 72 ] < < 8 ) ;
dbg ( " Bitstream len: %i " , blen ) ;
b - > data [ 0 ] = 0x2b ;
b - > data [ 1 ] = 0 ;
b - > data [ 2 ] = 0 ;
b - > data [ 3 ] = 60 ;
for ( n = 0 ; n < = blen + 60 ; n + = 60 ) {
// some cclks for startup
b - > size = 64 ;
memcpy ( b - > data + 4 , buf + 74 + n , 60 ) ;
ret = dabusb_bulk ( s , b ) ;
if ( ret < 0 ) {
err ( " dabusb_bulk failed. " ) ;
break ;
}
mdelay ( 1 ) ;
}
ret = dabusb_fpga_init ( s , b ) ;
kfree ( b ) ;
dbg ( " exit dabusb_fpga_download " ) ;
return ret ;
}
static int dabusb_stop ( pdabusb_t s )
{
dbg ( " dabusb_stop " ) ;
s - > state = _stopped ;
dabusb_cancel_queue ( s , & s - > rec_buff_list ) ;
dbg ( " pending_io: %d " , s - > pending_io . counter ) ;
s - > pending_io . counter = 0 ;
return 0 ;
}
static int dabusb_startrek ( pdabusb_t s )
{
if ( ! s - > got_mem & & s - > state ! = _started ) {
dbg ( " dabusb_startrek " ) ;
if ( dabusb_alloc_buffers ( s ) < 0 )
return - ENOMEM ;
dabusb_stop ( s ) ;
s - > state = _started ;
s - > readptr = 0 ;
}
if ( ! list_empty ( & s - > free_buff_list ) ) {
pbuff_t end ;
int ret ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
while ( ! dabusb_add_buf_tail ( s , & s - > rec_buff_list , & s - > free_buff_list ) ) {
dbg ( " submitting: end:%p s->rec_buff_list:%p " , s - > rec_buff_list . prev , & s - > rec_buff_list ) ;
end = list_entry ( s - > rec_buff_list . prev , buff_t , buff_list ) ;
ret = usb_submit_urb ( end - > purb , GFP_KERNEL ) ;
if ( ret ) {
err ( " usb_submit_urb returned:%d " , ret ) ;
if ( dabusb_add_buf_tail ( s , & s - > free_buff_list , & s - > rec_buff_list ) )
err ( " startrek: dabusb_add_buf_tail failed " ) ;
break ;
}
else
atomic_inc ( & s - > pending_io ) ;
}
dbg ( " pending_io: %d " , s - > pending_io . counter ) ;
}
return 0 ;
}
static ssize_t dabusb_read ( struct file * file , char __user * buf , size_t count , loff_t * ppos )
{
pdabusb_t s = ( pdabusb_t ) file - > private_data ;
unsigned long flags ;
unsigned ret = 0 ;
int rem ;
int cnt ;
pbuff_t b ;
struct urb * purb = NULL ;
dbg ( " dabusb_read " ) ;
if ( * ppos )
return - ESPIPE ;
if ( s - > remove_pending )
return - EIO ;
if ( ! s - > usbdev )
return - EIO ;
while ( count > 0 ) {
dabusb_startrek ( s ) ;
spin_lock_irqsave ( & s - > lock , flags ) ;
if ( list_empty ( & s - > rec_buff_list ) ) {
spin_unlock_irqrestore ( & s - > lock , flags ) ;
err ( " error: rec_buf_list is empty " ) ;
goto err ;
}
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
b = list_entry ( s - > rec_buff_list . next , buff_t , buff_list ) ;
purb = b - > purb ;
spin_unlock_irqrestore ( & s - > lock , flags ) ;
if ( purb - > status = = - EINPROGRESS ) {
if ( file - > f_flags & O_NONBLOCK ) // return nonblocking
{
if ( ! ret )
ret = - EAGAIN ;
goto err ;
}
interruptible_sleep_on ( & s - > wait ) ;
if ( signal_pending ( current ) ) {
if ( ! ret )
ret = - ERESTARTSYS ;
goto err ;
}
spin_lock_irqsave ( & s - > lock , flags ) ;
if ( list_empty ( & s - > rec_buff_list ) ) {
spin_unlock_irqrestore ( & s - > lock , flags ) ;
err ( " error: still no buffer available. " ) ;
goto err ;
}
spin_unlock_irqrestore ( & s - > lock , flags ) ;
s - > readptr = 0 ;
}
if ( s - > remove_pending ) {
ret = - EIO ;
goto err ;
}
rem = purb - > actual_length - s - > readptr ; // set remaining bytes to copy
if ( count > = rem )
cnt = rem ;
else
cnt = count ;
dbg ( " copy_to_user:%p %p %d " , buf , purb - > transfer_buffer + s - > readptr , cnt ) ;
if ( copy_to_user ( buf , purb - > transfer_buffer + s - > readptr , cnt ) ) {
err ( " read: copy_to_user failed " ) ;
if ( ! ret )
ret = - EFAULT ;
goto err ;
}
s - > readptr + = cnt ;
count - = cnt ;
buf + = cnt ;
ret + = cnt ;
if ( s - > readptr = = purb - > actual_length ) {
// finished, take next buffer
if ( dabusb_add_buf_tail ( s , & s - > free_buff_list , & s - > rec_buff_list ) )
err ( " read: dabusb_add_buf_tail failed " ) ;
s - > readptr = 0 ;
}
}
2006-01-11 15:55:29 +01:00
err : //mutex_unlock(&s->mutex);
2005-04-16 15:20:36 -07:00
return ret ;
}
static int dabusb_open ( struct inode * inode , struct file * file )
{
int devnum = iminor ( inode ) ;
pdabusb_t s ;
if ( devnum < DABUSB_MINOR | | devnum > = ( DABUSB_MINOR + NRDABUSB ) )
return - EIO ;
s = & dabusb [ devnum - DABUSB_MINOR ] ;
dbg ( " dabusb_open " ) ;
2006-01-11 15:55:29 +01:00
mutex_lock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
while ( ! s - > usbdev | | s - > opened ) {
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
if ( file - > f_flags & O_NONBLOCK ) {
return - EBUSY ;
}
msleep_interruptible ( 500 ) ;
if ( signal_pending ( current ) ) {
return - EAGAIN ;
}
2006-01-11 15:55:29 +01:00
mutex_lock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
}
if ( usb_set_interface ( s - > usbdev , _DABUSB_IF , 1 ) < 0 ) {
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
err ( " set_interface failed " ) ;
return - EINVAL ;
}
s - > opened = 1 ;
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
file - > f_pos = 0 ;
file - > private_data = s ;
return nonseekable_open ( inode , file ) ;
}
static int dabusb_release ( struct inode * inode , struct file * file )
{
pdabusb_t s = ( pdabusb_t ) file - > private_data ;
dbg ( " dabusb_release " ) ;
2006-01-11 15:55:29 +01:00
mutex_lock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
dabusb_stop ( s ) ;
dabusb_free_buffers ( s ) ;
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
if ( ! s - > remove_pending ) {
if ( usb_set_interface ( s - > usbdev , _DABUSB_IF , 0 ) < 0 )
err ( " set_interface failed " ) ;
}
else
wake_up ( & s - > remove_ok ) ;
s - > opened = 0 ;
return 0 ;
}
static int dabusb_ioctl ( struct inode * inode , struct file * file , unsigned int cmd , unsigned long arg )
{
pdabusb_t s = ( pdabusb_t ) file - > private_data ;
pbulk_transfer_t pbulk ;
int ret = 0 ;
int version = DABUSB_VERSION ;
dbg ( " dabusb_ioctl " ) ;
if ( s - > remove_pending )
return - EIO ;
2006-01-11 15:55:29 +01:00
mutex_lock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
if ( ! s - > usbdev ) {
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
switch ( cmd ) {
case IOCTL_DAB_BULK :
pbulk = ( pbulk_transfer_t ) kmalloc ( sizeof ( bulk_transfer_t ) , GFP_KERNEL ) ;
if ( ! pbulk ) {
ret = - ENOMEM ;
break ;
}
if ( copy_from_user ( pbulk , ( void __user * ) arg , sizeof ( bulk_transfer_t ) ) ) {
ret = - EFAULT ;
kfree ( pbulk ) ;
break ;
}
ret = dabusb_bulk ( s , pbulk ) ;
if ( ret = = 0 )
if ( copy_to_user ( ( void __user * ) arg , pbulk ,
sizeof ( bulk_transfer_t ) ) )
ret = - EFAULT ;
kfree ( pbulk ) ;
break ;
case IOCTL_DAB_OVERRUNS :
ret = put_user ( s - > overruns , ( unsigned int __user * ) arg ) ;
break ;
case IOCTL_DAB_VERSION :
ret = put_user ( version , ( unsigned int __user * ) arg ) ;
break ;
default :
ret = - ENOIOCTLCMD ;
break ;
}
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
static struct file_operations dabusb_fops =
{
. owner = THIS_MODULE ,
. llseek = no_llseek ,
. read = dabusb_read ,
. ioctl = dabusb_ioctl ,
. open = dabusb_open ,
. release = dabusb_release ,
} ;
static struct usb_class_driver dabusb_class = {
2005-06-20 21:15:16 -07:00
. name = " dabusb%d " ,
2005-04-16 15:20:36 -07:00
. fops = & dabusb_fops ,
. minor_base = DABUSB_MINOR ,
} ;
/* --------------------------------------------------------------------- */
static int dabusb_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_device * usbdev = interface_to_usbdev ( intf ) ;
int retval ;
pdabusb_t s ;
dbg ( " dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d " ,
le16_to_cpu ( usbdev - > descriptor . idVendor ) ,
le16_to_cpu ( usbdev - > descriptor . idProduct ) ,
intf - > altsetting - > desc . bInterfaceNumber ) ;
/* We don't handle multiple configurations */
if ( usbdev - > descriptor . bNumConfigurations ! = 1 )
return - ENODEV ;
if ( intf - > altsetting - > desc . bInterfaceNumber ! = _DABUSB_IF & &
le16_to_cpu ( usbdev - > descriptor . idProduct ) = = 0x9999 )
return - ENODEV ;
s = & dabusb [ intf - > minor ] ;
2006-01-11 15:55:29 +01:00
mutex_lock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
s - > remove_pending = 0 ;
s - > usbdev = usbdev ;
s - > devnum = intf - > minor ;
if ( usb_reset_configuration ( usbdev ) < 0 ) {
err ( " reset_configuration failed " ) ;
goto reject ;
}
if ( le16_to_cpu ( usbdev - > descriptor . idProduct ) = = 0x2131 ) {
dabusb_loadmem ( s , NULL ) ;
goto reject ;
}
else {
dabusb_fpga_download ( s , NULL ) ;
if ( usb_set_interface ( s - > usbdev , _DABUSB_IF , 0 ) < 0 ) {
err ( " set_interface failed " ) ;
goto reject ;
}
}
dbg ( " bound to interface: %d " , intf - > altsetting - > desc . bInterfaceNumber ) ;
usb_set_intfdata ( intf , s ) ;
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
retval = usb_register_dev ( intf , & dabusb_class ) ;
if ( retval ) {
usb_set_intfdata ( intf , NULL ) ;
return - ENOMEM ;
}
return 0 ;
reject :
2006-01-11 15:55:29 +01:00
mutex_unlock ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
s - > usbdev = NULL ;
return - ENODEV ;
}
static void dabusb_disconnect ( struct usb_interface * intf )
{
wait_queue_t __wait ;
pdabusb_t s = usb_get_intfdata ( intf ) ;
dbg ( " dabusb_disconnect " ) ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
init_waitqueue_entry ( & __wait , current ) ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
usb_set_intfdata ( intf , NULL ) ;
if ( s ) {
usb_deregister_dev ( intf , & dabusb_class ) ;
s - > remove_pending = 1 ;
wake_up ( & s - > wait ) ;
add_wait_queue ( & s - > remove_ok , & __wait ) ;
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
if ( s - > state = = _started )
schedule ( ) ;
current - > state = TASK_RUNNING ;
remove_wait_queue ( & s - > remove_ok , & __wait ) ;
2006-03-25 09:19:53 -03:00
2005-04-16 15:20:36 -07:00
s - > usbdev = NULL ;
s - > overruns = 0 ;
}
}
static struct usb_device_id dabusb_ids [ ] = {
// { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */
{ USB_DEVICE ( 0x0547 , 0x9999 ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , dabusb_ids ) ;
static struct usb_driver dabusb_driver = {
. name = " dabusb " ,
. probe = dabusb_probe ,
. disconnect = dabusb_disconnect ,
. id_table = dabusb_ids ,
} ;
/* --------------------------------------------------------------------- */
static int __init dabusb_init ( void )
{
int retval ;
unsigned u ;
/* initialize struct */
for ( u = 0 ; u < NRDABUSB ; u + + ) {
pdabusb_t s = & dabusb [ u ] ;
memset ( s , 0 , sizeof ( dabusb_t ) ) ;
2006-01-11 15:55:29 +01:00
mutex_init ( & s - > mutex ) ;
2005-04-16 15:20:36 -07:00
s - > usbdev = NULL ;
s - > total_buffer_size = buffers ;
init_waitqueue_head ( & s - > wait ) ;
init_waitqueue_head ( & s - > remove_ok ) ;
spin_lock_init ( & s - > lock ) ;
INIT_LIST_HEAD ( & s - > free_buff_list ) ;
INIT_LIST_HEAD ( & s - > rec_buff_list ) ;
}
/* register misc device */
retval = usb_register ( & dabusb_driver ) ;
if ( retval )
goto out ;
dbg ( " dabusb_init: driver registered " ) ;
info ( DRIVER_VERSION " : " DRIVER_DESC ) ;
out :
return retval ;
}
static void __exit dabusb_cleanup ( void )
{
dbg ( " dabusb_cleanup " ) ;
usb_deregister ( & dabusb_driver ) ;
}
/* --------------------------------------------------------------------- */
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( buffers , int , 0 ) ;
MODULE_PARM_DESC ( buffers , " Number of buffers (default=256) " ) ;
module_init ( dabusb_init ) ;
module_exit ( dabusb_cleanup ) ;
/* --------------------------------------------------------------------- */