2010-03-30 17:56:23 +04:00
/*
* Copyright ( C ) ST - Ericsson AB 2010
2013-04-23 03:57:01 +04:00
* Author : Sjur Brendeland
2010-03-30 17:56:23 +04:00
* License terms : GNU General Public License ( GPL ) version 2
*/
2010-09-06 01:31:11 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
2010-03-30 17:56:23 +04:00
# include <linux/stddef.h>
# include <linux/spinlock.h>
# include <linux/slab.h>
2012-04-12 12:27:24 +04:00
# include <linux/pkt_sched.h>
2010-03-30 17:56:23 +04:00
# include <net/caif/caif_layer.h>
# include <net/caif/cfpkt.h>
# include <net/caif/cfctrl.h>
# define container_obj(layr) container_of(layr, struct cfctrl, serv.layer)
# define UTILITY_NAME_LENGTH 16
# define CFPKT_CTRL_PKT_LEN 20
# ifdef CAIF_NO_LOOP
static int handle_loop ( struct cfctrl * ctrl ,
2013-03-06 23:39:57 +04:00
int cmd , struct cfpkt * pkt ) {
2010-06-17 10:55:40 +04:00
return - 1 ;
2010-03-30 17:56:23 +04:00
}
# else
static int handle_loop ( struct cfctrl * ctrl ,
2013-03-06 23:39:57 +04:00
int cmd , struct cfpkt * pkt ) ;
2010-03-30 17:56:23 +04:00
# endif
static int cfctrl_recv ( struct cflayer * layr , struct cfpkt * pkt ) ;
static void cfctrl_ctrlcmd ( struct cflayer * layr , enum caif_ctrlcmd ctrl ,
int phyid ) ;
struct cflayer * cfctrl_create ( void )
{
2010-04-28 12:54:37 +04:00
struct dev_info dev_info ;
2010-03-30 17:56:23 +04:00
struct cfctrl * this =
2011-08-25 17:22:24 +04:00
kzalloc ( sizeof ( struct cfctrl ) , GFP_ATOMIC ) ;
if ( ! this )
2010-03-30 17:56:23 +04:00
return NULL ;
caif_assert ( offsetof ( struct cfctrl , serv . layer ) = = 0 ) ;
2010-04-28 12:54:37 +04:00
memset ( & dev_info , 0 , sizeof ( dev_info ) ) ;
dev_info . id = 0xff ;
2010-06-17 10:55:38 +04:00
cfsrvl_init ( & this - > serv , 0 , & dev_info , false ) ;
2010-03-30 17:56:23 +04:00
atomic_set ( & this - > req_seq_no , 1 ) ;
atomic_set ( & this - > rsp_seq_no , 1 ) ;
this - > serv . layer . receive = cfctrl_recv ;
sprintf ( this - > serv . layer . name , " ctrl " ) ;
this - > serv . layer . ctrlcmd = cfctrl_ctrlcmd ;
2011-05-13 06:44:06 +04:00
# ifndef CAIF_NO_LOOP
2010-03-30 17:56:23 +04:00
spin_lock_init ( & this - > loop_linkid_lock ) ;
2011-05-13 06:44:06 +04:00
this - > loop_linkid = 1 ;
# endif
2010-05-21 06:16:08 +04:00
spin_lock_init ( & this - > info_list_lock ) ;
INIT_LIST_HEAD ( & this - > list ) ;
2010-03-30 17:56:23 +04:00
return & this - > serv . layer ;
}
2011-05-13 06:44:06 +04:00
void cfctrl_remove ( struct cflayer * layer )
{
struct cfctrl_request_info * p , * tmp ;
struct cfctrl * ctrl = container_obj ( layer ) ;
spin_lock_bh ( & ctrl - > info_list_lock ) ;
list_for_each_entry_safe ( p , tmp , & ctrl - > list , list ) {
list_del ( & p - > list ) ;
kfree ( p ) ;
}
spin_unlock_bh ( & ctrl - > info_list_lock ) ;
kfree ( layer ) ;
}
2011-04-11 14:43:50 +04:00
static bool param_eq ( const struct cfctrl_link_param * p1 ,
2013-03-06 23:39:57 +04:00
const struct cfctrl_link_param * p2 )
2010-03-30 17:56:23 +04:00
{
bool eq =
p1 - > linktype = = p2 - > linktype & &
p1 - > priority = = p2 - > priority & &
p1 - > phyid = = p2 - > phyid & &
p1 - > endpoint = = p2 - > endpoint & & p1 - > chtype = = p2 - > chtype ;
if ( ! eq )
return false ;
switch ( p1 - > linktype ) {
case CFCTRL_SRV_VEI :
return true ;
case CFCTRL_SRV_DATAGRAM :
return p1 - > u . datagram . connid = = p2 - > u . datagram . connid ;
case CFCTRL_SRV_RFM :
return
p1 - > u . rfm . connid = = p2 - > u . rfm . connid & &
strcmp ( p1 - > u . rfm . volume , p2 - > u . rfm . volume ) = = 0 ;
case CFCTRL_SRV_UTIL :
return
p1 - > u . utility . fifosize_kb = = p2 - > u . utility . fifosize_kb
& & p1 - > u . utility . fifosize_bufs = =
p2 - > u . utility . fifosize_bufs
& & strcmp ( p1 - > u . utility . name , p2 - > u . utility . name ) = = 0
& & p1 - > u . utility . paramlen = = p2 - > u . utility . paramlen
& & memcmp ( p1 - > u . utility . params , p2 - > u . utility . params ,
p1 - > u . utility . paramlen ) = = 0 ;
case CFCTRL_SRV_VIDEO :
return p1 - > u . video . connid = = p2 - > u . video . connid ;
case CFCTRL_SRV_DBG :
return true ;
case CFCTRL_SRV_DECM :
return false ;
default :
return false ;
}
return false ;
}
2011-04-11 14:43:50 +04:00
static bool cfctrl_req_eq ( const struct cfctrl_request_info * r1 ,
const struct cfctrl_request_info * r2 )
2010-03-30 17:56:23 +04:00
{
if ( r1 - > cmd ! = r2 - > cmd )
return false ;
if ( r1 - > cmd = = CFCTRL_CMD_LINK_SETUP )
return param_eq ( & r1 - > param , & r2 - > param ) ;
else
return r1 - > channel_id = = r2 - > channel_id ;
}
/* Insert request at the end */
2011-04-11 14:43:50 +04:00
static void cfctrl_insert_req ( struct cfctrl * ctrl ,
2010-03-30 17:56:23 +04:00
struct cfctrl_request_info * req )
{
2011-05-13 06:44:06 +04:00
spin_lock_bh ( & ctrl - > info_list_lock ) ;
2010-03-30 17:56:23 +04:00
atomic_inc ( & ctrl - > req_seq_no ) ;
req - > sequence_no = atomic_read ( & ctrl - > req_seq_no ) ;
2010-05-21 06:16:08 +04:00
list_add_tail ( & req - > list , & ctrl - > list ) ;
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & ctrl - > info_list_lock ) ;
2010-03-30 17:56:23 +04:00
}
/* Compare and remove request */
2011-04-11 14:43:50 +04:00
static struct cfctrl_request_info * cfctrl_remove_req ( struct cfctrl * ctrl ,
struct cfctrl_request_info * req )
2010-03-30 17:56:23 +04:00
{
2010-05-21 06:16:08 +04:00
struct cfctrl_request_info * p , * tmp , * first ;
2010-03-30 17:56:23 +04:00
2010-05-21 06:16:08 +04:00
first = list_first_entry ( & ctrl - > list , struct cfctrl_request_info , list ) ;
2010-03-30 17:56:23 +04:00
2010-05-21 06:16:08 +04:00
list_for_each_entry_safe ( p , tmp , & ctrl - > list , list ) {
if ( cfctrl_req_eq ( req , p ) ) {
if ( p ! = first )
2010-09-06 01:31:11 +04:00
pr_warn ( " Requests are not received in order \n " ) ;
2010-05-21 06:16:08 +04:00
2010-03-30 17:56:23 +04:00
atomic_set ( & ctrl - > rsp_seq_no ,
2010-05-21 06:16:08 +04:00
p - > sequence_no ) ;
list_del ( & p - > list ) ;
goto out ;
2010-03-30 17:56:23 +04:00
}
}
2010-05-21 06:16:08 +04:00
p = NULL ;
out :
return p ;
2010-03-30 17:56:23 +04:00
}
struct cfctrl_rsp * cfctrl_get_respfuncs ( struct cflayer * layer )
{
struct cfctrl * this = container_obj ( layer ) ;
return & this - > res ;
}
static void init_info ( struct caif_payload_info * info , struct cfctrl * cfctrl )
{
info - > hdr_len = 0 ;
info - > channel_id = cfctrl - > serv . layer . id ;
info - > dev_info = & cfctrl - > serv . dev_info ;
}
void cfctrl_enum_req ( struct cflayer * layer , u8 physlinkid )
{
2012-06-25 11:49:35 +04:00
struct cfpkt * pkt ;
2010-03-30 17:56:23 +04:00
struct cfctrl * cfctrl = container_obj ( layer ) ;
2011-05-22 15:18:50 +04:00
struct cflayer * dn = cfctrl - > serv . layer . dn ;
2012-06-25 11:49:35 +04:00
2011-05-22 15:18:50 +04:00
if ( ! dn ) {
pr_debug ( " not able to send enum request \n " ) ;
return ;
}
2012-06-25 11:49:35 +04:00
pkt = cfpkt_create ( CFPKT_CTRL_PKT_LEN ) ;
if ( ! pkt )
return ;
2010-03-30 17:56:23 +04:00
caif_assert ( offsetof ( struct cfctrl , serv . layer ) = = 0 ) ;
init_info ( cfpkt_info ( pkt ) , cfctrl ) ;
cfpkt_info ( pkt ) - > dev_info - > id = physlinkid ;
cfctrl - > serv . dev_info . id = physlinkid ;
cfpkt_addbdy ( pkt , CFCTRL_CMD_ENUM ) ;
cfpkt_addbdy ( pkt , physlinkid ) ;
2012-04-12 12:27:24 +04:00
cfpkt_set_prio ( pkt , TC_PRIO_CONTROL ) ;
2011-05-22 15:18:50 +04:00
dn - > transmit ( dn , pkt ) ;
2010-03-30 17:56:23 +04:00
}
2010-04-28 12:54:37 +04:00
int cfctrl_linkup_request ( struct cflayer * layer ,
2013-03-06 23:39:57 +04:00
struct cfctrl_link_param * param ,
struct cflayer * user_layer )
2010-03-30 17:56:23 +04:00
{
struct cfctrl * cfctrl = container_obj ( layer ) ;
u32 tmp32 ;
u16 tmp16 ;
u8 tmp8 ;
struct cfctrl_request_info * req ;
int ret ;
char utility_name [ 16 ] ;
2011-05-13 06:44:06 +04:00
struct cfpkt * pkt ;
2011-05-22 15:18:50 +04:00
struct cflayer * dn = cfctrl - > serv . layer . dn ;
if ( ! dn ) {
pr_debug ( " not able to send linkup request \n " ) ;
return - ENODEV ;
}
2011-05-13 06:44:06 +04:00
if ( cfctrl_cancel_req ( layer , user_layer ) > 0 ) {
/* Slight Paranoia, check if already connecting */
pr_err ( " Duplicate connect request for same client \n " ) ;
WARN_ON ( 1 ) ;
return - EALREADY ;
}
pkt = cfpkt_create ( CFPKT_CTRL_PKT_LEN ) ;
2011-08-25 17:22:24 +04:00
if ( ! pkt )
2010-04-28 12:54:37 +04:00
return - ENOMEM ;
2010-03-30 17:56:23 +04:00
cfpkt_addbdy ( pkt , CFCTRL_CMD_LINK_SETUP ) ;
2011-05-13 06:44:06 +04:00
cfpkt_addbdy ( pkt , ( param - > chtype < < 4 ) | param - > linktype ) ;
cfpkt_addbdy ( pkt , ( param - > priority < < 3 ) | param - > phyid ) ;
2010-03-30 17:56:23 +04:00
cfpkt_addbdy ( pkt , param - > endpoint & 0x03 ) ;
switch ( param - > linktype ) {
case CFCTRL_SRV_VEI :
break ;
case CFCTRL_SRV_VIDEO :
cfpkt_addbdy ( pkt , ( u8 ) param - > u . video . connid ) ;
break ;
case CFCTRL_SRV_DBG :
break ;
case CFCTRL_SRV_DATAGRAM :
tmp32 = cpu_to_le32 ( param - > u . datagram . connid ) ;
cfpkt_add_body ( pkt , & tmp32 , 4 ) ;
break ;
case CFCTRL_SRV_RFM :
/* Construct a frame, convert DatagramConnectionID to network
* format long and copy it out . . .
*/
tmp32 = cpu_to_le32 ( param - > u . rfm . connid ) ;
cfpkt_add_body ( pkt , & tmp32 , 4 ) ;
/* Add volume name, including zero termination... */
cfpkt_add_body ( pkt , param - > u . rfm . volume ,
strlen ( param - > u . rfm . volume ) + 1 ) ;
break ;
case CFCTRL_SRV_UTIL :
tmp16 = cpu_to_le16 ( param - > u . utility . fifosize_kb ) ;
cfpkt_add_body ( pkt , & tmp16 , 2 ) ;
tmp16 = cpu_to_le16 ( param - > u . utility . fifosize_bufs ) ;
cfpkt_add_body ( pkt , & tmp16 , 2 ) ;
memset ( utility_name , 0 , sizeof ( utility_name ) ) ;
2018-01-08 14:43:00 +03:00
strlcpy ( utility_name , param - > u . utility . name ,
UTILITY_NAME_LENGTH ) ;
2010-03-30 17:56:23 +04:00
cfpkt_add_body ( pkt , utility_name , UTILITY_NAME_LENGTH ) ;
tmp8 = param - > u . utility . paramlen ;
cfpkt_add_body ( pkt , & tmp8 , 1 ) ;
cfpkt_add_body ( pkt , param - > u . utility . params ,
param - > u . utility . paramlen ) ;
break ;
default :
2010-09-06 01:31:11 +04:00
pr_warn ( " Request setup of bad link type = %d \n " ,
param - > linktype ) ;
2010-04-28 12:54:37 +04:00
return - EINVAL ;
2010-03-30 17:56:23 +04:00
}
2010-05-13 14:03:32 +04:00
req = kzalloc ( sizeof ( * req ) , GFP_KERNEL ) ;
2011-08-25 17:22:24 +04:00
if ( ! req )
2010-04-28 12:54:37 +04:00
return - ENOMEM ;
2010-03-30 17:56:23 +04:00
req - > client_layer = user_layer ;
req - > cmd = CFCTRL_CMD_LINK_SETUP ;
req - > param = * param ;
cfctrl_insert_req ( cfctrl , req ) ;
init_info ( cfpkt_info ( pkt ) , cfctrl ) ;
2010-04-28 12:54:37 +04:00
/*
* NOTE : Always send linkup and linkdown request on the same
* device as the payload . Otherwise old queued up payload
* might arrive with the newly allocated channel ID .
*/
2010-03-30 17:56:23 +04:00
cfpkt_info ( pkt ) - > dev_info - > id = param - > phyid ;
2012-04-12 12:27:24 +04:00
cfpkt_set_prio ( pkt , TC_PRIO_CONTROL ) ;
2010-03-30 17:56:23 +04:00
ret =
2011-05-22 15:18:50 +04:00
dn - > transmit ( dn , pkt ) ;
2010-03-30 17:56:23 +04:00
if ( ret < 0 ) {
2011-05-13 06:44:06 +04:00
int count ;
count = cfctrl_cancel_req ( & cfctrl - > serv . layer ,
user_layer ) ;
2013-09-05 08:11:19 +04:00
if ( count ! = 1 ) {
2011-05-13 06:44:06 +04:00
pr_err ( " Could not remove request (%d) " , count ) ;
return - ENODEV ;
2013-09-05 08:11:19 +04:00
}
2010-03-30 17:56:23 +04:00
}
2010-04-28 12:54:37 +04:00
return 0 ;
2010-03-30 17:56:23 +04:00
}
int cfctrl_linkdown_req ( struct cflayer * layer , u8 channelid ,
2013-03-06 23:39:57 +04:00
struct cflayer * client )
2010-03-30 17:56:23 +04:00
{
int ret ;
2012-06-25 11:49:35 +04:00
struct cfpkt * pkt ;
2010-03-30 17:56:23 +04:00
struct cfctrl * cfctrl = container_obj ( layer ) ;
2011-05-22 15:18:50 +04:00
struct cflayer * dn = cfctrl - > serv . layer . dn ;
if ( ! dn ) {
pr_debug ( " not able to send link-down request \n " ) ;
return - ENODEV ;
}
2012-06-25 11:49:35 +04:00
pkt = cfpkt_create ( CFPKT_CTRL_PKT_LEN ) ;
if ( ! pkt )
return - ENOMEM ;
2010-03-30 17:56:23 +04:00
cfpkt_addbdy ( pkt , CFCTRL_CMD_LINK_DESTROY ) ;
cfpkt_addbdy ( pkt , channelid ) ;
init_info ( cfpkt_info ( pkt ) , cfctrl ) ;
2012-04-12 12:27:24 +04:00
cfpkt_set_prio ( pkt , TC_PRIO_CONTROL ) ;
2010-03-30 17:56:23 +04:00
ret =
2011-05-22 15:18:50 +04:00
dn - > transmit ( dn , pkt ) ;
2011-05-13 06:44:06 +04:00
# ifndef CAIF_NO_LOOP
cfctrl - > loop_linkused [ channelid ] = 0 ;
# endif
2010-03-30 17:56:23 +04:00
return ret ;
}
2011-05-13 06:44:06 +04:00
int cfctrl_cancel_req ( struct cflayer * layr , struct cflayer * adap_layer )
2010-04-28 12:54:37 +04:00
{
2010-05-21 06:16:08 +04:00
struct cfctrl_request_info * p , * tmp ;
2010-04-28 12:54:37 +04:00
struct cfctrl * ctrl = container_obj ( layr ) ;
2011-05-13 06:44:06 +04:00
int found = 0 ;
spin_lock_bh ( & ctrl - > info_list_lock ) ;
2010-05-21 06:16:08 +04:00
list_for_each_entry_safe ( p , tmp , & ctrl - > list , list ) {
if ( p - > client_layer = = adap_layer ) {
list_del ( & p - > list ) ;
kfree ( p ) ;
2011-05-13 06:44:06 +04:00
found + + ;
2010-04-28 12:54:37 +04:00
}
}
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & ctrl - > info_list_lock ) ;
return found ;
2010-04-28 12:54:37 +04:00
}
2010-03-30 17:56:23 +04:00
static int cfctrl_recv ( struct cflayer * layer , struct cfpkt * pkt )
{
u8 cmdrsp ;
u8 cmd ;
int ret = - 1 ;
u16 tmp16 ;
u8 len ;
u8 param [ 255 ] ;
u8 linkid ;
struct cfctrl * cfctrl = container_obj ( layer ) ;
struct cfctrl_request_info rsp , * req ;
cfpkt_extr_head ( pkt , & cmdrsp , 1 ) ;
cmd = cmdrsp & CFCTRL_CMD_MASK ;
if ( cmd ! = CFCTRL_CMD_LINK_ERR
2011-05-22 15:18:52 +04:00
& & CFCTRL_RSP_BIT ! = ( CFCTRL_RSP_BIT & cmdrsp )
& & CFCTRL_ERR_BIT ! = ( CFCTRL_ERR_BIT & cmdrsp ) ) {
2010-06-17 10:55:40 +04:00
if ( handle_loop ( cfctrl , cmd , pkt ) ! = 0 )
2010-04-28 12:54:37 +04:00
cmdrsp | = CFCTRL_ERR_BIT ;
2010-03-30 17:56:23 +04:00
}
switch ( cmd ) {
case CFCTRL_CMD_LINK_SETUP :
{
enum cfctrl_srv serv ;
enum cfctrl_srv servtype ;
u8 endpoint ;
u8 physlinkid ;
u8 prio ;
u8 tmp ;
u32 tmp32 ;
u8 * cp ;
int i ;
struct cfctrl_link_param linkparam ;
memset ( & linkparam , 0 , sizeof ( linkparam ) ) ;
cfpkt_extr_head ( pkt , & tmp , 1 ) ;
serv = tmp & CFCTRL_SRV_MASK ;
linkparam . linktype = serv ;
servtype = tmp > > 4 ;
linkparam . chtype = servtype ;
cfpkt_extr_head ( pkt , & tmp , 1 ) ;
physlinkid = tmp & 0x07 ;
prio = tmp > > 3 ;
linkparam . priority = prio ;
linkparam . phyid = physlinkid ;
cfpkt_extr_head ( pkt , & endpoint , 1 ) ;
linkparam . endpoint = endpoint & 0x03 ;
switch ( serv ) {
case CFCTRL_SRV_VEI :
case CFCTRL_SRV_DBG :
2010-04-28 12:54:37 +04:00
if ( CFCTRL_ERR_BIT & cmdrsp )
break ;
2010-03-30 17:56:23 +04:00
/* Link ID */
cfpkt_extr_head ( pkt , & linkid , 1 ) ;
break ;
case CFCTRL_SRV_VIDEO :
cfpkt_extr_head ( pkt , & tmp , 1 ) ;
linkparam . u . video . connid = tmp ;
2010-04-28 12:54:37 +04:00
if ( CFCTRL_ERR_BIT & cmdrsp )
break ;
2010-03-30 17:56:23 +04:00
/* Link ID */
cfpkt_extr_head ( pkt , & linkid , 1 ) ;
break ;
case CFCTRL_SRV_DATAGRAM :
cfpkt_extr_head ( pkt , & tmp32 , 4 ) ;
linkparam . u . datagram . connid =
le32_to_cpu ( tmp32 ) ;
2010-04-28 12:54:37 +04:00
if ( CFCTRL_ERR_BIT & cmdrsp )
break ;
2010-03-30 17:56:23 +04:00
/* Link ID */
cfpkt_extr_head ( pkt , & linkid , 1 ) ;
break ;
case CFCTRL_SRV_RFM :
/* Construct a frame, convert
* DatagramConnectionID
* to network format long and copy it out . . .
*/
cfpkt_extr_head ( pkt , & tmp32 , 4 ) ;
linkparam . u . rfm . connid =
le32_to_cpu ( tmp32 ) ;
cp = ( u8 * ) linkparam . u . rfm . volume ;
for ( cfpkt_extr_head ( pkt , & tmp , 1 ) ;
cfpkt_more ( pkt ) & & tmp ! = ' \0 ' ;
cfpkt_extr_head ( pkt , & tmp , 1 ) )
* cp + + = tmp ;
* cp = ' \0 ' ;
2010-04-28 12:54:37 +04:00
if ( CFCTRL_ERR_BIT & cmdrsp )
break ;
2010-03-30 17:56:23 +04:00
/* Link ID */
cfpkt_extr_head ( pkt , & linkid , 1 ) ;
break ;
case CFCTRL_SRV_UTIL :
/* Construct a frame, convert
* DatagramConnectionID
* to network format long and copy it out . . .
*/
/* Fifosize KB */
cfpkt_extr_head ( pkt , & tmp16 , 2 ) ;
linkparam . u . utility . fifosize_kb =
le16_to_cpu ( tmp16 ) ;
/* Fifosize bufs */
cfpkt_extr_head ( pkt , & tmp16 , 2 ) ;
linkparam . u . utility . fifosize_bufs =
le16_to_cpu ( tmp16 ) ;
/* name */
cp = ( u8 * ) linkparam . u . utility . name ;
caif_assert ( sizeof ( linkparam . u . utility . name )
> = UTILITY_NAME_LENGTH ) ;
for ( i = 0 ;
i < UTILITY_NAME_LENGTH
& & cfpkt_more ( pkt ) ; i + + ) {
cfpkt_extr_head ( pkt , & tmp , 1 ) ;
* cp + + = tmp ;
}
/* Length */
cfpkt_extr_head ( pkt , & len , 1 ) ;
linkparam . u . utility . paramlen = len ;
/* Param Data */
cp = linkparam . u . utility . params ;
while ( cfpkt_more ( pkt ) & & len - - ) {
cfpkt_extr_head ( pkt , & tmp , 1 ) ;
* cp + + = tmp ;
}
2010-04-28 12:54:37 +04:00
if ( CFCTRL_ERR_BIT & cmdrsp )
break ;
2010-03-30 17:56:23 +04:00
/* Link ID */
cfpkt_extr_head ( pkt , & linkid , 1 ) ;
/* Length */
cfpkt_extr_head ( pkt , & len , 1 ) ;
/* Param Data */
cfpkt_extr_head ( pkt , & param , len ) ;
break ;
default :
2011-05-22 15:18:50 +04:00
pr_warn ( " Request setup, invalid type (%d) \n " ,
2010-09-06 01:31:11 +04:00
serv ) ;
2010-03-30 17:56:23 +04:00
goto error ;
}
rsp . cmd = cmd ;
rsp . param = linkparam ;
2011-05-13 06:44:06 +04:00
spin_lock_bh ( & cfctrl - > info_list_lock ) ;
2010-03-30 17:56:23 +04:00
req = cfctrl_remove_req ( cfctrl , & rsp ) ;
if ( CFCTRL_ERR_BIT = = ( CFCTRL_ERR_BIT & cmdrsp ) | |
cfpkt_erroneous ( pkt ) ) {
2011-05-22 15:18:50 +04:00
pr_err ( " Invalid O/E bit or parse error "
" on CAIF control channel \n " ) ;
2010-03-30 17:56:23 +04:00
cfctrl - > res . reject_rsp ( cfctrl - > serv . layer . up ,
0 ,
req ? req - > client_layer
: NULL ) ;
} else {
cfctrl - > res . linksetup_rsp ( cfctrl - > serv .
layer . up , linkid ,
serv , physlinkid ,
req ? req - >
client_layer : NULL ) ;
}
2012-11-20 04:53:58 +04:00
kfree ( req ) ;
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & cfctrl - > info_list_lock ) ;
2010-03-30 17:56:23 +04:00
}
break ;
case CFCTRL_CMD_LINK_DESTROY :
cfpkt_extr_head ( pkt , & linkid , 1 ) ;
2010-04-28 12:54:37 +04:00
cfctrl - > res . linkdestroy_rsp ( cfctrl - > serv . layer . up , linkid ) ;
2010-03-30 17:56:23 +04:00
break ;
case CFCTRL_CMD_LINK_ERR :
2010-09-06 01:31:11 +04:00
pr_err ( " Frame Error Indication received \n " ) ;
2010-03-30 17:56:23 +04:00
cfctrl - > res . linkerror_ind ( ) ;
break ;
case CFCTRL_CMD_ENUM :
cfctrl - > res . enum_rsp ( ) ;
break ;
case CFCTRL_CMD_SLEEP :
cfctrl - > res . sleep_rsp ( ) ;
break ;
case CFCTRL_CMD_WAKE :
cfctrl - > res . wake_rsp ( ) ;
break ;
case CFCTRL_CMD_LINK_RECONF :
cfctrl - > res . restart_rsp ( ) ;
break ;
case CFCTRL_CMD_RADIO_SET :
cfctrl - > res . radioset_rsp ( ) ;
break ;
default :
2010-09-06 01:31:11 +04:00
pr_err ( " Unrecognized Control Frame \n " ) ;
2010-03-30 17:56:23 +04:00
goto error ;
}
ret = 0 ;
error :
cfpkt_destroy ( pkt ) ;
return ret ;
}
static void cfctrl_ctrlcmd ( struct cflayer * layr , enum caif_ctrlcmd ctrl ,
2013-03-06 23:39:57 +04:00
int phyid )
2010-03-30 17:56:23 +04:00
{
struct cfctrl * this = container_obj ( layr ) ;
switch ( ctrl ) {
case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND :
case CAIF_CTRLCMD_FLOW_OFF_IND :
2011-05-13 06:44:06 +04:00
spin_lock_bh ( & this - > info_list_lock ) ;
2011-05-22 15:18:50 +04:00
if ( ! list_empty ( & this - > list ) )
2010-09-06 01:31:11 +04:00
pr_debug ( " Received flow off in control layer \n " ) ;
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & this - > info_list_lock ) ;
2010-03-30 17:56:23 +04:00
break ;
2011-05-13 06:44:06 +04:00
case _CAIF_CTRLCMD_PHYIF_DOWN_IND : {
struct cfctrl_request_info * p , * tmp ;
/* Find all connect request and report failure */
spin_lock_bh ( & this - > info_list_lock ) ;
list_for_each_entry_safe ( p , tmp , & this - > list , list ) {
if ( p - > param . phyid = = phyid ) {
list_del ( & p - > list ) ;
p - > client_layer - > ctrlcmd ( p - > client_layer ,
CAIF_CTRLCMD_INIT_FAIL_RSP ,
phyid ) ;
kfree ( p ) ;
}
}
spin_unlock_bh ( & this - > info_list_lock ) ;
break ;
}
2010-03-30 17:56:23 +04:00
default :
break ;
}
}
# ifndef CAIF_NO_LOOP
static int handle_loop ( struct cfctrl * ctrl , int cmd , struct cfpkt * pkt )
{
static int last_linkid ;
2011-05-13 06:44:06 +04:00
static int dec ;
2010-03-30 17:56:23 +04:00
u8 linkid , linktype , tmp ;
switch ( cmd ) {
case CFCTRL_CMD_LINK_SETUP :
2011-05-13 06:44:06 +04:00
spin_lock_bh ( & ctrl - > loop_linkid_lock ) ;
if ( ! dec ) {
2011-05-22 15:18:52 +04:00
for ( linkid = last_linkid + 1 ; linkid < 254 ; linkid + + )
2011-05-13 06:44:06 +04:00
if ( ! ctrl - > loop_linkused [ linkid ] )
goto found ;
}
dec = 1 ;
2011-05-22 15:18:52 +04:00
for ( linkid = last_linkid - 1 ; linkid > 1 ; linkid - - )
2010-03-30 17:56:23 +04:00
if ( ! ctrl - > loop_linkused [ linkid ] )
goto found ;
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & ctrl - > loop_linkid_lock ) ;
2011-05-22 15:18:52 +04:00
return - 1 ;
2010-03-30 17:56:23 +04:00
found :
2011-05-13 06:44:06 +04:00
if ( linkid < 10 )
dec = 0 ;
2010-03-30 17:56:23 +04:00
if ( ! ctrl - > loop_linkused [ linkid ] )
ctrl - > loop_linkused [ linkid ] = 1 ;
last_linkid = linkid ;
cfpkt_add_trail ( pkt , & linkid , 1 ) ;
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & ctrl - > loop_linkid_lock ) ;
2010-03-30 17:56:23 +04:00
cfpkt_peek_head ( pkt , & linktype , 1 ) ;
if ( linktype = = CFCTRL_SRV_UTIL ) {
tmp = 0x01 ;
cfpkt_add_trail ( pkt , & tmp , 1 ) ;
cfpkt_add_trail ( pkt , & tmp , 1 ) ;
}
break ;
case CFCTRL_CMD_LINK_DESTROY :
2011-05-13 06:44:06 +04:00
spin_lock_bh ( & ctrl - > loop_linkid_lock ) ;
2010-03-30 17:56:23 +04:00
cfpkt_peek_head ( pkt , & linkid , 1 ) ;
ctrl - > loop_linkused [ linkid ] = 0 ;
2011-05-13 06:44:06 +04:00
spin_unlock_bh ( & ctrl - > loop_linkid_lock ) ;
2010-03-30 17:56:23 +04:00
break ;
default :
break ;
}
2010-06-17 10:55:40 +04:00
return 0 ;
2010-03-30 17:56:23 +04:00
}
# endif