linux/net/caif/cfrfml.c
<<
>>
Prefs
   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
  24static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
  25static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);
  26static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl);
  27
  28struct 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
  45static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
  46{
  47       return -EPROTO;
  48}
  49
  50static 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
  74static 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