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
7
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
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 <net/caif/caif_layer.h>
15
#include <net/caif/cfsrvl.h>
16
#include <net/caif/cfpkt.h>
18
#define SRVL_CTRL_PKT_SIZE 1
19
#define SRVL_FLOW_OFF 0x81
20
#define SRVL_FLOW_ON 0x80
21
#define SRVL_SET_PIN 0x82
22
#define SRVL_CTRL_PKT_SIZE 1
24
#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
26
static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
29
struct cfsrvl *service = container_obj(layr);
31
if (layr->up == NULL || layr->up->ctrlcmd == NULL)
35
case CAIF_CTRLCMD_INIT_RSP:
37
layr->up->ctrlcmd(layr->up, ctrl, phyid);
39
case CAIF_CTRLCMD_DEINIT_RSP:
40
case CAIF_CTRLCMD_INIT_FAIL_RSP:
41
service->open = false;
42
layr->up->ctrlcmd(layr->up, ctrl, phyid);
44
case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
45
if (phyid != service->dev_info.id)
47
if (service->modem_flow_on)
48
layr->up->ctrlcmd(layr->up,
49
CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
50
service->phy_flow_on = false;
52
case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
53
if (phyid != service->dev_info.id)
55
if (service->modem_flow_on) {
56
layr->up->ctrlcmd(layr->up,
57
CAIF_CTRLCMD_FLOW_ON_IND,
60
service->phy_flow_on = true;
62
case CAIF_CTRLCMD_FLOW_OFF_IND:
63
if (service->phy_flow_on) {
64
layr->up->ctrlcmd(layr->up,
65
CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
67
service->modem_flow_on = false;
69
case CAIF_CTRLCMD_FLOW_ON_IND:
70
if (service->phy_flow_on) {
71
layr->up->ctrlcmd(layr->up,
72
CAIF_CTRLCMD_FLOW_ON_IND, phyid);
74
service->modem_flow_on = true;
76
case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
77
/* In case interface is down, let's fake a remove shutdown */
78
layr->up->ctrlcmd(layr->up,
79
CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
81
case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
82
layr->up->ctrlcmd(layr->up, ctrl, phyid);
85
pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
86
/* We have both modem and phy flow on, send flow on */
87
layr->up->ctrlcmd(layr->up, ctrl, phyid);
88
service->phy_flow_on = true;
93
static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
95
struct cfsrvl *service = container_obj(layr);
97
caif_assert(layr != NULL);
98
caif_assert(layr->dn != NULL);
99
caif_assert(layr->dn->transmit != NULL);
101
if (!service->supports_flowctrl)
105
case CAIF_MODEMCMD_FLOW_ON_REQ:
108
struct caif_payload_info *info;
109
u8 flow_on = SRVL_FLOW_ON;
110
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
114
if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
115
pr_err("Packet is erroneous!\n");
119
info = cfpkt_info(pkt);
120
info->channel_id = service->layer.id;
122
info->dev_info = &service->dev_info;
123
return layr->dn->transmit(layr->dn, pkt);
125
case CAIF_MODEMCMD_FLOW_OFF_REQ:
128
struct caif_payload_info *info;
129
u8 flow_off = SRVL_FLOW_OFF;
130
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
134
if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
135
pr_err("Packet is erroneous!\n");
139
info = cfpkt_info(pkt);
140
info->channel_id = service->layer.id;
142
info->dev_info = &service->dev_info;
143
return layr->dn->transmit(layr->dn, pkt);
151
static void cfsrvl_release(struct cflayer *layer)
153
struct cfsrvl *service = container_of(layer, struct cfsrvl, layer);
157
void cfsrvl_init(struct cfsrvl *service,
159
struct dev_info *dev_info,
160
bool supports_flowctrl
163
caif_assert(offsetof(struct cfsrvl, layer) == 0);
164
service->open = false;
165
service->modem_flow_on = true;
166
service->phy_flow_on = true;
167
service->layer.id = channel_id;
168
service->layer.ctrlcmd = cfservl_ctrlcmd;
169
service->layer.modemcmd = cfservl_modemcmd;
170
service->dev_info = *dev_info;
171
service->supports_flowctrl = supports_flowctrl;
172
service->release = cfsrvl_release;
175
bool cfsrvl_ready(struct cfsrvl *service, int *err)
177
if (service->open && service->modem_flow_on && service->phy_flow_on)
179
if (!service->open) {
183
caif_assert(!(service->modem_flow_on && service->phy_flow_on));
188
u8 cfsrvl_getphyid(struct cflayer *layer)
190
struct cfsrvl *servl = container_obj(layer);
191
return servl->dev_info.id;
194
bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
196
struct cfsrvl *servl = container_obj(layer);
197
return servl->dev_info.id == phyid;
200
void caif_free_client(struct cflayer *adap_layer)
202
struct cfsrvl *servl;
203
if (adap_layer == NULL || adap_layer->dn == NULL)
205
servl = container_obj(adap_layer->dn);
206
servl->release(&servl->layer);
208
EXPORT_SYMBOL(caif_free_client);
210
void caif_client_register_refcnt(struct cflayer *adapt_layer,
211
void (*hold)(struct cflayer *lyr),
212
void (*put)(struct cflayer *lyr))
214
struct cfsrvl *service;
215
service = container_of(adapt_layer->dn, struct cfsrvl, layer);
217
WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL);
218
service->hold = hold;
221
EXPORT_SYMBOL(caif_client_register_refcnt);