2010-03-30 17:56:23 +04:00
/*
* Copyright ( C ) ST - Ericsson AB 2010
* Author : Sjur Brendeland / sjur . brandeland @ stericsson . com
* 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/slab.h>
# include <net/caif/caif_layer.h>
# include <net/caif/cfsrvl.h>
# include <net/caif/cfpkt.h>
# define VEI_PAYLOAD 0x00
# define VEI_CMD_BIT 0x80
# define VEI_FLOW_OFF 0x81
# define VEI_FLOW_ON 0x80
# define VEI_SET_PIN 0x82
2011-01-14 01:19:52 +03:00
2010-03-30 17:56:23 +04:00
# define container_obj(layr) container_of(layr, struct cfsrvl, layer)
static int cfvei_receive ( struct cflayer * layr , struct cfpkt * pkt ) ;
static int cfvei_transmit ( struct cflayer * layr , struct cfpkt * pkt ) ;
struct cflayer * cfvei_create ( u8 channel_id , struct dev_info * dev_info )
{
2011-08-25 17:22:24 +04:00
struct cfsrvl * vei = kzalloc ( sizeof ( struct cfsrvl ) , GFP_ATOMIC ) ;
if ( ! vei )
2010-03-30 17:56:23 +04:00
return NULL ;
caif_assert ( offsetof ( struct cfsrvl , layer ) = = 0 ) ;
2010-06-17 10:55:38 +04:00
cfsrvl_init ( vei , channel_id , dev_info , true ) ;
2010-03-30 17:56:23 +04:00
vei - > layer . receive = cfvei_receive ;
vei - > layer . transmit = cfvei_transmit ;
snprintf ( vei - > layer . name , CAIF_LAYER_NAME_SZ - 1 , " vei%d " , channel_id ) ;
return & vei - > layer ;
}
static int cfvei_receive ( struct cflayer * layr , struct cfpkt * pkt )
{
u8 cmd ;
int ret ;
caif_assert ( layr - > up ! = NULL ) ;
caif_assert ( layr - > receive ! = NULL ) ;
caif_assert ( layr - > ctrlcmd ! = NULL ) ;
if ( cfpkt_extr_head ( pkt , & cmd , 1 ) < 0 ) {
2010-09-06 01:31:11 +04:00
pr_err ( " Packet is erroneous! \n " ) ;
2010-03-30 17:56:23 +04:00
cfpkt_destroy ( pkt ) ;
return - EPROTO ;
}
switch ( cmd ) {
case VEI_PAYLOAD :
ret = layr - > up - > receive ( layr - > up , pkt ) ;
return ret ;
case VEI_FLOW_OFF :
layr - > ctrlcmd ( layr , CAIF_CTRLCMD_FLOW_OFF_IND , 0 ) ;
cfpkt_destroy ( pkt ) ;
return 0 ;
case VEI_FLOW_ON :
layr - > ctrlcmd ( layr , CAIF_CTRLCMD_FLOW_ON_IND , 0 ) ;
cfpkt_destroy ( pkt ) ;
return 0 ;
case VEI_SET_PIN : /* SET RS232 PIN */
cfpkt_destroy ( pkt ) ;
return 0 ;
default : /* SET RS232 PIN */
2010-09-06 01:31:11 +04:00
pr_warn ( " Unknown VEI control packet %d (0x%x)! \n " , cmd , cmd ) ;
2010-03-30 17:56:23 +04:00
cfpkt_destroy ( pkt ) ;
return - EPROTO ;
}
}
static int cfvei_transmit ( struct cflayer * layr , struct cfpkt * pkt )
{
u8 tmp = 0 ;
struct caif_payload_info * info ;
int ret ;
struct cfsrvl * service = container_obj ( layr ) ;
if ( ! cfsrvl_ready ( service , & ret ) )
2011-05-13 06:44:06 +04:00
goto err ;
2010-03-30 17:56:23 +04:00
caif_assert ( layr - > dn ! = NULL ) ;
caif_assert ( layr - > dn - > transmit ! = NULL ) ;
if ( cfpkt_add_head ( pkt , & tmp , 1 ) < 0 ) {
2010-09-06 01:31:11 +04:00
pr_err ( " Packet is erroneous! \n " ) ;
2011-05-13 06:44:06 +04:00
ret = - EPROTO ;
goto err ;
2010-03-30 17:56:23 +04:00
}
/* Add info-> for MUX-layer to route the packet out. */
info = cfpkt_info ( pkt ) ;
info - > channel_id = service - > layer . id ;
info - > hdr_len = 1 ;
info - > dev_info = & service - > dev_info ;
2011-04-11 14:43:51 +04:00
return layr - > dn - > transmit ( layr - > dn , pkt ) ;
2011-05-13 06:44:06 +04:00
err :
cfpkt_destroy ( pkt ) ;
return ret ;
2010-03-30 17:56:23 +04:00
}