2006-03-26 13:38:29 +04:00
/*
* Stuff used by all variants of the driver
*
2006-04-11 09:55:14 +04:00
* Copyright ( c ) 2001 by Stefan Eilers ,
2006-03-26 13:38:29 +04:00
* Hansjoerg Lipp < hjlipp @ web . de > ,
* Tilman Schmidt < tilman @ imap . cc > .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* 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 .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "gigaset.h"
# include <linux/ctype.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
/* Version Information */
2006-04-11 09:55:14 +04:00
# define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
2006-03-26 13:38:29 +04:00
# define DRIVER_DESC "Driver for Gigaset 307x"
2009-10-06 16:18:41 +04:00
# ifdef CONFIG_GIGASET_DEBUG
# define DRIVER_DESC_DEBUG " (debug build)"
# else
# define DRIVER_DESC_DEBUG ""
# endif
2006-03-26 13:38:29 +04:00
/* Module parameters */
int gigaset_debuglevel = DEBUG_DEFAULT ;
EXPORT_SYMBOL_GPL ( gigaset_debuglevel ) ;
module_param_named ( debug , gigaset_debuglevel , int , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( debug , " debug level " ) ;
2006-04-11 09:55:14 +04:00
/* driver state flags */
2006-04-11 09:55:04 +04:00
# define VALID_MINOR 0x01
# define VALID_ID 0x02
2006-03-26 13:38:29 +04:00
2009-10-06 16:19:01 +04:00
/**
* gigaset_dbg_buffer ( ) - dump data in ASCII and hex for debugging
* @ level : debugging level .
* @ msg : message prefix .
* @ len : number of bytes to dump .
* @ buf : data to dump .
*
* If the current debugging level includes one of the bits set in @ level ,
* @ len bytes starting at @ buf are logged to dmesg at KERN_DEBUG prio ,
* prefixed by the text @ msg .
*/
2006-03-26 13:38:29 +04:00
void gigaset_dbg_buffer ( enum debuglevel level , const unsigned char * msg ,
2006-04-11 09:55:11 +04:00
size_t len , const unsigned char * buf )
2006-03-26 13:38:29 +04:00
{
unsigned char outbuf [ 80 ] ;
2006-04-11 09:55:04 +04:00
unsigned char c ;
2006-03-26 13:38:29 +04:00
size_t space = sizeof outbuf - 1 ;
unsigned char * out = outbuf ;
2006-04-11 09:55:11 +04:00
size_t numin = len ;
2006-03-26 13:38:29 +04:00
2006-04-11 09:55:11 +04:00
while ( numin - - ) {
2006-04-11 09:55:04 +04:00
c = * buf + + ;
if ( c = = ' ~ ' | | c = = ' ^ ' | | c = = ' \\ ' ) {
2006-04-11 09:55:11 +04:00
if ( ! space - - )
2006-04-11 09:55:04 +04:00
break ;
* out + + = ' \\ ' ;
}
if ( c & 0x80 ) {
2006-04-11 09:55:11 +04:00
if ( ! space - - )
2006-04-11 09:55:04 +04:00
break ;
* out + + = ' ~ ' ;
c ^ = 0x80 ;
}
if ( c < 0x20 | | c = = 0x7f ) {
2006-04-11 09:55:11 +04:00
if ( ! space - - )
2006-04-11 09:55:04 +04:00
break ;
2006-03-26 13:38:29 +04:00
* out + + = ' ^ ' ;
2006-04-11 09:55:04 +04:00
c ^ = 0x40 ;
2006-03-26 13:38:29 +04:00
}
2006-04-11 09:55:11 +04:00
if ( ! space - - )
2006-04-11 09:55:04 +04:00
break ;
* out + + = c ;
2006-03-26 13:38:29 +04:00
}
* out = 0 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( level , " %s (%u bytes): %s " , msg , ( unsigned ) len , outbuf ) ;
2006-03-26 13:38:29 +04:00
}
EXPORT_SYMBOL_GPL ( gigaset_dbg_buffer ) ;
static int setflags ( struct cardstate * cs , unsigned flags , unsigned delay )
{
int r ;
r = cs - > ops - > set_modem_ctrl ( cs , cs - > control_state , flags ) ;
cs - > control_state = flags ;
if ( r < 0 )
return r ;
if ( delay ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( delay * HZ / 1000 ) ;
}
return 0 ;
}
int gigaset_enterconfigmode ( struct cardstate * cs )
{
int i , r ;
cs - > control_state = TIOCM_RTS ; //FIXME
r = setflags ( cs , TIOCM_DTR , 200 ) ;
if ( r < 0 )
goto error ;
r = setflags ( cs , 0 , 200 ) ;
if ( r < 0 )
goto error ;
for ( i = 0 ; i < 5 ; + + i ) {
r = setflags ( cs , TIOCM_RTS , 100 ) ;
if ( r < 0 )
goto error ;
r = setflags ( cs , 0 , 100 ) ;
if ( r < 0 )
goto error ;
}
r = setflags ( cs , TIOCM_RTS | TIOCM_DTR , 800 ) ;
if ( r < 0 )
goto error ;
return 0 ;
error :
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev , " error %d on setuartbits \n " , - r ) ;
2006-03-26 13:38:29 +04:00
cs - > control_state = TIOCM_RTS | TIOCM_DTR ; // FIXME is this a good value?
cs - > ops - > set_modem_ctrl ( cs , 0 , TIOCM_RTS | TIOCM_DTR ) ;
return - 1 ; //r
}
static int test_timeout ( struct at_state_t * at_state )
{
if ( ! at_state - > timer_expires )
return 0 ;
if ( - - at_state - > timer_expires ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_MCMD , " decreased timer of %p to %lu " ,
at_state , at_state - > timer_expires ) ;
2006-03-26 13:38:29 +04:00
return 0 ;
}
if ( ! gigaset_add_event ( at_state - > cs , at_state , EV_TIMEOUT , NULL ,
2006-04-11 09:55:16 +04:00
at_state - > timer_index , NULL ) ) {
2006-03-26 13:38:29 +04:00
//FIXME what should we do?
}
return 1 ;
}
static void timer_tick ( unsigned long data )
{
struct cardstate * cs = ( struct cardstate * ) data ;
unsigned long flags ;
unsigned channel ;
struct at_state_t * at_state ;
int timeout = 0 ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
for ( channel = 0 ; channel < cs - > channels ; + + channel )
if ( test_timeout ( & cs - > bcs [ channel ] . at_state ) )
timeout = 1 ;
if ( test_timeout ( & cs - > at_state ) )
timeout = 1 ;
list_for_each_entry ( at_state , & cs - > temp_at_states , list )
if ( test_timeout ( at_state ) )
timeout = 1 ;
2006-04-11 09:55:16 +04:00
if ( cs - > running ) {
2006-04-11 09:55:03 +04:00
mod_timer ( & cs - > timer , jiffies + msecs_to_jiffies ( GIG_TICK ) ) ;
2006-03-26 13:38:29 +04:00
if ( timeout ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling timeout " ) ;
2006-03-26 13:38:29 +04:00
tasklet_schedule ( & cs - > event_tasklet ) ;
}
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
}
int gigaset_get_channel ( struct bc_state * bcs )
{
unsigned long flags ;
spin_lock_irqsave ( & bcs - > cs - > lock , flags ) ;
2008-02-06 12:38:29 +03:00
if ( bcs - > use_count | | ! try_module_get ( bcs - > cs - > driver - > owner ) ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " could not allocate channel %d " ,
bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
return 0 ;
}
+ + bcs - > use_count ;
bcs - > busy = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " allocated channel %d " , bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
return 1 ;
}
void gigaset_free_channel ( struct bc_state * bcs )
{
unsigned long flags ;
spin_lock_irqsave ( & bcs - > cs - > lock , flags ) ;
if ( ! bcs - > busy ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " could not free channel %d " , bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
return ;
}
- - bcs - > use_count ;
bcs - > busy = 0 ;
2008-02-06 12:38:29 +03:00
module_put ( bcs - > cs - > driver - > owner ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " freed channel %d " , bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
}
int gigaset_get_channels ( struct cardstate * cs )
{
unsigned long flags ;
int i ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
for ( i = 0 ; i < cs - > channels ; + + i )
if ( cs - > bcs [ i ] . use_count ) {
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " could not allocate all channels " ) ;
2006-03-26 13:38:29 +04:00
return 0 ;
}
for ( i = 0 ; i < cs - > channels ; + + i )
+ + cs - > bcs [ i ] . use_count ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " allocated all channels " ) ;
2006-03-26 13:38:29 +04:00
return 1 ;
}
void gigaset_free_channels ( struct cardstate * cs )
{
unsigned long flags ;
int i ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " unblocking all channels " ) ;
2006-03-26 13:38:29 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
for ( i = 0 ; i < cs - > channels ; + + i )
- - cs - > bcs [ i ] . use_count ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
}
void gigaset_block_channels ( struct cardstate * cs )
{
unsigned long flags ;
int i ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " blocking all channels " ) ;
2006-03-26 13:38:29 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
for ( i = 0 ; i < cs - > channels ; + + i )
+ + cs - > bcs [ i ] . use_count ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
}
static void clear_events ( struct cardstate * cs )
{
struct event_t * ev ;
unsigned head , tail ;
2006-04-11 09:55:16 +04:00
unsigned long flags ;
2006-03-26 13:38:29 +04:00
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > ev_lock , flags ) ;
2006-03-26 13:38:29 +04:00
2006-04-11 09:55:16 +04:00
head = cs - > ev_head ;
tail = cs - > ev_tail ;
2006-03-26 13:38:29 +04:00
while ( tail ! = head ) {
ev = cs - > events + head ;
kfree ( ev - > ptr ) ;
head = ( head + 1 ) % MAX_EVENTS ;
}
2006-04-11 09:55:16 +04:00
cs - > ev_head = tail ;
spin_unlock_irqrestore ( & cs - > ev_lock , flags ) ;
2006-03-26 13:38:29 +04:00
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_add_event ( ) - add event to device event queue
* @ cs : device descriptor structure .
* @ at_state : connection state structure .
* @ type : event type .
* @ ptr : pointer parameter for event .
* @ parameter : integer parameter for event .
* @ arg : pointer parameter for event .
*
* Allocate an event queue entry from the device ' s event queue , and set it up
* with the parameters given .
*
* Return value : added event
*/
2006-03-26 13:38:29 +04:00
struct event_t * gigaset_add_event ( struct cardstate * cs ,
2006-04-11 09:55:04 +04:00
struct at_state_t * at_state , int type ,
void * ptr , int parameter , void * arg )
2006-03-26 13:38:29 +04:00
{
unsigned long flags ;
unsigned next , tail ;
struct event_t * event = NULL ;
spin_lock_irqsave ( & cs - > ev_lock , flags ) ;
2006-04-11 09:55:16 +04:00
tail = cs - > ev_tail ;
2006-03-26 13:38:29 +04:00
next = ( tail + 1 ) % MAX_EVENTS ;
2006-04-11 09:55:16 +04:00
if ( unlikely ( next = = cs - > ev_head ) )
2008-07-24 08:28:27 +04:00
dev_err ( cs - > dev , " event queue full \n " ) ;
2006-03-26 13:38:29 +04:00
else {
event = cs - > events + tail ;
event - > type = type ;
event - > at_state = at_state ;
event - > cid = - 1 ;
event - > ptr = ptr ;
event - > arg = arg ;
event - > parameter = parameter ;
2006-04-11 09:55:16 +04:00
cs - > ev_tail = next ;
2006-03-26 13:38:29 +04:00
}
spin_unlock_irqrestore ( & cs - > ev_lock , flags ) ;
return event ;
}
EXPORT_SYMBOL_GPL ( gigaset_add_event ) ;
static void free_strings ( struct at_state_t * at_state )
{
int i ;
for ( i = 0 ; i < STR_NUM ; + + i ) {
kfree ( at_state - > str_var [ i ] ) ;
at_state - > str_var [ i ] = NULL ;
}
}
static void clear_at_state ( struct at_state_t * at_state )
{
free_strings ( at_state ) ;
}
static void dealloc_at_states ( struct cardstate * cs )
{
struct at_state_t * cur , * next ;
list_for_each_entry_safe ( cur , next , & cs - > temp_at_states , list ) {
list_del ( & cur - > list ) ;
free_strings ( cur ) ;
kfree ( cur ) ;
}
}
static void gigaset_freebcs ( struct bc_state * bcs )
{
int i ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " freeing bcs[%d]->hw " , bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
if ( ! bcs - > cs - > ops - > freebcshw ( bcs ) ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " failed " ) ;
2006-03-26 13:38:29 +04:00
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " clearing bcs[%d]->at_state " , bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
clear_at_state ( & bcs - > at_state ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " freeing bcs[%d]->skb " , bcs - > channel ) ;
2006-03-26 13:38:29 +04:00
if ( bcs - > skb )
dev_kfree_skb ( bcs - > skb ) ;
for ( i = 0 ; i < AT_NUM ; + + i ) {
kfree ( bcs - > commands [ i ] ) ;
bcs - > commands [ i ] = NULL ;
}
}
2006-04-11 09:55:14 +04:00
static struct cardstate * alloc_cs ( struct gigaset_driver * drv )
{
unsigned long flags ;
unsigned i ;
2008-02-06 12:38:29 +03:00
struct cardstate * cs ;
2007-01-26 11:56:56 +03:00
struct cardstate * ret = NULL ;
2006-04-11 09:55:14 +04:00
spin_lock_irqsave ( & drv - > lock , flags ) ;
2008-02-06 12:38:29 +03:00
if ( drv - > blocked )
goto exit ;
2006-04-11 09:55:14 +04:00
for ( i = 0 ; i < drv - > minors ; + + i ) {
2008-02-06 12:38:29 +03:00
cs = drv - > cs + i ;
if ( ! ( cs - > flags & VALID_MINOR ) ) {
cs - > flags = VALID_MINOR ;
ret = cs ;
2006-04-11 09:55:14 +04:00
break ;
2007-01-26 11:56:56 +03:00
}
2006-04-11 09:55:14 +04:00
}
2008-02-06 12:38:29 +03:00
exit :
2006-04-11 09:55:14 +04:00
spin_unlock_irqrestore ( & drv - > lock , flags ) ;
return ret ;
}
static void free_cs ( struct cardstate * cs )
{
2008-02-06 12:38:29 +03:00
cs - > flags = 0 ;
2006-04-11 09:55:14 +04:00
}
static void make_valid ( struct cardstate * cs , unsigned mask )
{
unsigned long flags ;
struct gigaset_driver * drv = cs - > driver ;
spin_lock_irqsave ( & drv - > lock , flags ) ;
2008-02-06 12:38:29 +03:00
cs - > flags | = mask ;
2006-04-11 09:55:14 +04:00
spin_unlock_irqrestore ( & drv - > lock , flags ) ;
}
static void make_invalid ( struct cardstate * cs , unsigned mask )
{
unsigned long flags ;
struct gigaset_driver * drv = cs - > driver ;
spin_lock_irqsave ( & drv - > lock , flags ) ;
2008-02-06 12:38:29 +03:00
cs - > flags & = ~ mask ;
2006-04-11 09:55:14 +04:00
spin_unlock_irqrestore ( & drv - > lock , flags ) ;
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_freecs ( ) - free all associated ressources of a device
* @ cs : device descriptor structure .
*
* Stops all tasklets and timers , unregisters the device from all
* subsystems it was registered to , deallocates the device structure
* @ cs and all structures referenced from it .
* Operations on the device should be stopped before calling this .
*/
2006-03-26 13:38:29 +04:00
void gigaset_freecs ( struct cardstate * cs )
{
int i ;
unsigned long flags ;
if ( ! cs )
return ;
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
if ( ! cs - > bcs )
goto f_cs ;
if ( ! cs - > inbuf )
goto f_bcs ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
2006-04-11 09:55:16 +04:00
cs - > running = 0 ;
2006-04-11 09:55:00 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ; /* event handler and timer are
not rescheduled below */
2006-03-26 13:38:29 +04:00
tasklet_kill ( & cs - > event_tasklet ) ;
del_timer_sync ( & cs - > timer ) ;
switch ( cs - > cs_init ) {
default :
2006-04-22 20:43:00 +04:00
/* clear device sysfs */
gigaset_free_dev_sysfs ( cs ) ;
2006-03-26 13:38:29 +04:00
gigaset_if_free ( cs ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " clearing hw " ) ;
2006-03-26 13:38:29 +04:00
cs - > ops - > freecshw ( cs ) ;
//FIXME cmdbuf
/* fall through */
case 2 : /* error in initcshw */
/* Deregister from LL */
make_invalid ( cs , VALID_ID ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " clearing iif " ) ;
2006-03-26 13:38:29 +04:00
gigaset_i4l_cmd ( cs , ISDN_STAT_UNLOAD ) ;
/* fall through */
case 1 : /* error when regestering to LL */
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " clearing at_state " ) ;
2006-03-26 13:38:29 +04:00
clear_at_state ( & cs - > at_state ) ;
dealloc_at_states ( cs ) ;
/* fall through */
case 0 : /* error in one call to initbcs */
for ( i = 0 ; i < cs - > channels ; + + i ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " clearing bcs[%d] " , i ) ;
2006-03-26 13:38:29 +04:00
gigaset_freebcs ( cs - > bcs + i ) ;
}
clear_events ( cs ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " freeing inbuf " ) ;
2006-03-26 13:38:29 +04:00
kfree ( cs - > inbuf ) ;
}
2006-04-11 09:55:04 +04:00
f_bcs : gig_dbg ( DEBUG_INIT , " freeing bcs[] " ) ;
2006-03-26 13:38:29 +04:00
kfree ( cs - > bcs ) ;
2006-04-11 09:55:04 +04:00
f_cs : gig_dbg ( DEBUG_INIT , " freeing cs " ) ;
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
free_cs ( cs ) ;
}
EXPORT_SYMBOL_GPL ( gigaset_freecs ) ;
void gigaset_at_init ( struct at_state_t * at_state , struct bc_state * bcs ,
2006-04-11 09:55:04 +04:00
struct cardstate * cs , int cid )
2006-03-26 13:38:29 +04:00
{
int i ;
INIT_LIST_HEAD ( & at_state - > list ) ;
at_state - > waiting = 0 ;
at_state - > getstring = 0 ;
at_state - > pending_commands = 0 ;
at_state - > timer_expires = 0 ;
at_state - > timer_active = 0 ;
2006-04-11 09:55:16 +04:00
at_state - > timer_index = 0 ;
at_state - > seq_index = 0 ;
2006-03-26 13:38:29 +04:00
at_state - > ConState = 0 ;
for ( i = 0 ; i < STR_NUM ; + + i )
at_state - > str_var [ i ] = NULL ;
at_state - > int_var [ VAR_ZDLE ] = 0 ;
at_state - > int_var [ VAR_ZCTP ] = - 1 ;
at_state - > int_var [ VAR_ZSAU ] = ZSAU_NULL ;
at_state - > cs = cs ;
at_state - > bcs = bcs ;
at_state - > cid = cid ;
if ( ! cid )
at_state - > replystruct = cs - > tabnocid ;
else
at_state - > replystruct = cs - > tabcid ;
}
static void gigaset_inbuf_init ( struct inbuf_t * inbuf , struct bc_state * bcs ,
2006-04-11 09:55:04 +04:00
struct cardstate * cs , int inputstate )
2006-03-26 13:38:29 +04:00
/* inbuf->read must be allocated before! */
{
2008-02-06 12:38:28 +03:00
inbuf - > head = 0 ;
inbuf - > tail = 0 ;
2006-03-26 13:38:29 +04:00
inbuf - > cs = cs ;
inbuf - > bcs = bcs ; /*base driver: NULL*/
2008-02-06 12:38:28 +03:00
inbuf - > rcvbuf = NULL ;
2006-03-26 13:38:29 +04:00
inbuf - > inputstate = inputstate ;
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_fill_inbuf ( ) - append received data to input buffer
* @ inbuf : buffer structure .
* @ src : received data .
* @ numbytes : number of bytes received .
*/
2006-04-11 09:55:09 +04:00
int gigaset_fill_inbuf ( struct inbuf_t * inbuf , const unsigned char * src ,
unsigned numbytes )
{
unsigned n , head , tail , bytesleft ;
gig_dbg ( DEBUG_INTR , " received %u bytes " , numbytes ) ;
if ( ! numbytes )
return 0 ;
bytesleft = numbytes ;
2008-02-06 12:38:28 +03:00
tail = inbuf - > tail ;
head = inbuf - > head ;
2006-04-11 09:55:09 +04:00
gig_dbg ( DEBUG_INTR , " buffer state: %u -> %u " , head , tail ) ;
while ( bytesleft ) {
if ( head > tail )
n = head - 1 - tail ;
else if ( head = = 0 )
n = ( RBUFSIZE - 1 ) - tail ;
else
n = RBUFSIZE - tail ;
if ( ! n ) {
dev_err ( inbuf - > cs - > dev ,
2007-10-18 14:06:30 +04:00
" buffer overflow (%u bytes lost) \n " ,
bytesleft ) ;
2006-04-11 09:55:09 +04:00
break ;
}
if ( n > bytesleft )
n = bytesleft ;
memcpy ( inbuf - > data + tail , src , n ) ;
bytesleft - = n ;
tail = ( tail + n ) % RBUFSIZE ;
src + = n ;
}
gig_dbg ( DEBUG_INTR , " setting tail to %u " , tail ) ;
2008-02-06 12:38:28 +03:00
inbuf - > tail = tail ;
2006-04-11 09:55:09 +04:00
return numbytes ! = bytesleft ;
}
EXPORT_SYMBOL_GPL ( gigaset_fill_inbuf ) ;
2006-03-26 13:38:29 +04:00
/* Initialize the b-channel structure */
static struct bc_state * gigaset_initbcs ( struct bc_state * bcs ,
2006-04-11 09:55:04 +04:00
struct cardstate * cs , int channel )
2006-03-26 13:38:29 +04:00
{
int i ;
bcs - > tx_skb = NULL ; //FIXME -> hw part
skb_queue_head_init ( & bcs - > squeue ) ;
bcs - > corrupted = 0 ;
bcs - > trans_down = 0 ;
bcs - > trans_up = 0 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up bcs[%d]->at_state " , channel ) ;
2006-03-26 13:38:29 +04:00
gigaset_at_init ( & bcs - > at_state , bcs , cs , - 1 ) ;
# ifdef CONFIG_GIGASET_DEBUG
bcs - > emptycount = 0 ;
# endif
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " allocating bcs[%d]->skb " , channel ) ;
2006-03-26 13:38:29 +04:00
bcs - > fcs = PPP_INITFCS ;
bcs - > inputstate = 0 ;
if ( cs - > ignoreframes ) {
bcs - > inputstate | = INS_skip_frame ;
bcs - > skb = NULL ;
} else if ( ( bcs - > skb = dev_alloc_skb ( SBUFSIZE + HW_HDR_LEN ) ) ! = NULL )
skb_reserve ( bcs - > skb , HW_HDR_LEN ) ;
else {
2008-12-26 12:21:29 +03:00
pr_err ( " out of memory \n " ) ;
2006-03-26 13:38:29 +04:00
bcs - > inputstate | = INS_skip_frame ;
}
bcs - > channel = channel ;
bcs - > cs = cs ;
bcs - > chstate = 0 ;
bcs - > use_count = 1 ;
bcs - > busy = 0 ;
bcs - > ignore = cs - > ignoreframes ;
for ( i = 0 ; i < AT_NUM ; + + i )
bcs - > commands [ i ] = NULL ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up bcs[%d]->hw " , channel ) ;
2006-03-26 13:38:29 +04:00
if ( cs - > ops - > initbcshw ( bcs ) )
return bcs ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " failed " ) ;
2006-03-26 13:38:29 +04:00
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " freeing bcs[%d]->skb " , channel ) ;
2006-03-26 13:38:29 +04:00
if ( bcs - > skb )
dev_kfree_skb ( bcs - > skb ) ;
return NULL ;
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_initcs ( ) - initialize device structure
* @ drv : hardware driver the device belongs to
* @ channels : number of B channels supported by device
* @ onechannel : ! = 0 if B channel data and AT commands share one
* communication channel ( M10x ) ,
* = = 0 if B channels have separate communication channels ( base )
* @ ignoreframes : number of frames to ignore after setting up B channel
* @ cidmode : ! = 0 : start in CallID mode
* @ modulename : name of driver module for LL registration
*
2006-03-26 13:38:29 +04:00
* Allocate and initialize cardstate structure for Gigaset driver
* Calls hardware dependent gigaset_initcshw ( ) function
* Calls B channel initialization function gigaset_initbcs ( ) for each B channel
2009-10-06 16:19:01 +04:00
*
* Return value :
2006-03-26 13:38:29 +04:00
* pointer to cardstate structure
*/
struct cardstate * gigaset_initcs ( struct gigaset_driver * drv , int channels ,
int onechannel , int ignoreframes ,
int cidmode , const char * modulename )
{
struct cardstate * cs = NULL ;
2006-04-11 09:55:16 +04:00
unsigned long flags ;
2006-03-26 13:38:29 +04:00
int i ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " allocating cs " ) ;
2007-01-26 11:56:56 +03:00
if ( ! ( cs = alloc_cs ( drv ) ) ) {
2008-12-26 12:21:29 +03:00
pr_err ( " maximum number of devices exceeded \n " ) ;
2007-01-26 11:56:56 +03:00
return NULL ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " allocating bcs[0..%d] " , channels - 1 ) ;
2006-03-26 13:38:29 +04:00
cs - > bcs = kmalloc ( channels * sizeof ( struct bc_state ) , GFP_KERNEL ) ;
2007-01-26 11:56:56 +03:00
if ( ! cs - > bcs ) {
2008-12-26 12:21:29 +03:00
pr_err ( " out of memory \n " ) ;
2006-03-26 13:38:29 +04:00
goto error ;
2007-01-26 11:56:56 +03:00
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " allocating inbuf " ) ;
2006-03-26 13:38:29 +04:00
cs - > inbuf = kmalloc ( sizeof ( struct inbuf_t ) , GFP_KERNEL ) ;
2007-01-26 11:56:56 +03:00
if ( ! cs - > inbuf ) {
2008-12-26 12:21:29 +03:00
pr_err ( " out of memory \n " ) ;
2006-03-26 13:38:29 +04:00
goto error ;
2007-01-26 11:56:56 +03:00
}
2006-03-26 13:38:29 +04:00
cs - > cs_init = 0 ;
cs - > channels = channels ;
cs - > onechannel = onechannel ;
cs - > ignoreframes = ignoreframes ;
INIT_LIST_HEAD ( & cs - > temp_at_states ) ;
2006-04-11 09:55:16 +04:00
cs - > running = 0 ;
2006-03-26 13:38:29 +04:00
init_timer ( & cs - > timer ) ; /* clear next & prev */
spin_lock_init ( & cs - > ev_lock ) ;
2006-04-11 09:55:16 +04:00
cs - > ev_tail = 0 ;
cs - > ev_head = 0 ;
2006-04-11 09:55:12 +04:00
2006-04-11 09:55:00 +04:00
tasklet_init ( & cs - > event_tasklet , & gigaset_handle_event ,
( unsigned long ) cs ) ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 0 ;
2006-03-26 13:38:29 +04:00
cs - > cur_at_seq = 0 ;
cs - > gotfwver = - 1 ;
cs - > open_count = 0 ;
2006-04-11 09:55:04 +04:00
cs - > dev = NULL ;
2006-03-26 13:38:29 +04:00
cs - > tty = NULL ;
2006-08-08 09:19:37 +04:00
cs - > tty_dev = NULL ;
2006-04-11 09:55:16 +04:00
cs - > cidmode = cidmode ! = 0 ;
2009-05-13 16:44:17 +04:00
cs - > tabnocid = gigaset_tab_nocid ;
cs - > tabcid = gigaset_tab_cid ;
2006-03-26 13:38:29 +04:00
init_waitqueue_head ( & cs - > waitqueue ) ;
cs - > waiting = 0 ;
2008-02-06 12:38:28 +03:00
cs - > mode = M_UNKNOWN ;
cs - > mstate = MS_UNINITIALIZED ;
2006-03-26 13:38:29 +04:00
for ( i = 0 ; i < channels ; + + i ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up bcs[%d].read " , i ) ;
2007-01-26 11:56:56 +03:00
if ( ! gigaset_initbcs ( cs - > bcs + i , cs , i ) ) {
2008-12-26 12:21:29 +03:00
pr_err ( " could not allocate channel %d data \n " , i ) ;
2006-03-26 13:38:29 +04:00
goto error ;
2007-01-26 11:56:56 +03:00
}
2006-03-26 13:38:29 +04:00
}
+ + cs - > cs_init ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up at_state " ) ;
2006-03-26 13:38:29 +04:00
spin_lock_init ( & cs - > lock ) ;
gigaset_at_init ( & cs - > at_state , NULL , cs , 0 ) ;
cs - > dle = 0 ;
cs - > cbytes = 0 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up inbuf " ) ;
2006-03-26 13:38:29 +04:00
if ( onechannel ) { //FIXME distinction necessary?
gigaset_inbuf_init ( cs - > inbuf , cs - > bcs , cs , INS_command ) ;
} else
gigaset_inbuf_init ( cs - > inbuf , NULL , cs , INS_command ) ;
2006-04-11 09:55:16 +04:00
cs - > connected = 0 ;
cs - > isdn_up = 0 ;
2006-03-26 13:38:29 +04:00
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up cmdbuf " ) ;
2006-03-26 13:38:29 +04:00
cs - > cmdbuf = cs - > lastcmdbuf = NULL ;
spin_lock_init ( & cs - > cmdlock ) ;
cs - > curlen = 0 ;
cs - > cmdbytes = 0 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up iif " ) ;
2006-03-26 13:38:29 +04:00
if ( ! gigaset_register_to_LL ( cs , modulename ) ) {
2008-12-26 12:21:29 +03:00
pr_err ( " error registering ISDN device \n " ) ;
2006-03-26 13:38:29 +04:00
goto error ;
}
make_valid ( cs , VALID_ID ) ;
+ + cs - > cs_init ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " setting up hw " ) ;
2008-12-26 12:21:29 +03:00
if ( ! cs - > ops - > initcshw ( cs ) )
2006-03-26 13:38:29 +04:00
goto error ;
+ + cs - > cs_init ;
2007-02-12 11:52:24 +03:00
/* set up character device */
2006-03-26 13:38:29 +04:00
gigaset_if_init ( cs ) ;
2006-04-22 20:43:00 +04:00
/* set up device sysfs */
gigaset_init_dev_sysfs ( cs ) ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
cs - > running = 1 ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-04-11 09:55:03 +04:00
setup_timer ( & cs - > timer , timer_tick , ( unsigned long ) cs ) ;
cs - > timer . expires = jiffies + msecs_to_jiffies ( GIG_TICK ) ;
2006-03-26 13:38:29 +04:00
/* FIXME: can jiffies increase too much until the timer is added?
* Same problem ( ? ) with mod_timer ( ) in timer_tick ( ) . */
add_timer ( & cs - > timer ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " cs initialized " ) ;
2006-03-26 13:38:29 +04:00
return cs ;
2007-01-26 11:56:56 +03:00
error :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INIT , " failed " ) ;
2006-03-26 13:38:29 +04:00
gigaset_freecs ( cs ) ;
return NULL ;
}
EXPORT_SYMBOL_GPL ( gigaset_initcs ) ;
2006-04-22 13:35:30 +04:00
/* ReInitialize the b-channel structure on hangup */
2006-03-26 13:38:29 +04:00
void gigaset_bcs_reinit ( struct bc_state * bcs )
{
struct sk_buff * skb ;
struct cardstate * cs = bcs - > cs ;
unsigned long flags ;
while ( ( skb = skb_dequeue ( & bcs - > squeue ) ) ! = NULL )
dev_kfree_skb ( skb ) ;
2006-04-11 09:55:00 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
2006-03-26 13:38:29 +04:00
clear_at_state ( & bcs - > at_state ) ;
bcs - > at_state . ConState = 0 ;
bcs - > at_state . timer_active = 0 ;
bcs - > at_state . timer_expires = 0 ;
2006-04-11 09:55:04 +04:00
bcs - > at_state . cid = - 1 ; /* No CID defined */
2006-03-26 13:38:29 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
bcs - > inputstate = 0 ;
# ifdef CONFIG_GIGASET_DEBUG
bcs - > emptycount = 0 ;
# endif
bcs - > fcs = PPP_INITFCS ;
bcs - > chstate = 0 ;
bcs - > ignore = cs - > ignoreframes ;
if ( bcs - > ignore )
bcs - > inputstate | = INS_skip_frame ;
cs - > ops - > reinitbcshw ( bcs ) ;
}
static void cleanup_cs ( struct cardstate * cs )
{
struct cmdbuf_t * cb , * tcb ;
int i ;
unsigned long flags ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
2008-02-06 12:38:28 +03:00
cs - > mode = M_UNKNOWN ;
cs - > mstate = MS_UNINITIALIZED ;
2006-03-26 13:38:29 +04:00
clear_at_state ( & cs - > at_state ) ;
dealloc_at_states ( cs ) ;
free_strings ( & cs - > at_state ) ;
gigaset_at_init ( & cs - > at_state , NULL , cs , 0 ) ;
kfree ( cs - > inbuf - > rcvbuf ) ;
cs - > inbuf - > rcvbuf = NULL ;
cs - > inbuf - > inputstate = INS_command ;
2008-02-06 12:38:28 +03:00
cs - > inbuf - > head = 0 ;
cs - > inbuf - > tail = 0 ;
2006-03-26 13:38:29 +04:00
cb = cs - > cmdbuf ;
while ( cb ) {
tcb = cb ;
cb = cb - > next ;
kfree ( tcb ) ;
}
cs - > cmdbuf = cs - > lastcmdbuf = NULL ;
cs - > curlen = 0 ;
cs - > cmdbytes = 0 ;
cs - > gotfwver = - 1 ;
cs - > dle = 0 ;
cs - > cur_at_seq = 0 ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 0 ;
2006-03-26 13:38:29 +04:00
cs - > cbytes = 0 ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
for ( i = 0 ; i < cs - > channels ; + + i ) {
gigaset_freebcs ( cs - > bcs + i ) ;
if ( ! gigaset_initbcs ( cs - > bcs + i , cs , i ) )
2008-12-26 12:21:29 +03:00
pr_err ( " could not allocate channel %d data \n " , i ) ;
2006-03-26 13:38:29 +04:00
}
if ( cs - > waiting ) {
cs - > cmd_result = - ENODEV ;
cs - > waiting = 0 ;
wake_up_interruptible ( & cs - > waitqueue ) ;
}
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_start ( ) - start device operations
* @ cs : device descriptor structure .
*
* Prepares the device for use by setting up communication parameters ,
* scheduling an EV_START event to initiate device initialization , and
* waiting for completion of the initialization .
*
* Return value :
* 1 - success , 0 - error
*/
2006-03-26 13:38:29 +04:00
int gigaset_start ( struct cardstate * cs )
{
2006-04-11 09:55:16 +04:00
unsigned long flags ;
2006-04-11 09:55:12 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) )
2006-03-26 13:38:29 +04:00
return 0 ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
cs - > connected = 1 ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:29 +04:00
2008-02-06 12:38:28 +03:00
if ( cs - > mstate ! = MS_LOCKED ) {
2006-03-26 13:38:29 +04:00
cs - > ops - > set_modem_ctrl ( cs , 0 , TIOCM_DTR | TIOCM_RTS ) ;
cs - > ops - > baud_rate ( cs , B115200 ) ;
cs - > ops - > set_line_ctrl ( cs , CS8 ) ;
cs - > control_state = TIOCM_DTR | TIOCM_RTS ;
} else {
//FIXME use some saved values?
}
cs - > waiting = 1 ;
if ( ! gigaset_add_event ( cs , & cs - > at_state , EV_START , NULL , 0 , NULL ) ) {
cs - > waiting = 0 ;
//FIXME what should we do?
goto error ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling START " ) ;
2006-03-26 13:38:29 +04:00
gigaset_schedule_event ( cs ) ;
wait_event ( cs - > waitqueue , ! cs - > waiting ) ;
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
return 1 ;
error :
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( gigaset_start ) ;
2009-10-06 16:19:01 +04:00
/**
* gigaset_shutdown ( ) - shut down device operations
* @ cs : device descriptor structure .
*
* Deactivates the device by scheduling an EV_SHUTDOWN event and
* waiting for completion of the shutdown .
*
* Return value :
* 0 - success , - 1 - error ( no device associated )
2008-02-06 12:38:29 +03:00
*/
int gigaset_shutdown ( struct cardstate * cs )
2006-03-26 13:38:29 +04:00
{
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
2008-03-07 21:47:08 +03:00
if ( ! ( cs - > flags & VALID_MINOR ) ) {
mutex_unlock ( & cs - > mutex ) ;
2008-02-06 12:38:29 +03:00
return - 1 ;
2008-03-07 21:47:08 +03:00
}
2008-02-06 12:38:29 +03:00
2006-03-26 13:38:29 +04:00
cs - > waiting = 1 ;
if ( ! gigaset_add_event ( cs , & cs - > at_state , EV_SHUTDOWN , NULL , 0 , NULL ) ) {
//FIXME what should we do?
goto exit ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling SHUTDOWN " ) ;
2006-03-26 13:38:29 +04:00
gigaset_schedule_event ( cs ) ;
2007-02-12 11:52:34 +03:00
wait_event ( cs - > waitqueue , ! cs - > waiting ) ;
2006-03-26 13:38:29 +04:00
cleanup_cs ( cs ) ;
exit :
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2008-02-06 12:38:29 +03:00
return 0 ;
2006-03-26 13:38:29 +04:00
}
EXPORT_SYMBOL_GPL ( gigaset_shutdown ) ;
2009-10-06 16:19:01 +04:00
/**
* gigaset_stop ( ) - stop device operations
* @ cs : device descriptor structure .
*
* Stops operations on the device by scheduling an EV_STOP event and
* waiting for completion of the shutdown .
*/
2006-03-26 13:38:29 +04:00
void gigaset_stop ( struct cardstate * cs )
{
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
cs - > waiting = 1 ;
if ( ! gigaset_add_event ( cs , & cs - > at_state , EV_STOP , NULL , 0 , NULL ) ) {
//FIXME what should we do?
goto exit ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling STOP " ) ;
2006-03-26 13:38:29 +04:00
gigaset_schedule_event ( cs ) ;
2007-02-12 11:52:34 +03:00
wait_event ( cs - > waitqueue , ! cs - > waiting ) ;
2006-03-26 13:38:29 +04:00
cleanup_cs ( cs ) ;
exit :
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:29 +04:00
}
EXPORT_SYMBOL_GPL ( gigaset_stop ) ;
static LIST_HEAD ( drivers ) ;
2006-06-27 13:53:55 +04:00
static DEFINE_SPINLOCK ( driver_lock ) ;
2006-03-26 13:38:29 +04:00
struct cardstate * gigaset_get_cs_by_id ( int id )
{
unsigned long flags ;
2007-03-29 12:20:34 +04:00
struct cardstate * ret = NULL ;
struct cardstate * cs ;
2006-03-26 13:38:29 +04:00
struct gigaset_driver * drv ;
unsigned i ;
spin_lock_irqsave ( & driver_lock , flags ) ;
list_for_each_entry ( drv , & drivers , list ) {
spin_lock ( & drv - > lock ) ;
for ( i = 0 ; i < drv - > minors ; + + i ) {
2008-02-06 12:38:29 +03:00
cs = drv - > cs + i ;
if ( ( cs - > flags & VALID_ID ) & & cs - > myid = = id ) {
ret = cs ;
2006-03-26 13:38:29 +04:00
break ;
2008-02-06 12:38:29 +03:00
}
2006-03-26 13:38:29 +04:00
}
spin_unlock ( & drv - > lock ) ;
if ( ret )
break ;
}
spin_unlock_irqrestore ( & driver_lock , flags ) ;
return ret ;
}
void gigaset_debugdrivers ( void )
{
unsigned long flags ;
static struct cardstate * cs ;
struct gigaset_driver * drv ;
unsigned i ;
spin_lock_irqsave ( & driver_lock , flags ) ;
list_for_each_entry ( drv , & drivers , list ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_DRIVER , " driver %p " , drv ) ;
2006-03-26 13:38:29 +04:00
spin_lock ( & drv - > lock ) ;
for ( i = 0 ; i < drv - > minors ; + + i ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_DRIVER , " index %u " , i ) ;
2006-03-26 13:38:29 +04:00
cs = drv - > cs + i ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_DRIVER , " cardstate %p " , cs ) ;
2008-02-06 12:38:29 +03:00
gig_dbg ( DEBUG_DRIVER , " flags 0x%02x " , cs - > flags ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_DRIVER , " minor_index %u " ,
cs - > minor_index ) ;
gig_dbg ( DEBUG_DRIVER , " driver %p " , cs - > driver ) ;
gig_dbg ( DEBUG_DRIVER , " i4l id %d " , cs - > myid ) ;
2006-03-26 13:38:29 +04:00
}
spin_unlock ( & drv - > lock ) ;
}
spin_unlock_irqrestore ( & driver_lock , flags ) ;
}
2006-04-11 09:55:18 +04:00
static struct cardstate * gigaset_get_cs_by_minor ( unsigned minor )
2006-03-26 13:38:29 +04:00
{
unsigned long flags ;
2007-03-29 12:20:34 +04:00
struct cardstate * ret = NULL ;
2006-03-26 13:38:29 +04:00
struct gigaset_driver * drv ;
unsigned index ;
spin_lock_irqsave ( & driver_lock , flags ) ;
list_for_each_entry ( drv , & drivers , list ) {
if ( minor < drv - > minor | | minor > = drv - > minor + drv - > minors )
continue ;
index = minor - drv - > minor ;
spin_lock ( & drv - > lock ) ;
2008-02-06 12:38:29 +03:00
if ( drv - > cs [ index ] . flags & VALID_MINOR )
2006-03-26 13:38:29 +04:00
ret = drv - > cs + index ;
spin_unlock ( & drv - > lock ) ;
if ( ret )
break ;
}
spin_unlock_irqrestore ( & driver_lock , flags ) ;
return ret ;
}
2006-04-11 09:55:18 +04:00
struct cardstate * gigaset_get_cs_by_tty ( struct tty_struct * tty )
{
if ( tty - > index < 0 | | tty - > index > = tty - > driver - > num )
return NULL ;
return gigaset_get_cs_by_minor ( tty - > index + tty - > driver - > minor_start ) ;
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_freedriver ( ) - free all associated ressources of a driver
* @ drv : driver descriptor structure .
*
* Unregisters the driver from the system and deallocates the driver
* structure @ drv and all structures referenced from it .
* All devices should be shut down before calling this .
*/
2006-03-26 13:38:29 +04:00
void gigaset_freedriver ( struct gigaset_driver * drv )
{
unsigned long flags ;
spin_lock_irqsave ( & driver_lock , flags ) ;
list_del ( & drv - > list ) ;
spin_unlock_irqrestore ( & driver_lock , flags ) ;
gigaset_if_freedriver ( drv ) ;
kfree ( drv - > cs ) ;
kfree ( drv ) ;
}
EXPORT_SYMBOL_GPL ( gigaset_freedriver ) ;
2009-10-06 16:19:01 +04:00
/**
* gigaset_initdriver ( ) - initialize driver structure
* @ minor : First minor number
* @ minors : Number of minors this driver can handle
* @ procname : Name of the driver
* @ devname : Name of the device files ( prefix without minor number )
*
2006-03-26 13:38:29 +04:00
* Allocate and initialize gigaset_driver structure . Initialize interface .
2009-10-06 16:19:01 +04:00
*
* Return value :
2006-04-11 09:55:04 +04:00
* Pointer to the gigaset_driver structure on success , NULL on failure .
2006-03-26 13:38:29 +04:00
*/
struct gigaset_driver * gigaset_initdriver ( unsigned minor , unsigned minors ,
2006-04-11 09:55:04 +04:00
const char * procname ,
const char * devname ,
const struct gigaset_ops * ops ,
struct module * owner )
2006-03-26 13:38:29 +04:00
{
struct gigaset_driver * drv ;
unsigned long flags ;
unsigned i ;
drv = kmalloc ( sizeof * drv , GFP_KERNEL ) ;
if ( ! drv )
return NULL ;
2006-04-11 09:55:19 +04:00
2006-03-26 13:38:29 +04:00
drv - > have_tty = 0 ;
drv - > minor = minor ;
drv - > minors = minors ;
spin_lock_init ( & drv - > lock ) ;
drv - > blocked = 0 ;
drv - > ops = ops ;
drv - > owner = owner ;
INIT_LIST_HEAD ( & drv - > list ) ;
drv - > cs = kmalloc ( minors * sizeof * drv - > cs , GFP_KERNEL ) ;
if ( ! drv - > cs )
2007-01-26 11:56:56 +03:00
goto error ;
2006-04-11 09:55:19 +04:00
2006-03-26 13:38:29 +04:00
for ( i = 0 ; i < minors ; + + i ) {
2008-02-06 12:38:29 +03:00
drv - > cs [ i ] . flags = 0 ;
2006-03-26 13:38:29 +04:00
drv - > cs [ i ] . driver = drv ;
drv - > cs [ i ] . ops = drv - > ops ;
drv - > cs [ i ] . minor_index = i ;
2008-03-07 21:47:08 +03:00
mutex_init ( & drv - > cs [ i ] . mutex ) ;
2006-03-26 13:38:29 +04:00
}
2005-06-21 08:15:16 +04:00
gigaset_if_initdriver ( drv , procname , devname ) ;
2006-03-26 13:38:29 +04:00
spin_lock_irqsave ( & driver_lock , flags ) ;
list_add ( & drv - > list , & drivers ) ;
spin_unlock_irqrestore ( & driver_lock , flags ) ;
return drv ;
2007-01-26 11:56:56 +03:00
error :
2006-03-26 13:38:29 +04:00
kfree ( drv - > cs ) ;
kfree ( drv ) ;
return NULL ;
}
EXPORT_SYMBOL_GPL ( gigaset_initdriver ) ;
2009-10-06 16:19:01 +04:00
/**
* gigaset_blockdriver ( ) - block driver
* @ drv : driver descriptor structure .
*
* Prevents the driver from attaching new devices , in preparation for
* deregistration .
*/
2006-03-26 13:38:29 +04:00
void gigaset_blockdriver ( struct gigaset_driver * drv )
{
drv - > blocked = 1 ;
}
EXPORT_SYMBOL_GPL ( gigaset_blockdriver ) ;
static int __init gigaset_init_module ( void )
{
/* in accordance with the principle of least astonishment,
* setting the ' debug ' parameter to 1 activates a sensible
* set of default debug levels
*/
if ( gigaset_debuglevel = = 1 )
gigaset_debuglevel = DEBUG_DEFAULT ;
2009-10-06 16:18:41 +04:00
pr_info ( DRIVER_DESC DRIVER_DESC_DEBUG " \n " ) ;
2006-03-26 13:38:29 +04:00
return 0 ;
}
static void __exit gigaset_exit_module ( void )
{
}
module_init ( gigaset_init_module ) ;
module_exit ( gigaset_exit_module ) ;
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;