root/net/caif/cfsrvl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cfservl_ctrlcmd
  2. cfservl_modemcmd
  3. cfsrvl_release
  4. cfsrvl_init
  5. cfsrvl_ready
  6. cfsrvl_getphyid
  7. cfsrvl_phyid_match
  8. caif_free_client
  9. caif_client_register_refcnt

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) ST-Ericsson AB 2010
   4  * Author:      Sjur Brendeland
   5  */
   6 
   7 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/types.h>
  11 #include <linux/errno.h>
  12 #include <linux/slab.h>
  13 #include <linux/module.h>
  14 #include <linux/pkt_sched.h>
  15 #include <net/caif/caif_layer.h>
  16 #include <net/caif/cfsrvl.h>
  17 #include <net/caif/cfpkt.h>
  18 #include <net/caif/caif_dev.h>
  19 
  20 #define SRVL_CTRL_PKT_SIZE 1
  21 #define SRVL_FLOW_OFF 0x81
  22 #define SRVL_FLOW_ON  0x80
  23 #define SRVL_SET_PIN  0x82
  24 #define SRVL_CTRL_PKT_SIZE 1
  25 
  26 #define container_obj(layr) container_of(layr, struct cfsrvl, layer)
  27 
  28 static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  29                             int phyid)
  30 {
  31         struct cfsrvl *service = container_obj(layr);
  32 
  33         if (layr->up == NULL || layr->up->ctrlcmd == NULL)
  34                 return;
  35 
  36         switch (ctrl) {
  37         case CAIF_CTRLCMD_INIT_RSP:
  38                 service->open = true;
  39                 layr->up->ctrlcmd(layr->up, ctrl, phyid);
  40                 break;
  41         case CAIF_CTRLCMD_DEINIT_RSP:
  42         case CAIF_CTRLCMD_INIT_FAIL_RSP:
  43                 service->open = false;
  44                 layr->up->ctrlcmd(layr->up, ctrl, phyid);
  45                 break;
  46         case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
  47                 if (phyid != service->dev_info.id)
  48                         break;
  49                 if (service->modem_flow_on)
  50                         layr->up->ctrlcmd(layr->up,
  51                                           CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
  52                 service->phy_flow_on = false;
  53                 break;
  54         case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
  55                 if (phyid != service->dev_info.id)
  56                         return;
  57                 if (service->modem_flow_on) {
  58                         layr->up->ctrlcmd(layr->up,
  59                                            CAIF_CTRLCMD_FLOW_ON_IND,
  60                                            phyid);
  61                 }
  62                 service->phy_flow_on = true;
  63                 break;
  64         case CAIF_CTRLCMD_FLOW_OFF_IND:
  65                 if (service->phy_flow_on) {
  66                         layr->up->ctrlcmd(layr->up,
  67                                           CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
  68                 }
  69                 service->modem_flow_on = false;
  70                 break;
  71         case CAIF_CTRLCMD_FLOW_ON_IND:
  72                 if (service->phy_flow_on) {
  73                         layr->up->ctrlcmd(layr->up,
  74                                           CAIF_CTRLCMD_FLOW_ON_IND, phyid);
  75                 }
  76                 service->modem_flow_on = true;
  77                 break;
  78         case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
  79                 /* In case interface is down, let's fake a remove shutdown */
  80                 layr->up->ctrlcmd(layr->up,
  81                                 CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
  82                 break;
  83         case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
  84                 layr->up->ctrlcmd(layr->up, ctrl, phyid);
  85                 break;
  86         default:
  87                 pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
  88                 /* We have both modem and phy flow on, send flow on */
  89                 layr->up->ctrlcmd(layr->up, ctrl, phyid);
  90                 service->phy_flow_on = true;
  91                 break;
  92         }
  93 }
  94 
  95 static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
  96 {
  97         struct cfsrvl *service = container_obj(layr);
  98 
  99         caif_assert(layr != NULL);
 100         caif_assert(layr->dn != NULL);
 101         caif_assert(layr->dn->transmit != NULL);
 102 
 103         if (!service->supports_flowctrl)
 104                 return 0;
 105 
 106         switch (ctrl) {
 107         case CAIF_MODEMCMD_FLOW_ON_REQ:
 108                 {
 109                         struct cfpkt *pkt;
 110                         struct caif_payload_info *info;
 111                         u8 flow_on = SRVL_FLOW_ON;
 112                         pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
 113                         if (!pkt)
 114                                 return -ENOMEM;
 115 
 116                         if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
 117                                 pr_err("Packet is erroneous!\n");
 118                                 cfpkt_destroy(pkt);
 119                                 return -EPROTO;
 120                         }
 121                         info = cfpkt_info(pkt);
 122                         info->channel_id = service->layer.id;
 123                         info->hdr_len = 1;
 124                         info->dev_info = &service->dev_info;
 125                         cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
 126                         return layr->dn->transmit(layr->dn, pkt);
 127                 }
 128         case CAIF_MODEMCMD_FLOW_OFF_REQ:
 129                 {
 130                         struct cfpkt *pkt;
 131                         struct caif_payload_info *info;
 132                         u8 flow_off = SRVL_FLOW_OFF;
 133                         pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
 134                         if (!pkt)
 135                                 return -ENOMEM;
 136 
 137                         if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
 138                                 pr_err("Packet is erroneous!\n");
 139                                 cfpkt_destroy(pkt);
 140                                 return -EPROTO;
 141                         }
 142                         info = cfpkt_info(pkt);
 143                         info->channel_id = service->layer.id;
 144                         info->hdr_len = 1;
 145                         info->dev_info = &service->dev_info;
 146                         cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
 147                         return layr->dn->transmit(layr->dn, pkt);
 148                 }
 149         default:
 150           break;
 151         }
 152         return -EINVAL;
 153 }
 154 
 155 static void cfsrvl_release(struct cflayer *layer)
 156 {
 157         struct cfsrvl *service = container_of(layer, struct cfsrvl, layer);
 158         kfree(service);
 159 }
 160 
 161 void cfsrvl_init(struct cfsrvl *service,
 162                  u8 channel_id,
 163                  struct dev_info *dev_info,
 164                  bool supports_flowctrl)
 165 {
 166         caif_assert(offsetof(struct cfsrvl, layer) == 0);
 167         service->open = false;
 168         service->modem_flow_on = true;
 169         service->phy_flow_on = true;
 170         service->layer.id = channel_id;
 171         service->layer.ctrlcmd = cfservl_ctrlcmd;
 172         service->layer.modemcmd = cfservl_modemcmd;
 173         service->dev_info = *dev_info;
 174         service->supports_flowctrl = supports_flowctrl;
 175         service->release = cfsrvl_release;
 176 }
 177 
 178 bool cfsrvl_ready(struct cfsrvl *service, int *err)
 179 {
 180         if (!service->open) {
 181                 *err = -ENOTCONN;
 182                 return false;
 183         }
 184         return true;
 185 }
 186 
 187 u8 cfsrvl_getphyid(struct cflayer *layer)
 188 {
 189         struct cfsrvl *servl = container_obj(layer);
 190         return servl->dev_info.id;
 191 }
 192 
 193 bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
 194 {
 195         struct cfsrvl *servl = container_obj(layer);
 196         return servl->dev_info.id == phyid;
 197 }
 198 
 199 void caif_free_client(struct cflayer *adap_layer)
 200 {
 201         struct cfsrvl *servl;
 202         if (adap_layer == NULL || adap_layer->dn == NULL)
 203                 return;
 204         servl = container_obj(adap_layer->dn);
 205         servl->release(&servl->layer);
 206 }
 207 EXPORT_SYMBOL(caif_free_client);
 208 
 209 void caif_client_register_refcnt(struct cflayer *adapt_layer,
 210                                  void (*hold)(struct cflayer *lyr),
 211                                  void (*put)(struct cflayer *lyr))
 212 {
 213         struct cfsrvl *service;
 214 
 215         if (WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL))
 216                 return;
 217         service = container_of(adapt_layer->dn, struct cfsrvl, layer);
 218         service->hold = hold;
 219         service->put = put;
 220 }
 221 EXPORT_SYMBOL(caif_client_register_refcnt);

/* [<][>][^][v][top][bottom][index][help] */