From 09009f30de188c847d72039e6250bfea56a0f887 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Tue, 30 Mar 2010 13:56:21 +0000 Subject: net-caif: add CAIF core protocol stack header files Add include files for the CAIF Core protocol stack. caif_layer.h - Defines the structure of the CAIF protocol layers cfcnfg.h - CAIF Configuration Module for services and link layers cfctrl.h - CAIF Control Protocol Layer cffrml.h - CAIF Framing Layer cfmuxl.h - CAIF Muxing Layer cfpkt.h - CAIF Packet layer (skb helper functions) cfserl.h - CAIF Serial Layer cfsrvl.h - CAIF Service Layer Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- include/net/caif/caif_layer.h | 283 ++++++++++++++++++++++++++++++++++++++++++ include/net/caif/cfcnfg.h | 133 ++++++++++++++++++++ include/net/caif/cfctrl.h | 138 ++++++++++++++++++++ include/net/caif/cffrml.h | 16 +++ include/net/caif/cfmuxl.h | 22 ++++ include/net/caif/cfpkt.h | 274 ++++++++++++++++++++++++++++++++++++++++ include/net/caif/cfserl.h | 12 ++ include/net/caif/cfsrvl.h | 34 +++++ 8 files changed, 912 insertions(+) create mode 100644 include/net/caif/caif_layer.h create mode 100644 include/net/caif/cfcnfg.h create mode 100644 include/net/caif/cfctrl.h create mode 100644 include/net/caif/cffrml.h create mode 100644 include/net/caif/cfmuxl.h create mode 100644 include/net/caif/cfpkt.h create mode 100644 include/net/caif/cfserl.h create mode 100644 include/net/caif/cfsrvl.h (limited to 'include/net/caif') diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h new file mode 100644 index 000000000000..25c472f0e5b8 --- /dev/null +++ b/include/net/caif/caif_layer.h @@ -0,0 +1,283 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland / sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_LAYER_H_ +#define CAIF_LAYER_H_ + +#include + +struct cflayer; +struct cfpkt; +struct cfpktq; +struct caif_payload_info; +struct caif_packet_funcs; + +#define CAIF_MAX_FRAMESIZE 4096 +#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64) +#define CAIF_NEEDED_HEADROOM (10) +#define CAIF_NEEDED_TAILROOM (2) + +#define CAIF_LAYER_NAME_SZ 16 +#define CAIF_SUCCESS 1 +#define CAIF_FAILURE 0 + +/** + * caif_assert() - Assert function for CAIF. + * @assert: expression to evaluate. + * + * This function will print a error message and a do WARN_ON if the + * assertion failes. Normally this will do a stack up at the current location. + */ +#define caif_assert(assert) \ +do { \ + if (!(assert)) { \ + pr_err("caif:Assert detected:'%s'\n", #assert); \ + WARN_ON(!(assert)); \ + } \ +} while (0) + + +/** + * enum caif_ctrlcmd - CAIF Stack Control Signaling sent in layer.ctrlcmd(). + * + * @CAIF_CTRLCMD_FLOW_OFF_IND: Flow Control is OFF, transmit function + * should stop sending data + * + * @CAIF_CTRLCMD_FLOW_ON_IND: Flow Control is ON, transmit function + * can start sending data + * + * @CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: Remote end modem has decided to close + * down channel + * + * @CAIF_CTRLCMD_INIT_RSP: Called initially when the layer below + * has finished initialization + * + * @CAIF_CTRLCMD_DEINIT_RSP: Called when de-initialization is + * complete + * + * @CAIF_CTRLCMD_INIT_FAIL_RSP: Called if initialization fails + * + * @_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: CAIF Link layer temporarily cannot + * send more packets. + * @_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND: Called if CAIF Link layer is able + * to send packets again. + * @_CAIF_CTRLCMD_PHYIF_DOWN_IND: Called if CAIF Link layer is going + * down. + * + * These commands are sent upwards in the CAIF stack to the CAIF Client. + * They are used for signaling originating from the modem or CAIF Link Layer. + * These are either responses (*_RSP) or events (*_IND). + */ +enum caif_ctrlcmd { + CAIF_CTRLCMD_FLOW_OFF_IND, + CAIF_CTRLCMD_FLOW_ON_IND, + CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, + CAIF_CTRLCMD_INIT_RSP, + CAIF_CTRLCMD_DEINIT_RSP, + CAIF_CTRLCMD_INIT_FAIL_RSP, + _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, + _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND, + _CAIF_CTRLCMD_PHYIF_DOWN_IND, +}; + +/** + * enum caif_modemcmd - Modem Control Signaling, sent from CAIF Client + * to the CAIF Link Layer or modem. + * + * @CAIF_MODEMCMD_FLOW_ON_REQ: Flow Control is ON, transmit function + * can start sending data. + * + * @CAIF_MODEMCMD_FLOW_OFF_REQ: Flow Control is OFF, transmit function + * should stop sending data. + * + * @_CAIF_MODEMCMD_PHYIF_USEFULL: Notify physical layer that it is in use + * + * @_CAIF_MODEMCMD_PHYIF_USELESS: Notify physical layer that it is + * no longer in use. + * + * These are requests sent 'downwards' in the stack. + * Flow ON, OFF can be indicated to the modem. + */ +enum caif_modemcmd { + CAIF_MODEMCMD_FLOW_ON_REQ = 0, + CAIF_MODEMCMD_FLOW_OFF_REQ = 1, + _CAIF_MODEMCMD_PHYIF_USEFULL = 3, + _CAIF_MODEMCMD_PHYIF_USELESS = 4 +}; + +/** + * enum caif_direction - CAIF Packet Direction. + * Indicate if a packet is to be sent out or to be received in. + * @CAIF_DIR_IN: Incoming packet received. + * @CAIF_DIR_OUT: Outgoing packet to be transmitted. + */ +enum caif_direction { + CAIF_DIR_IN = 0, + CAIF_DIR_OUT = 1 +}; + +/** + * struct cflayer - CAIF Stack layer. + * Defines the framework for the CAIF Core Stack. + * @up: Pointer up to the layer above. + * @dn: Pointer down to the layer below. + * @node: List node used when layer participate in a list. + * @receive: Packet receive function. + * @transmit: Packet transmit funciton. + * @ctrlcmd: Used for control signalling upwards in the stack. + * @modemcmd: Used for control signaling downwards in the stack. + * @prio: Priority of this layer. + * @id: The identity of this layer + * @type: The type of this layer + * @name: Name of the layer. + * + * This structure defines the layered structure in CAIF. + * + * It defines CAIF layering structure, used by all CAIF Layers and the + * layers interfacing CAIF. + * + * In order to integrate with CAIF an adaptation layer on top of the CAIF stack + * and PHY layer below the CAIF stack + * must be implemented. These layer must follow the design principles below. + * + * Principles for layering of protocol layers: + * - All layers must use this structure. If embedding it, then place this + * structure first in the layer specific structure. + * + * - Each layer should not depend on any others layer private data. + * + * - In order to send data upwards do + * layer->up->receive(layer->up, packet); + * + * - In order to send data downwards do + * layer->dn->transmit(layer->dn, info, packet); + */ +struct cflayer { + struct cflayer *up; + struct cflayer *dn; + struct list_head node; + + /* + * receive() - Receive Function. + * Contract: Each layer must implement a receive function passing the + * CAIF packets upwards in the stack. + * Packet handling rules: + * - The CAIF packet (cfpkt) cannot be accessed after + * passing it to the next layer using up->receive(). + * - If parsing of the packet fails, the packet must be + * destroyed and -1 returned from the function. + * - If parsing succeeds (and above layers return OK) then + * the function must return a value > 0. + * + * Returns result < 0 indicates an error, 0 or positive value + * indicates success. + * + * @layr: Pointer to the current layer the receive function is + * implemented for (this pointer). + * @cfpkt: Pointer to CaifPacket to be handled. + */ + int (*receive)(struct cflayer *layr, struct cfpkt *cfpkt); + + /* + * transmit() - Transmit Function. + * Contract: Each layer must implement a transmit function passing the + * CAIF packet downwards in the stack. + * Packet handling rules: + * - The CAIF packet (cfpkt) ownership is passed to the + * transmit function. This means that the the packet + * cannot be accessed after passing it to the below + * layer using dn->transmit(). + * + * - If transmit fails, however, the ownership is returned + * to thecaller. The caller of "dn->transmit()" must + * destroy or resend packet. + * + * - Return value less than zero means error, zero or + * greater than zero means OK. + * + * result < 0 indicates an error, 0 or positive value + * indicate success. + * + * @layr: Pointer to the current layer the receive function + * isimplemented for (this pointer). + * @cfpkt: Pointer to CaifPacket to be handled. + */ + int (*transmit) (struct cflayer *layr, struct cfpkt *cfpkt); + + /* + * cttrlcmd() - Control Function upwards in CAIF Stack. + * Used for signaling responses (CAIF_CTRLCMD_*_RSP) + * and asynchronous events from the modem (CAIF_CTRLCMD_*_IND) + * + * @layr: Pointer to the current layer the receive function + * is implemented for (this pointer). + * @ctrl: Control Command. + */ + void (*ctrlcmd) (struct cflayer *layr, enum caif_ctrlcmd ctrl, + int phyid); + + /* + * modemctrl() - Control Function used for controlling the modem. + * Used to signal down-wards in the CAIF stack. + * Returns 0 on success, < 0 upon failure. + * + * @layr: Pointer to the current layer the receive function + * is implemented for (this pointer). + * @ctrl: Control Command. + */ + int (*modemcmd) (struct cflayer *layr, enum caif_modemcmd ctrl); + + unsigned short prio; + unsigned int id; + unsigned int type; + char name[CAIF_LAYER_NAME_SZ]; +}; + +/** + * layer_set_up() - Set the up pointer for a specified layer. + * @layr: Layer where up pointer shall be set. + * @above: Layer above. + */ +#define layer_set_up(layr, above) ((layr)->up = (struct cflayer *)(above)) + +/** + * layer_set_dn() - Set the down pointer for a specified layer. + * @layr: Layer where down pointer shall be set. + * @below: Layer below. + */ +#define layer_set_dn(layr, below) ((layr)->dn = (struct cflayer *)(below)) + +/** + * struct dev_info - Physical Device info information about physical layer. + * @dev: Pointer to native physical device. + * @id: Physical ID of the physical connection used by the + * logical CAIF connection. Used by service layers to + * identify their physical id to Caif MUX (CFMUXL)so + * that the MUX can add the correct physical ID to the + * packet. + */ +struct dev_info { + void *dev; + unsigned int id; +}; + +/** + * struct caif_payload_info - Payload information embedded in packet (sk_buff). + * + * @dev_info: Information about the receiving device. + * + * @hdr_len: Header length, used to align pay load on 32bit boundary. + * + * @channel_id: Channel ID of the logical CAIF connection. + * Used by mux to insert channel id into the caif packet. + */ +struct caif_payload_info { + struct dev_info *dev_info; + unsigned short hdr_len; + unsigned short channel_id; +}; + +#endif /* CAIF_LAYER_H_ */ diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h new file mode 100644 index 000000000000..366082c5d435 --- /dev/null +++ b/include/net/caif/cfcnfg.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFCNFG_H_ +#define CFCNFG_H_ +#include +#include +#include + +struct cfcnfg; + +/** + * enum cfcnfg_phy_type - Types of physical layers defined in CAIF Stack + * + * @CFPHYTYPE_FRAG: Fragmented frames physical interface. + * @CFPHYTYPE_CAIF: Generic CAIF physical interface + */ +enum cfcnfg_phy_type { + CFPHYTYPE_FRAG = 1, + CFPHYTYPE_CAIF, + CFPHYTYPE_MAX +}; + +/** + * enum cfcnfg_phy_preference - Physical preference HW Abstraction + * + * @CFPHYPREF_UNSPECIFIED: Default physical interface + * + * @CFPHYPREF_LOW_LAT: Default physical interface for low-latency + * traffic + * @CFPHYPREF_HIGH_BW: Default physical interface for high-bandwidth + * traffic + * @CFPHYPREF_LOOP: TEST only Loopback interface simulating modem + * responses. + * + */ +enum cfcnfg_phy_preference { + CFPHYPREF_UNSPECIFIED, + CFPHYPREF_LOW_LAT, + CFPHYPREF_HIGH_BW, + CFPHYPREF_LOOP +}; + +/** + * cfcnfg_create() - Create the CAIF configuration object. + */ +struct cfcnfg *cfcnfg_create(void); + +/** + * cfcnfg_remove() - Remove the CFCNFG object + * @cfg: config object + */ +void cfcnfg_remove(struct cfcnfg *cfg); + +/** + * cfcnfg_add_phy_layer() - Adds a physical layer to the CAIF stack. + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @phy_type: Specifies the type of physical interface, e.g. + * CFPHYTYPE_FRAG. + * @dev: Pointer to link layer device + * @phy_layer: Specify the physical layer. The transmit function + * MUST be set in the structure. + * @phyid: The assigned physical ID for this layer, used in + * cfcnfg_add_adapt_layer to specify PHY for the link. + * @pref: The phy (link layer) preference. + * @fcs: Specify if checksum is used in CAIF Framing Layer. + * @stx: Specify if Start Of Frame eXtention is used. + */ + +void +cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, + void *dev, struct cflayer *phy_layer, u16 *phyid, + enum cfcnfg_phy_preference pref, + bool fcs, bool stx); + +/** + * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack. + * + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @phy_layer: Adaptation layer to be removed. + */ +int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); + +/** + * cfcnfg_del_adapt_layer - Deletes an adaptation layer from the CAIF stack. + * + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @adap_layer: Adaptation layer to be removed. + */ +int cfcnfg_del_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer); + +/** + * cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack. + * + * The adaptation Layer is where the interface to application or higher-level + * driver functionality is implemented. + * + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @param: Link setup parameters. + * @adap_layer: Specify the adaptation layer; the receive and + * flow-control functions MUST be set in the structure. + * + */ +int +cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, + struct cfctrl_link_param *param, + struct cflayer *adap_layer); + +/** + * cfcnfg_get_phyid() - Get physical ID, given type. + * Returns one of the physical interfaces matching the given type. + * Zero if no match is found. + * @cnfg: Configuration object + * @phy_pref: Caif Link Layer preference + */ +struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, + enum cfcnfg_phy_preference phy_pref); + +/** + * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer + * @cnfg: Configuration object + * @name: Name of the Physical Layer (Caif Link Layer) + */ +int cfcnfg_get_named(struct cfcnfg *cnfg, char *name); + +#endif /* CFCNFG_H_ */ diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h new file mode 100644 index 000000000000..dee25b86caa0 --- /dev/null +++ b/include/net/caif/cfctrl.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFCTRL_H_ +#define CFCTRL_H_ +#include +#include + +/* CAIF Control packet commands */ +enum cfctrl_cmd { + CFCTRL_CMD_LINK_SETUP = 0, + CFCTRL_CMD_LINK_DESTROY = 1, + CFCTRL_CMD_LINK_ERR = 2, + CFCTRL_CMD_ENUM = 3, + CFCTRL_CMD_SLEEP = 4, + CFCTRL_CMD_WAKE = 5, + CFCTRL_CMD_LINK_RECONF = 6, + CFCTRL_CMD_START_REASON = 7, + CFCTRL_CMD_RADIO_SET = 8, + CFCTRL_CMD_MODEM_SET = 9, + CFCTRL_CMD_MASK = 0xf +}; + +/* Channel types */ +enum cfctrl_srv { + CFCTRL_SRV_DECM = 0, + CFCTRL_SRV_VEI = 1, + CFCTRL_SRV_VIDEO = 2, + CFCTRL_SRV_DBG = 3, + CFCTRL_SRV_DATAGRAM = 4, + CFCTRL_SRV_RFM = 5, + CFCTRL_SRV_UTIL = 6, + CFCTRL_SRV_MASK = 0xf +}; + +#define CFCTRL_RSP_BIT 0x20 +#define CFCTRL_ERR_BIT 0x10 + +struct cfctrl_rsp { + void (*linksetup_rsp)(struct cflayer *layer, u8 linkid, + enum cfctrl_srv serv, u8 phyid, + struct cflayer *adapt_layer); + void (*linkdestroy_rsp)(struct cflayer *layer, u8 linkid, + struct cflayer *client_layer); + void (*linkerror_ind)(void); + void (*enum_rsp)(void); + void (*sleep_rsp)(void); + void (*wake_rsp)(void); + void (*restart_rsp)(void); + void (*radioset_rsp)(void); + void (*reject_rsp)(struct cflayer *layer, u8 linkid, + struct cflayer *client_layer);; +}; + +/* Link Setup Parameters for CAIF-Links. */ +struct cfctrl_link_param { + enum cfctrl_srv linktype;/* (T3,T0) Type of Channel */ + u8 priority; /* (P4,P0) Priority of the channel */ + u8 phyid; /* (U2-U0) Physical interface to connect */ + u8 endpoint; /* (E1,E0) Endpoint for data channels */ + u8 chtype; /* (H1,H0) Channel-Type, applies to + * VEI, DEBUG */ + union { + struct { + u8 connid; /* (D7,D0) Video LinkId */ + } video; + + struct { + u32 connid; /* (N31,Ngit0) Connection ID used + * for Datagram */ + } datagram; + + struct { + u32 connid; /* Connection ID used for RFM */ + char volume[20]; /* Volume to mount for RFM */ + } rfm; /* Configuration for RFM */ + + struct { + u16 fifosize_kb; /* Psock FIFO size in KB */ + u16 fifosize_bufs; /* Psock # signal buffers */ + char name[16]; /* Name of the PSOCK service */ + u8 params[255]; /* Link setup Parameters> */ + u16 paramlen; /* Length of Link Setup + * Parameters */ + } utility; /* Configuration for Utility Links (Psock) */ + } u; +}; + +/* This structure is used internally in CFCTRL */ +struct cfctrl_request_info { + int sequence_no; + enum cfctrl_cmd cmd; + u8 channel_id; + struct cfctrl_link_param param; + struct cfctrl_request_info *next; + struct cflayer *client_layer; +}; + +struct cfctrl { + struct cfsrvl serv; + struct cfctrl_rsp res; + atomic_t req_seq_no; + atomic_t rsp_seq_no; + struct cfctrl_request_info *first_req; + /* Protects from simultaneous access to first_req list */ + spinlock_t info_list_lock; +#ifndef CAIF_NO_LOOP + u8 loop_linkid; + int loop_linkused[256]; + /* Protects simultaneous access to loop_linkid and loop_linkused */ + spinlock_t loop_linkid_lock; +#endif + +}; + +void cfctrl_enum_req(struct cflayer *cfctrl, u8 physlinkid); +void cfctrl_linkup_request(struct cflayer *cfctrl, + struct cfctrl_link_param *param, + struct cflayer *user_layer); +int cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid, + struct cflayer *client); +void cfctrl_sleep_req(struct cflayer *cfctrl); +void cfctrl_wake_req(struct cflayer *cfctrl); +void cfctrl_getstartreason_req(struct cflayer *cfctrl); +struct cflayer *cfctrl_create(void); +void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn); +void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up); +struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer); +bool cfctrl_req_eq(struct cfctrl_request_info *r1, + struct cfctrl_request_info *r2); +void cfctrl_insert_req(struct cfctrl *ctrl, + struct cfctrl_request_info *req); +struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, + struct cfctrl_request_info *req); +#endif /* CFCTRL_H_ */ diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h new file mode 100644 index 000000000000..3f14d2e1ce61 --- /dev/null +++ b/include/net/caif/cffrml.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFFRML_H_ +#define CFFRML_H_ +#include + +struct cffrml; +struct cflayer *cffrml_create(u16 phyid, bool DoFCS); +void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up); +void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn); + +#endif /* CFFRML_H_ */ diff --git a/include/net/caif/cfmuxl.h b/include/net/caif/cfmuxl.h new file mode 100644 index 000000000000..4e1b4f33423e --- /dev/null +++ b/include/net/caif/cfmuxl.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFMUXL_H_ +#define CFMUXL_H_ +#include + +struct cfsrvl; +struct cffrml; + +struct cflayer *cfmuxl_create(void); +int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid); +struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid); +int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *up, u8 phyid); +struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 linkid); +bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid); +u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id); + +#endif /* CFMUXL_H_ */ diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h new file mode 100644 index 000000000000..fbc681beff52 --- /dev/null +++ b/include/net/caif/cfpkt.h @@ -0,0 +1,274 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFPKT_H_ +#define CFPKT_H_ +#include +#include +struct cfpkt; + +/* Create a CAIF packet. + * len: Length of packet to be created + * @return New packet. + */ +struct cfpkt *cfpkt_create(u16 len); + +/* Create a CAIF packet. + * data Data to copy. + * len Length of packet to be created + * @return New packet. + */ +struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len); +/* + * Destroy a CAIF Packet. + * pkt Packet to be destoyed. + */ +void cfpkt_destroy(struct cfpkt *pkt); + +/* + * Extract header from packet. + * + * pkt Packet to extract header data from. + * data Pointer to copy the header data into. + * len Length of head data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len); + +/* + * Peek header from packet. + * Reads data from packet without changing packet. + * + * pkt Packet to extract header data from. + * data Pointer to copy the header data into. + * len Length of head data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len); + +/* + * Extract header from trailer (end of packet). + * + * pkt Packet to extract header data from. + * data Pointer to copy the trailer data into. + * len Length of header data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_extr_trail(struct cfpkt *pkt, void *data, u16 len); + +/* + * Add header to packet. + * + * + * pkt Packet to add header data to. + * data Pointer to data to copy into the header. + * len Length of header data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_add_head(struct cfpkt *pkt, const void *data, u16 len); + +/* + * Add trailer to packet. + * + * + * pkt Packet to add trailer data to. + * data Pointer to data to copy into the trailer. + * len Length of trailer data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len); + +/* + * Pad trailer on packet. + * Moves data pointer in packet, no content copied. + * + * pkt Packet in which to pad trailer. + * len Length of padding to add. + * @return zero on success and error code upon failure + */ +int cfpkt_pad_trail(struct cfpkt *pkt, u16 len); + +/* + * Add a single byte to packet body (tail). + * + * pkt Packet in which to add byte. + * data Byte to add. + * @return zero on success and error code upon failure + */ +int cfpkt_addbdy(struct cfpkt *pkt, const u8 data); + +/* + * Add a data to packet body (tail). + * + * pkt Packet in which to add data. + * data Pointer to data to copy into the packet body. + * len Length of data to add. + * @return zero on success and error code upon failure + */ +int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len); + +/* + * Checks whether there are more data to process in packet. + * pkt Packet to check. + * @return true if more data are available in packet false otherwise + */ +bool cfpkt_more(struct cfpkt *pkt); + +/* + * Checks whether the packet is erroneous, + * i.e. if it has been attempted to extract more data than available in packet + * or writing more data than has been allocated in cfpkt_create(). + * pkt Packet to check. + * @return true on error false otherwise + */ +bool cfpkt_erroneous(struct cfpkt *pkt); + +/* + * Get the packet length. + * pkt Packet to get length from. + * @return Number of bytes in packet. + */ +u16 cfpkt_getlen(struct cfpkt *pkt); + +/* + * Set the packet length, by adjusting the trailer pointer according to length. + * pkt Packet to set length. + * len Packet length. + * @return Number of bytes in packet. + */ +int cfpkt_setlen(struct cfpkt *pkt, u16 len); + +/* + * cfpkt_append - Appends a packet's data to another packet. + * dstpkt: Packet to append data into, WILL BE FREED BY THIS FUNCTION + * addpkt: Packet to be appended and automatically released, + * WILL BE FREED BY THIS FUNCTION. + * expectlen: Packet's expected total length. This should be considered + * as a hint. + * NB: Input packets will be destroyed after appending and cannot be used + * after calling this function. + * @return The new appended packet. + */ +struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt, + u16 expectlen); + +/* + * cfpkt_split - Split a packet into two packets at the specified split point. + * pkt: Packet to be split (will contain the first part of the data on exit) + * pos: Position to split packet in two parts. + * @return The new packet, containing the second part of the data. + */ +struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos); + +/* + * Iteration function, iterates the packet buffers from start to end. + * + * Checksum iteration function used to iterate buffers + * (we may have packets consisting of a chain of buffers) + * pkt: Packet to calculate checksum for + * iter_func: Function pointer to iteration function + * chks: Checksum calculated so far. + * buf: Pointer to the buffer to checksum + * len: Length of buf. + * data: Initial checksum value. + * @return Checksum of buffer. + */ + +u16 cfpkt_iterate(struct cfpkt *pkt, + u16 (*iter_func)(u16 chks, void *buf, u16 len), + u16 data); + +/* Append by giving user access to packet buffer + * cfpkt Packet to append to + * buf Buffer inside pkt that user shall copy data into + * buflen Length of buffer and number of bytes added to packet + * @return 0 on error, 1 on success + */ +int cfpkt_raw_append(struct cfpkt *cfpkt, void **buf, unsigned int buflen); + +/* Extract by giving user access to packet buffer + * cfpkt Packet to extract from + * buf Buffer inside pkt that user shall copy data from + * buflen Length of buffer and number of bytes removed from packet + * @return 0 on error, 1 on success + */ +int cfpkt_raw_extract(struct cfpkt *cfpkt, void **buf, unsigned int buflen); + +/* Map from a "native" packet (e.g. Linux Socket Buffer) to a CAIF packet. + * dir - Direction indicating whether this packet is to be sent or received. + * nativepkt - The native packet to be transformed to a CAIF packet + * @return The mapped CAIF Packet CFPKT. + */ +struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt); + +/* Map from a CAIF packet to a "native" packet (e.g. Linux Socket Buffer). + * pkt - The CAIF packet to be transformed into a "native" packet. + * @return The native packet transformed from a CAIF packet. + */ +void *cfpkt_tonative(struct cfpkt *pkt); + +/* + * Insert a packet in the packet queue. + * pktq Packet queue to insert into + * pkt Packet to be inserted in queue + * prio Priority of packet + */ +void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, + unsigned short prio); + +/* + * Remove a packet from the packet queue. + * pktq Packet queue to fetch packets from. + * @return Dequeued packet. + */ +struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq); + +/* + * Peek into a packet from the packet queue. + * pktq Packet queue to fetch packets from. + * @return Peeked packet. + */ +struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq); + +/* + * Initiates the packet queue. + * @return Pointer to new packet queue. + */ +struct cfpktq *cfpktq_create(void); + +/* + * Get the number of packets in the queue. + * pktq Packet queue to fetch count from. + * @return Number of packets in queue. + */ +int cfpkt_qcount(struct cfpktq *pktq); + +/* + * Put content of packet into buffer for debuging purposes. + * pkt Packet to copy data from + * buf Buffer to copy data into + * buflen Length of data to copy + * @return Pointer to copied data + */ +char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen); + +/* + * Clones a packet and releases the original packet. + * This is used for taking ownership of a packet e.g queueing. + * pkt Packet to clone and release. + * @return Cloned packet. + */ +struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt); + + +/* + * Returns packet information for a packet. + * pkt Packet to get info from; + * @return Packet information + */ +struct caif_payload_info *cfpkt_info(struct cfpkt *pkt); +/*! @} */ +#endif /* CFPKT_H_ */ diff --git a/include/net/caif/cfserl.h b/include/net/caif/cfserl.h new file mode 100644 index 000000000000..b8374321b362 --- /dev/null +++ b/include/net/caif/cfserl.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFSERL_H_ +#define CFSERL_H_ +#include + +struct cflayer *cfserl_create(int type, int instance, bool use_stx); +#endif /* CFSERL_H_ */ diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h new file mode 100644 index 000000000000..b2a12db20cd2 --- /dev/null +++ b/include/net/caif/cfsrvl.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFSRVL_H_ +#define CFSRVL_H_ +#include +#include +#include +struct cfsrvl { + struct cflayer layer; + bool open; + bool phy_flow_on; + bool modem_flow_on; + struct dev_info dev_info; +}; + +struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info); +bool cfsrvl_phyid_match(struct cflayer *layer, int phyid); +void cfservl_destroy(struct cflayer *layer); +void cfsrvl_init(struct cfsrvl *service, + u8 channel_id, + struct dev_info *dev_info); +bool cfsrvl_ready(struct cfsrvl *service, int *err); +u8 cfsrvl_getphyid(struct cflayer *layer); + +#endif /* CFSRVL_H_ */ -- cgit v1.2.3 From 2721c5b9dd2a56a9710021c00146bb26ba8dd7b3 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Tue, 30 Mar 2010 13:56:22 +0000 Subject: net-caif: add CAIF Link layer device header files Header files for CAIF Link layer net-device, and link-layer registration. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- include/net/caif/caif_dev.h | 90 ++++++++++++++++++++++++++++++++++++++++++ include/net/caif/caif_device.h | 55 ++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 include/net/caif/caif_dev.h create mode 100644 include/net/caif/caif_device.h (limited to 'include/net/caif') diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h new file mode 100644 index 000000000000..42a7c7867849 --- /dev/null +++ b/include/net/caif/caif_dev.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_DEV_H_ +#define CAIF_DEV_H_ + +#include +#include +#include +#include + +/** + * struct caif_param - CAIF parameters. + * @size: Length of data + * @data: Binary Data Blob + */ +struct caif_param { + u16 size; + u8 data[256]; +}; + +/** + * caif_connect_request - Request data for CAIF channel setup. + * @sockaddr: Socket address to connect. + * @priority: Priority of the connection. + * @link_selector: Link selector (high bandwidth or low latency) + * @link_name: Name of the CAIF Link Layer to use. + * + * This struct is used when connecting a CAIF channel. + * It contains all CAIF channel configuration options. + */ +struct caif_connect_request { + int protocol; + struct sockaddr_caif sockaddr; + enum caif_channel_priority priority; + enum caif_link_selector link_selector; + char link_name[16]; + struct caif_param param; +}; + +/** + * caif_connect_client - Connect a client to CAIF Core Stack. + * @config: Channel setup parameters, specifying what address + * to connect on the Modem. + * @client_layer: User implementation of client layer. This layer + * MUST have receive and control callback functions + * implemented. + * + * This function connects a CAIF channel. The Client must implement + * the struct cflayer. This layer represents the Client layer and holds + * receive functions and control callback functions. Control callback + * function will receive information about connect/disconnect responses, + * flow control etc (see enum caif_control). + * E.g. CAIF Socket will call this function for each socket it connects + * and have one client_layer instance for each socket. + */ +int caif_connect_client(struct caif_connect_request *config, + struct cflayer *client_layer); + +/** + * caif_disconnect_client - Disconnects a client from the CAIF stack. + * + * @client_layer: Client layer to be removed. + */ +int caif_disconnect_client(struct cflayer *client_layer); + +/** + * connect_req_to_link_param - Translate configuration parameters + * from socket format to internal format. + * @cnfg: Pointer to configuration handler + * @con_req: Configuration parameters supplied in function + * caif_connect_client + * @channel_setup_param: Parameters supplied to the CAIF Core stack for + * setting up channels. + * + */ +int connect_req_to_link_param(struct cfcnfg *cnfg, + struct caif_connect_request *con_req, + struct cfctrl_link_param *channel_setup_param); + +/** + * get_caif_conf() - Get the configuration handler. + */ +struct cfcnfg *get_caif_conf(void); + + +#endif /* CAIF_DEV_H_ */ diff --git a/include/net/caif/caif_device.h b/include/net/caif/caif_device.h new file mode 100644 index 000000000000..d02f044adb8a --- /dev/null +++ b/include/net/caif/caif_device.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_DEVICE_H_ +#define CAIF_DEVICE_H_ +#include +#include +#include +#include +#include + +/** + * struct caif_dev_common - data shared between CAIF drivers and stack. + * @flowctrl: Flow Control callback function. This function is + * supplied by CAIF Core Stack and is used by CAIF + * Link Layer to send flow-stop to CAIF Core. + * The flow information will be distributed to all + * clients of CAIF. + * + * @link_select: Profile of device, either high-bandwidth or + * low-latency. This member is set by CAIF Link + * Layer Device in order to indicate if this device + * is a high bandwidth or low latency device. + * + * @use_frag: CAIF Frames may be fragmented. + * Is set by CAIF Link Layer in order to indicate if the + * interface receives fragmented frames that must be + * assembled by CAIF Core Layer. + * + * @use_fcs: Indicate if Frame CheckSum (fcs) is used. + * Is set if the physical interface is + * using Frame Checksum on the CAIF Frames. + * + * @use_stx: Indicate STart of frame eXtension (stx) in use. + * Is set if the CAIF Link Layer expects + * CAIF Frames to start with the STX byte. + * + * This structure is shared between the CAIF drivers and the CAIF stack. + * It is used by the device to register its behavior. + * CAIF Core layer must set the member flowctrl in order to supply + * CAIF Link Layer with the flow control function. + * + */ + struct caif_dev_common { + void (*flowctrl)(struct net_device *net, int on); + enum caif_link_selector link_select; + int use_frag; + int use_fcs; + int use_stx; +}; + +#endif /* CAIF_DEVICE_H_ */ -- cgit v1.2.3 From e539d83cc8a4fa581cbf8ed288fdadb19a692cb0 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Wed, 28 Apr 2010 08:54:35 +0000 Subject: caif: Rename functions in cfcnfg and caif_dev Changes: o Renamed cfcnfg_del_adapt_layer to cfcnfg_disconn_adapt_layer o Fixed typo cfcfg to cfcnfg o Renamed linkid to channel_id o Updated documentation in caif_dev.h o Minor formatting changes Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- include/net/caif/caif_dev.h | 6 ++++-- include/net/caif/cfcnfg.h | 10 ++++----- net/caif/caif_dev.c | 15 +++++++------ net/caif/cfcnfg.c | 51 ++++++++++++++++++++++----------------------- 4 files changed, 41 insertions(+), 41 deletions(-) (limited to 'include/net/caif') diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h index 42a7c7867849..3aa1ff642323 100644 --- a/include/net/caif/caif_dev.h +++ b/include/net/caif/caif_dev.h @@ -23,17 +23,19 @@ struct caif_param { }; /** - * caif_connect_request - Request data for CAIF channel setup. + * struct caif_connect_request - Request data for CAIF channel setup. + * @protocol: Type of CAIF protocol to use (at, datagram etc) * @sockaddr: Socket address to connect. * @priority: Priority of the connection. * @link_selector: Link selector (high bandwidth or low latency) * @link_name: Name of the CAIF Link Layer to use. + * @param: Connect Request parameters (CAIF_SO_REQ_PARAM). * * This struct is used when connecting a CAIF channel. * It contains all CAIF channel configuration options. */ struct caif_connect_request { - int protocol; + enum caif_protocol_type protocol; struct sockaddr_caif sockaddr; enum caif_channel_priority priority; enum caif_link_selector link_selector; diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h index 366082c5d435..f16b875acc48 100644 --- a/include/net/caif/cfcnfg.h +++ b/include/net/caif/cfcnfg.h @@ -87,13 +87,14 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); /** - * cfcnfg_del_adapt_layer - Deletes an adaptation layer from the CAIF stack. + * cfcnfg_disconn_adapt_layer - Disconnects an adaptation layer. * * @cnfg: Pointer to a CAIF configuration object, created by * cfcnfg_create(). * @adap_layer: Adaptation layer to be removed. */ -int cfcnfg_del_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer); +int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, + struct cflayer *adap_layer); /** * cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack. @@ -102,14 +103,13 @@ int cfcnfg_del_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer); * driver functionality is implemented. * * @cnfg: Pointer to a CAIF configuration object, created by - * cfcnfg_create(). + * cfcnfg_create(). * @param: Link setup parameters. * @adap_layer: Specify the adaptation layer; the receive and * flow-control functions MUST be set in the structure. * */ -int -cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, +int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, struct cfctrl_link_param *param, struct cflayer *adap_layer); diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index e84837e1bc86..be1f674a3b67 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -330,20 +330,19 @@ int caif_connect_client(struct caif_connect_request *conn_req, struct cflayer *client_layer) { struct cfctrl_link_param param; - if (connect_req_to_link_param(get_caif_conf(), conn_req, ¶m) == 0) - /* Hook up the adaptation layer. */ - return cfcnfg_add_adaptation_layer(get_caif_conf(), + int ret; + ret = connect_req_to_link_param(get_caif_conf(), conn_req, ¶m); + if (ret) + return ret; + /* Hook up the adaptation layer. */ + return cfcnfg_add_adaptation_layer(get_caif_conf(), ¶m, client_layer); - - return -EINVAL; - - caif_assert(0); } EXPORT_SYMBOL(caif_connect_client); int caif_disconnect_client(struct cflayer *adap_layer) { - return cfcnfg_del_adapt_layer(get_caif_conf(), adap_layer); + return cfcnfg_disconn_adapt_layer(get_caif_conf(), adap_layer); } EXPORT_SYMBOL(caif_disconnect_client); diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index c873e3d4387c..d52f2566916e 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -51,12 +51,12 @@ struct cfcnfg { struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS]; }; -static void cncfg_linkup_rsp(struct cflayer *layer, u8 linkid, +static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, u8 phyid, struct cflayer *adapt_layer); -static void cncfg_linkdestroy_rsp(struct cflayer *layer, u8 linkid, +static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *client_layer); -static void cncfg_reject_rsp(struct cflayer *layer, u8 linkid, +static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *adapt_layer); static void cfctrl_resp_func(void); static void cfctrl_enum_resp(void); @@ -82,13 +82,13 @@ struct cfcnfg *cfcnfg_create(void) resp = cfctrl_get_respfuncs(this->ctrl); resp->enum_rsp = cfctrl_enum_resp; resp->linkerror_ind = cfctrl_resp_func; - resp->linkdestroy_rsp = cncfg_linkdestroy_rsp; + resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp; resp->sleep_rsp = cfctrl_resp_func; resp->wake_rsp = cfctrl_resp_func; resp->restart_rsp = cfctrl_resp_func; resp->radioset_rsp = cfctrl_resp_func; - resp->linksetup_rsp = cncfg_linkup_rsp; - resp->reject_rsp = cncfg_reject_rsp; + resp->linksetup_rsp = cfcnfg_linkup_rsp; + resp->reject_rsp = cfcnfg_reject_rsp; this->last_phyid = 1; @@ -191,8 +191,7 @@ int cfcnfg_get_named(struct cfcnfg *cnfg, char *name) * 4) Link-Error - (no response) * Not handled, but this should be a CAIF PROTOCOL ERROR */ - -int cfcnfg_del_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer) +int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer) { u8 channel_id = 0; int ret = 0; @@ -246,9 +245,9 @@ end: return ret; } -EXPORT_SYMBOL(cfcnfg_del_adapt_layer); +EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer); -static void cncfg_linkdestroy_rsp(struct cflayer *layer, u8 linkid, +static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *client_layer) { struct cfcnfg *cnfg = container_obj(layer); @@ -258,20 +257,20 @@ static void cncfg_linkdestroy_rsp(struct cflayer *layer, u8 linkid, * 1) Remove service from the MUX layer. The MUX must * guarante that no more payload sent "upwards" (receive) */ - servl = cfmuxl_remove_uplayer(cnfg->mux, linkid); + servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id); if (servl == NULL) { pr_err("CAIF: %s(): PROTOCOL ERROR " - "- Error removing service_layer Linkid(%d)", - __func__, linkid); + "- Error removing service_layer Channel_Id(%d)", + __func__, channel_id); return; } - caif_assert(linkid == servl->id); + caif_assert(channel_id == servl->id); if (servl != client_layer && servl->up != client_layer) { pr_err("CAIF: %s(): Error removing service_layer " - "Linkid(%d) %p %p", - __func__, linkid, (void *) servl, + "Channel_Id(%d) %p %p", + __func__, channel_id, (void *) servl, (void *) client_layer); return; } @@ -345,7 +344,7 @@ cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, } EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); -static void cncfg_reject_rsp(struct cflayer *layer, u8 linkid, +static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *adapt_layer) { if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL) @@ -354,7 +353,7 @@ static void cncfg_reject_rsp(struct cflayer *layer, u8 linkid, } static void -cncfg_linkup_rsp(struct cflayer *layer, u8 linkid, enum cfctrl_srv serv, +cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, u8 phyid, struct cflayer *adapt_layer) { struct cfcnfg *cnfg = container_obj(layer); @@ -383,26 +382,26 @@ cncfg_linkup_rsp(struct cflayer *layer, u8 linkid, enum cfctrl_srv serv, _CAIF_MODEMCMD_PHYIF_USEFULL); } - adapt_layer->id = linkid; + adapt_layer->id = channel_id; switch (serv) { case CFCTRL_SRV_VEI: - servicel = cfvei_create(linkid, &phyinfo->dev_info); + servicel = cfvei_create(channel_id, &phyinfo->dev_info); break; case CFCTRL_SRV_DATAGRAM: - servicel = cfdgml_create(linkid, &phyinfo->dev_info); + servicel = cfdgml_create(channel_id, &phyinfo->dev_info); break; case CFCTRL_SRV_RFM: - servicel = cfrfml_create(linkid, &phyinfo->dev_info); + servicel = cfrfml_create(channel_id, &phyinfo->dev_info); break; case CFCTRL_SRV_UTIL: - servicel = cfutill_create(linkid, &phyinfo->dev_info); + servicel = cfutill_create(channel_id, &phyinfo->dev_info); break; case CFCTRL_SRV_VIDEO: - servicel = cfvidl_create(linkid, &phyinfo->dev_info); + servicel = cfvidl_create(channel_id, &phyinfo->dev_info); break; case CFCTRL_SRV_DBG: - servicel = cfdbgl_create(linkid, &phyinfo->dev_info); + servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); break; default: pr_err("CAIF: %s(): Protocol error. " @@ -415,7 +414,7 @@ cncfg_linkup_rsp(struct cflayer *layer, u8 linkid, enum cfctrl_srv serv, return; } layer_set_dn(servicel, cnfg->mux); - cfmuxl_set_uplayer(cnfg->mux, servicel, linkid); + cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); layer_set_up(servicel, adapt_layer); layer_set_dn(adapt_layer, servicel); servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); -- cgit v1.2.3 From 5b2086567503f9b55136642031ec0067319f58e0 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Wed, 28 Apr 2010 08:54:36 +0000 Subject: caif: Add reference counting to service layer Changes: o Added functions cfsrvl_get and cfsrvl_put. o Added support release_client to use by socket and net device. o Increase reference counting for in-flight packets from cfmuxl Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- include/net/caif/caif_dev.h | 11 +++++++++++ include/net/caif/cfcnfg.h | 7 +++++++ include/net/caif/cfsrvl.h | 22 ++++++++++++++++++++++ net/caif/caif_dev.c | 6 ++++++ net/caif/cfcnfg.c | 7 +++++++ net/caif/cfmuxl.c | 7 ++++++- net/caif/cfsrvl.c | 7 +++++++ 7 files changed, 66 insertions(+), 1 deletion(-) (limited to 'include/net/caif') diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h index 3aa1ff642323..318ab9478a44 100644 --- a/include/net/caif/caif_dev.h +++ b/include/net/caif/caif_dev.h @@ -69,6 +69,17 @@ int caif_connect_client(struct caif_connect_request *config, */ int caif_disconnect_client(struct cflayer *client_layer); +/** + * caif_release_client - Release adaptation layer reference to client. + * + * @client_layer: Client layer. + * + * Releases a client/adaptation layer use of the caif stack. + * This function must be used after caif_disconnect_client to + * decrease the reference count of the service layer. + */ +void caif_release_client(struct cflayer *client_layer); + /** * connect_req_to_link_param - Translate configuration parameters * from socket format to internal format. diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h index f16b875acc48..9fc2fc20b884 100644 --- a/include/net/caif/cfcnfg.h +++ b/include/net/caif/cfcnfg.h @@ -96,6 +96,13 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer); +/** + * cfcnfg_release_adap_layer - Used by client to release the adaptation layer. + * + * @adap_layer: Adaptation layer. + */ +void cfcnfg_release_adap_layer(struct cflayer *adap_layer); + /** * cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack. * diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h index b2a12db20cd2..2dc9eb193ecf 100644 --- a/include/net/caif/cfsrvl.h +++ b/include/net/caif/cfsrvl.h @@ -9,14 +9,18 @@ #include #include #include +#include + struct cfsrvl { struct cflayer layer; bool open; bool phy_flow_on; bool modem_flow_on; struct dev_info dev_info; + struct kref ref; }; +void cfsrvl_release(struct kref *kref); struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info); struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info); struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info); @@ -31,4 +35,22 @@ void cfsrvl_init(struct cfsrvl *service, bool cfsrvl_ready(struct cfsrvl *service, int *err); u8 cfsrvl_getphyid(struct cflayer *layer); +static inline void cfsrvl_get(struct cflayer *layr) +{ + struct cfsrvl *s; + if (layr == NULL) + return; + s = container_of(layr, struct cfsrvl, layer); + kref_get(&s->ref); +} + +static inline void cfsrvl_put(struct cflayer *layr) +{ + struct cfsrvl *s; + if (layr == NULL) + return; + s = container_of(layr, struct cfsrvl, layer); + kref_put(&s->ref, cfsrvl_release); +} + #endif /* CFSRVL_H_ */ diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index be1f674a3b67..0145bae0274f 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -346,6 +346,12 @@ int caif_disconnect_client(struct cflayer *adap_layer) } EXPORT_SYMBOL(caif_disconnect_client); +void caif_release_client(struct cflayer *adap_layer) +{ + cfcnfg_release_adap_layer(adap_layer); +} +EXPORT_SYMBOL(caif_release_client); + /* Per-namespace Caif devices handling */ static int caif_init_net(struct net *net) { diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index d52f2566916e..f94f3dfe85c1 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -247,6 +247,13 @@ end: } EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer); +void cfcnfg_release_adap_layer(struct cflayer *adap_layer) +{ + if (adap_layer->dn) + cfsrvl_put(adap_layer->dn); +} +EXPORT_SYMBOL(cfcnfg_release_adap_layer); + static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *client_layer) { diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index 6fb9f9e96cf8..7372f27f1d32 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -62,6 +62,7 @@ int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid) { struct cfmuxl *muxl = container_obj(layr); spin_lock(&muxl->receive_lock); + cfsrvl_get(up); list_add(&up->node, &muxl->srvl_list); spin_unlock(&muxl->receive_lock); return 0; @@ -172,8 +173,11 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id) struct cfmuxl *muxl = container_obj(layr); spin_lock(&muxl->receive_lock); up = get_up(muxl, id); + if (up == NULL) + return NULL; memset(muxl->up_cache, 0, sizeof(muxl->up_cache)); list_del(&up->node); + cfsrvl_put(up); spin_unlock(&muxl->receive_lock); return up; } @@ -203,8 +207,9 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt) */ return /* CFGLU_EPROT; */ 0; } - + cfsrvl_get(up); ret = up->receive(up, pkt); + cfsrvl_put(up); return ret; } diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c index d470c51c6431..aff31f34528f 100644 --- a/net/caif/cfsrvl.c +++ b/net/caif/cfsrvl.c @@ -158,6 +158,13 @@ void cfsrvl_init(struct cfsrvl *service, service->layer.ctrlcmd = cfservl_ctrlcmd; service->layer.modemcmd = cfservl_modemcmd; service->dev_info = *dev_info; + kref_init(&service->ref); +} + +void cfsrvl_release(struct kref *kref) +{ + struct cfsrvl *service = container_of(kref, struct cfsrvl, ref); + kfree(service); } bool cfsrvl_ready(struct cfsrvl *service, int *err) -- cgit v1.2.3 From 8d545c8f958f5f433c50a00762ce1f231ed56eee Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Wed, 28 Apr 2010 08:54:37 +0000 Subject: caif: Disconnect without waiting for response Changes: o Function cfcnfg_disconn_adapt_layer is changed to do asynchronous disconnect, not waiting for any response from the modem. Due to this the function cfcnfg_linkdestroy_rsp does nothing anymore. o Because disconnect may take down a connection before a connect response is received the function cfcnfg_linkup_rsp is checking if the client is still waiting for the response, if not a disconnect request is sent to the modem. o cfctrl is no longer keeping track of pending disconnect requests. o Added function cfctrl_cancel_req, which is used for deleting a pending connect request if disconnect is done before connect response is received. o Removed unused function cfctrl_insert_req2 o Added better handling of connect reject from modem. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- include/net/caif/cfctrl.h | 7 ++- net/caif/cfcnfg.c | 155 ++++++++++++++-------------------------------- net/caif/cfctrl.c | 95 ++++++++++++++++++---------- 3 files changed, 111 insertions(+), 146 deletions(-) (limited to 'include/net/caif') diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h index dee25b86caa0..997603f2bf4c 100644 --- a/include/net/caif/cfctrl.h +++ b/include/net/caif/cfctrl.h @@ -43,8 +43,7 @@ struct cfctrl_rsp { void (*linksetup_rsp)(struct cflayer *layer, u8 linkid, enum cfctrl_srv serv, u8 phyid, struct cflayer *adapt_layer); - void (*linkdestroy_rsp)(struct cflayer *layer, u8 linkid, - struct cflayer *client_layer); + void (*linkdestroy_rsp)(struct cflayer *layer, u8 linkid); void (*linkerror_ind)(void); void (*enum_rsp)(void); void (*sleep_rsp)(void); @@ -117,7 +116,7 @@ struct cfctrl { }; void cfctrl_enum_req(struct cflayer *cfctrl, u8 physlinkid); -void cfctrl_linkup_request(struct cflayer *cfctrl, +int cfctrl_linkup_request(struct cflayer *cfctrl, struct cfctrl_link_param *param, struct cflayer *user_layer); int cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid, @@ -135,4 +134,6 @@ void cfctrl_insert_req(struct cfctrl *ctrl, struct cfctrl_request_info *req); struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, struct cfctrl_request_info *req); +void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer); + #endif /* CFCTRL_H_ */ diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index f94f3dfe85c1..471c62939fad 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -54,8 +54,7 @@ struct cfcnfg { static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, u8 phyid, struct cflayer *adapt_layer); -static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id, - struct cflayer *client_layer); +static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id); static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *adapt_layer); static void cfctrl_resp_func(void); @@ -175,73 +174,65 @@ int cfcnfg_get_named(struct cfcnfg *cnfg, char *name) return 0; } -/* - * NOTE: What happens on destroy failure: - * 1a) No response - Too early - * This will not happen because enumerate has already - * completed. - * 1b) No response - FATAL - * Not handled, but this should be a CAIF PROTOCOL ERROR - * Modem error, response is really expected - this - * case is not really handled. - * 2) O/E-bit indicate error - * Ignored - this link is destroyed anyway. - * 3) Not able to match on request - * Not handled, but this should be a CAIF PROTOCOL ERROR - * 4) Link-Error - (no response) - * Not handled, but this should be a CAIF PROTOCOL ERROR - */ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer) { u8 channel_id = 0; int ret = 0; + struct cflayer *servl = NULL; struct cfcnfg_phyinfo *phyinfo = NULL; u8 phyid = 0; - caif_assert(adap_layer != NULL); channel_id = adap_layer->id; - if (channel_id == 0) { + if (adap_layer->dn == NULL || channel_id == 0) { pr_err("CAIF: %s():adap_layer->id is 0\n", __func__); ret = -ENOTCONN; goto end; } - - if (adap_layer->dn == NULL) { - pr_err("CAIF: %s():adap_layer->dn is NULL\n", __func__); - ret = -ENODEV; - goto end; - } - - if (adap_layer->dn != NULL) - phyid = cfsrvl_getphyid(adap_layer->dn); - - phyinfo = cfcnfg_get_phyinfo(cnfg, phyid); - if (phyinfo == NULL) { - pr_warning("CAIF: %s(): No interface to send disconnect to\n", - __func__); - ret = -ENODEV; + servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id); + if (servl == NULL) goto end; - } - - if (phyinfo->id != phyid - || phyinfo->phy_layer->id != phyid - || phyinfo->frm_layer->id != phyid) { - - pr_err("CAIF: %s(): Inconsistency in phy registration\n", - __func__); + layer_set_up(servl, NULL); + ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer); + if (servl == NULL) { + pr_err("CAIF: %s(): PROTOCOL ERROR " + "- Error removing service_layer Channel_Id(%d)", + __func__, channel_id); ret = -EINVAL; goto end; } + caif_assert(channel_id == servl->id); + if (adap_layer->dn != NULL) { + phyid = cfsrvl_getphyid(adap_layer->dn); - ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer); - -end: + phyinfo = cfcnfg_get_phyinfo(cnfg, phyid); + if (phyinfo == NULL) { + pr_warning("CAIF: %s(): " + "No interface to send disconnect to\n", + __func__); + ret = -ENODEV; + goto end; + } + if (phyinfo->id != phyid || + phyinfo->phy_layer->id != phyid || + phyinfo->frm_layer->id != phyid) { + pr_err("CAIF: %s(): " + "Inconsistency in phy registration\n", + __func__); + ret = -EINVAL; + goto end; + } + } if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 && phyinfo->phy_layer != NULL && phyinfo->phy_layer->modemcmd != NULL) { phyinfo->phy_layer->modemcmd(phyinfo->phy_layer, _CAIF_MODEMCMD_PHYIF_USELESS); } +end: + cfsrvl_put(servl); + cfctrl_cancel_req(cnfg->ctrl, adap_layer); + if (adap_layer->ctrlcmd != NULL) + adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); return ret; } @@ -254,69 +245,11 @@ void cfcnfg_release_adap_layer(struct cflayer *adap_layer) } EXPORT_SYMBOL(cfcnfg_release_adap_layer); -static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id, - struct cflayer *client_layer) +static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) { - struct cfcnfg *cnfg = container_obj(layer); - struct cflayer *servl; - - /* - * 1) Remove service from the MUX layer. The MUX must - * guarante that no more payload sent "upwards" (receive) - */ - servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id); - - if (servl == NULL) { - pr_err("CAIF: %s(): PROTOCOL ERROR " - "- Error removing service_layer Channel_Id(%d)", - __func__, channel_id); - return; - } - caif_assert(channel_id == servl->id); - - if (servl != client_layer && servl->up != client_layer) { - pr_err("CAIF: %s(): Error removing service_layer " - "Channel_Id(%d) %p %p", - __func__, channel_id, (void *) servl, - (void *) client_layer); - return; - } - - /* - * 2) DEINIT_RSP must guarantee that no more packets are transmitted - * from client (adap_layer) when it returns. - */ - - if (servl->ctrlcmd == NULL) { - pr_err("CAIF: %s(): Error servl->ctrlcmd == NULL", __func__); - return; - } - - servl->ctrlcmd(servl, CAIF_CTRLCMD_DEINIT_RSP, 0); - - /* 3) It is now safe to destroy the service layer. */ - cfservl_destroy(servl); } -/* - * NOTE: What happens on linksetup failure: - * 1a) No response - Too early - * This will not happen because enumerate is secured - * before using interface. - * 1b) No response - FATAL - * Not handled, but this should be a CAIF PROTOCOL ERROR - * Modem error, response is really expected - this case is - * not really handled. - * 2) O/E-bit indicate error - * Handled in cnfg_reject_rsp - * 3) Not able to match on request - * Not handled, but this should be a CAIF PROTOCOL ERROR - * 4) Link-Error - (no response) - * Not handled, but this should be a CAIF PROTOCOL ERROR - */ - -int -cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, +int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, struct cfctrl_link_param *param, struct cflayer *adap_layer) { @@ -346,8 +279,7 @@ cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, param->phyid); /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ cfctrl_enum_req(cnfg->ctrl, param->phyid); - cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); - return 0; + return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); } EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); @@ -367,8 +299,10 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, struct cflayer *servicel = NULL; struct cfcnfg_phyinfo *phyinfo; if (adapt_layer == NULL) { - pr_err("CAIF: %s(): PROTOCOL ERROR " - "- LinkUp Request/Response did not match\n", __func__); + pr_debug("CAIF: %s(): link setup response " + "but no client exist, send linkdown back\n", + __func__); + cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); return; } @@ -424,6 +358,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); layer_set_up(servicel, adapt_layer); layer_set_dn(adapt_layer, servicel); + cfsrvl_get(servicel); servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); } diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 11f80140f3cb..a521d32cfe56 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -32,6 +32,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, struct cflayer *cfctrl_create(void) { + struct dev_info dev_info; struct cfctrl *this = kmalloc(sizeof(struct cfctrl), GFP_ATOMIC); if (!this) { @@ -39,12 +40,13 @@ struct cflayer *cfctrl_create(void) return NULL; } caif_assert(offsetof(struct cfctrl, serv.layer) == 0); + memset(&dev_info, 0, sizeof(dev_info)); + dev_info.id = 0xff; memset(this, 0, sizeof(*this)); + cfsrvl_init(&this->serv, 0, &dev_info); spin_lock_init(&this->info_list_lock); atomic_set(&this->req_seq_no, 1); atomic_set(&this->rsp_seq_no, 1); - this->serv.dev_info.id = 0xff; - this->serv.layer.id = 0; this->serv.layer.receive = cfctrl_recv; sprintf(this->serv.layer.name, "ctrl"); this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; @@ -127,20 +129,6 @@ void cfctrl_insert_req(struct cfctrl *ctrl, spin_unlock(&ctrl->info_list_lock); } -static void cfctrl_insert_req2(struct cfctrl *ctrl, enum cfctrl_cmd cmd, - u8 linkid, struct cflayer *user_layer) -{ - struct cfctrl_request_info *req = kmalloc(sizeof(*req), GFP_KERNEL); - if (!req) { - pr_warning("CAIF: %s(): Out of memory\n", __func__); - return; - } - req->client_layer = user_layer; - req->cmd = cmd; - req->channel_id = linkid; - cfctrl_insert_req(ctrl, req); -} - /* Compare and remove request */ struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, struct cfctrl_request_info *req) @@ -234,7 +222,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid) } } -void cfctrl_linkup_request(struct cflayer *layer, +int cfctrl_linkup_request(struct cflayer *layer, struct cfctrl_link_param *param, struct cflayer *user_layer) { @@ -248,7 +236,7 @@ void cfctrl_linkup_request(struct cflayer *layer, struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); if (!pkt) { pr_warning("CAIF: %s(): Out of memory\n", __func__); - return; + return -ENOMEM; } cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP); cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype); @@ -294,11 +282,12 @@ void cfctrl_linkup_request(struct cflayer *layer, default: pr_warning("CAIF: %s():Request setup of bad link type = %d\n", __func__, param->linktype); + return -EINVAL; } req = kmalloc(sizeof(*req), GFP_KERNEL); if (!req) { pr_warning("CAIF: %s(): Out of memory\n", __func__); - return; + return -ENOMEM; } memset(req, 0, sizeof(*req)); req->client_layer = user_layer; @@ -306,6 +295,11 @@ void cfctrl_linkup_request(struct cflayer *layer, req->param = *param; cfctrl_insert_req(cfctrl, req); init_info(cfpkt_info(pkt), cfctrl); + /* + * 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. + */ cfpkt_info(pkt)->dev_info->id = param->phyid; ret = cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); @@ -313,7 +307,9 @@ void cfctrl_linkup_request(struct cflayer *layer, pr_err("CAIF: %s(): Could not transmit linksetup request\n", __func__); cfpkt_destroy(pkt); + return -ENODEV; } + return 0; } int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid, @@ -326,7 +322,6 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid, pr_warning("CAIF: %s(): Out of memory\n", __func__); return -ENOMEM; } - cfctrl_insert_req2(cfctrl, CFCTRL_CMD_LINK_DESTROY, channelid, client); cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY); cfpkt_addbdy(pkt, channelid); init_info(cfpkt_info(pkt), cfctrl); @@ -392,6 +387,38 @@ void cfctrl_getstartreason_req(struct cflayer *layer) } +void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) +{ + struct cfctrl_request_info *p, *req; + struct cfctrl *ctrl = container_obj(layr); + spin_lock(&ctrl->info_list_lock); + + if (ctrl->first_req == NULL) { + spin_unlock(&ctrl->info_list_lock); + return; + } + + if (ctrl->first_req->client_layer == adap_layer) { + + req = ctrl->first_req; + ctrl->first_req = ctrl->first_req->next; + kfree(req); + } + + p = ctrl->first_req; + while (p != NULL && p->next != NULL) { + if (p->next->client_layer == adap_layer) { + + req = p->next; + p->next = p->next->next; + kfree(p->next); + } + p = p->next; + } + + spin_unlock(&ctrl->info_list_lock); +} + static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) { u8 cmdrsp; @@ -409,11 +436,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) cmd = cmdrsp & CFCTRL_CMD_MASK; if (cmd != CFCTRL_CMD_LINK_ERR && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) { - if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE) { - pr_info("CAIF: %s() CAIF Protocol error:" - "Response bit not set\n", __func__); - goto error; - } + if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE) + cmdrsp |= CFCTRL_ERR_BIT; } switch (cmd) { @@ -451,12 +475,16 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) switch (serv) { case CFCTRL_SRV_VEI: case CFCTRL_SRV_DBG: + if (CFCTRL_ERR_BIT & cmdrsp) + break; /* Link ID */ cfpkt_extr_head(pkt, &linkid, 1); break; case CFCTRL_SRV_VIDEO: cfpkt_extr_head(pkt, &tmp, 1); linkparam.u.video.connid = tmp; + if (CFCTRL_ERR_BIT & cmdrsp) + break; /* Link ID */ cfpkt_extr_head(pkt, &linkid, 1); break; @@ -465,6 +493,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) cfpkt_extr_head(pkt, &tmp32, 4); linkparam.u.datagram.connid = le32_to_cpu(tmp32); + if (CFCTRL_ERR_BIT & cmdrsp) + break; /* Link ID */ cfpkt_extr_head(pkt, &linkid, 1); break; @@ -483,6 +513,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) *cp++ = tmp; *cp = '\0'; + if (CFCTRL_ERR_BIT & cmdrsp) + break; /* Link ID */ cfpkt_extr_head(pkt, &linkid, 1); @@ -519,6 +551,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) cfpkt_extr_head(pkt, &tmp, 1); *cp++ = tmp; } + if (CFCTRL_ERR_BIT & cmdrsp) + break; /* Link ID */ cfpkt_extr_head(pkt, &linkid, 1); /* Length */ @@ -560,13 +594,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) break; case CFCTRL_CMD_LINK_DESTROY: cfpkt_extr_head(pkt, &linkid, 1); - rsp.cmd = cmd; - rsp.channel_id = linkid; - req = cfctrl_remove_req(cfctrl, &rsp); - cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid, - req ? req->client_layer : NULL); - if (req != NULL) - kfree(req); + cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid); break; case CFCTRL_CMD_LINK_ERR: pr_err("CAIF: %s(): Frame Error Indication received\n", @@ -608,7 +636,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, case CAIF_CTRLCMD_FLOW_OFF_IND: spin_lock(&this->info_list_lock); if (this->first_req != NULL) { - pr_warning("CAIF: %s(): Received flow off in " + pr_debug("CAIF: %s(): Received flow off in " "control layer", __func__); } spin_unlock(&this->info_list_lock); @@ -633,6 +661,7 @@ static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) if (!ctrl->loop_linkused[linkid]) goto found; spin_unlock(&ctrl->loop_linkid_lock); + pr_err("CAIF: %s(): Out of link-ids\n", __func__); return -EINVAL; found: if (!ctrl->loop_linkused[linkid]) -- cgit v1.2.3