1 /* 2 * Copyright (C) ST-Ericsson AB 2010 3 * Author: Sjur Brendeland/sjur.brandeland@stericsson.com 4 * License terms: GNU General Public License (GPL) version 2 5 */ 6 7 #include <linux/stddef.h> 8 #include <linux/spinlock.h> 9 #include <linux/slab.h> 10 #include <net/caif/caif_layer.h> 11 #include <net/caif/cfsrvl.h> 12 #include <net/caif/cfpkt.h> 13 14 #define container_obj(layr) container_of(layr, struct cfsrvl, layer) 15 16 #define RFM_SEGMENTATION_BIT 0x01 17 #define RFM_PAYLOAD 0x00 18 #define RFM_CMD_BIT 0x80 19 #define RFM_FLOW_OFF 0x81 20 #define RFM_FLOW_ON 0x80 21 #define RFM_SET_PIN 0x82 22 #define RFM_CTRL_PKT_SIZE 1 23 24 static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt); 25 static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt); 26 static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl); 27 28 struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info) 29 { 30 struct cfsrvl *rfm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); 31 if (!rfm) { 32 pr_warning("CAIF: %s(): Out of memory\n", __func__); 33 return NULL; 34 } 35 caif_assert(offsetof(struct cfsrvl, layer) == 0); 36 memset(rfm, 0, sizeof(struct cfsrvl)); 37 cfsrvl_init(rfm, channel_id, dev_info); 38 rfm->layer.modemcmd = cfservl_modemcmd; 39 rfm->layer.receive = cfrfml_receive; 40 rfm->layer.transmit = cfrfml_transmit; 41 snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id); 42 return &rfm->layer; 43 } 44 45 static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) 46 { 47 return -EPROTO; 48 } 49 50 static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt) 51 { 52 u8 tmp; 53 bool segmented; 54 int ret; 55 caif_assert(layr->up != NULL); 56 caif_assert(layr->receive != NULL); 57 58 /* 59 * RFM is taking care of segmentation and stripping of 60 * segmentation bit. 61 */ 62 if (cfpkt_extr_head(pkt, &tmp, 1) < 0) { 63 pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); 64 cfpkt_destroy(pkt); 65 return -EPROTO; 66 } 67 segmented = tmp & RFM_SEGMENTATION_BIT; 68 caif_assert(!segmented); 69 70 ret = layr->up->receive(layr->up, pkt); 71 return ret; 72 } 73 74 static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) 75 { 76 u8 tmp = 0; 77 int ret; 78 struct cfsrvl *service = container_obj(layr); 79 80 caif_assert(layr->dn != NULL); 81 caif_assert(layr->dn->transmit != NULL); 82 83 if (!cfsrvl_ready(service, &ret)) 84 return ret; 85 86 if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { 87 pr_err("CAIF: %s():Packet too large - size=%d\n", 88 __func__, cfpkt_getlen(pkt)); 89 return -EOVERFLOW; 90 } 91 if (cfpkt_add_head(pkt, &tmp, 1) < 0) { 92 pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); 93 return -EPROTO; 94 } 95 96 /* Add info for MUX-layer to route the packet out. */ 97 cfpkt_info(pkt)->channel_id = service->layer.id; 98 /* 99 * To optimize alignment, we add up the size of CAIF header before 100 * payload. 101 */ 102 cfpkt_info(pkt)->hdr_len = 1; 103 cfpkt_info(pkt)->dev_info = &service->dev_info; 104 ret = layr->dn->transmit(layr->dn, pkt); 105 if (ret < 0) 106 cfpkt_extr_head(pkt, &tmp, 1); 107 return ret; 108 } 109