Blame view

net/caif/cfsrvl.c 5.59 KB
b482cd205   Sjur Braendeland   net-caif: add CAI...
1
2
3
4
5
  /*
   * Copyright (C) ST-Ericsson AB 2010
   * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
   * License terms: GNU General Public License (GPL) version 2
   */
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
6
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
b482cd205   Sjur Braendeland   net-caif: add CAI...
7
8
9
10
  #include <linux/kernel.h>
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/slab.h>
43e369210   sjur.brandeland@stericsson.com   caif: Move refcou...
11
  #include <linux/module.h>
b482cd205   Sjur Braendeland   net-caif: add CAI...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  #include <net/caif/caif_layer.h>
  #include <net/caif/cfsrvl.h>
  #include <net/caif/cfpkt.h>
  
  #define SRVL_CTRL_PKT_SIZE 1
  #define SRVL_FLOW_OFF 0x81
  #define SRVL_FLOW_ON  0x80
  #define SRVL_SET_PIN  0x82
  #define SRVL_CTRL_PKT_SIZE 1
  
  #define container_obj(layr) container_of(layr, struct cfsrvl, layer)
  
  static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  				int phyid)
  {
  	struct cfsrvl *service = container_obj(layr);
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
28

43e369210   sjur.brandeland@stericsson.com   caif: Move refcou...
29
30
  	if (layr->up == NULL || layr->up->ctrlcmd == NULL)
  		return;
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
31

b482cd205   Sjur Braendeland   net-caif: add CAI...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  	switch (ctrl) {
  	case CAIF_CTRLCMD_INIT_RSP:
  		service->open = true;
  		layr->up->ctrlcmd(layr->up, ctrl, phyid);
  		break;
  	case CAIF_CTRLCMD_DEINIT_RSP:
  	case CAIF_CTRLCMD_INIT_FAIL_RSP:
  		service->open = false;
  		layr->up->ctrlcmd(layr->up, ctrl, phyid);
  		break;
  	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
  		if (phyid != service->dev_info.id)
  			break;
  		if (service->modem_flow_on)
  			layr->up->ctrlcmd(layr->up,
  					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
  		service->phy_flow_on = false;
  		break;
  	case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
  		if (phyid != service->dev_info.id)
  			return;
  		if (service->modem_flow_on) {
  			layr->up->ctrlcmd(layr->up,
  					   CAIF_CTRLCMD_FLOW_ON_IND,
  					   phyid);
  		}
  		service->phy_flow_on = true;
  		break;
  	case CAIF_CTRLCMD_FLOW_OFF_IND:
  		if (service->phy_flow_on) {
  			layr->up->ctrlcmd(layr->up,
  					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
  		}
  		service->modem_flow_on = false;
  		break;
  	case CAIF_CTRLCMD_FLOW_ON_IND:
  		if (service->phy_flow_on) {
  			layr->up->ctrlcmd(layr->up,
  					  CAIF_CTRLCMD_FLOW_ON_IND, phyid);
  		}
  		service->modem_flow_on = true;
  		break;
  	case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
  		/* In case interface is down, let's fake a remove shutdown */
  		layr->up->ctrlcmd(layr->up,
  				CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
  		break;
  	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
  		layr->up->ctrlcmd(layr->up, ctrl, phyid);
  		break;
  	default:
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
83
84
  		pr_warn("Unexpected ctrl in cfsrvl (%d)
  ", ctrl);
b482cd205   Sjur Braendeland   net-caif: add CAI...
85
86
87
88
89
90
91
92
93
94
  		/* We have both modem and phy flow on, send flow on */
  		layr->up->ctrlcmd(layr->up, ctrl, phyid);
  		service->phy_flow_on = true;
  		break;
  	}
  }
  
  static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
  {
  	struct cfsrvl *service = container_obj(layr);
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
95

b482cd205   Sjur Braendeland   net-caif: add CAI...
96
97
98
  	caif_assert(layr != NULL);
  	caif_assert(layr->dn != NULL);
  	caif_assert(layr->dn->transmit != NULL);
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
99
100
101
  
  	if (!service->supports_flowctrl)
  		return 0;
b482cd205   Sjur Braendeland   net-caif: add CAI...
102
103
104
105
106
107
108
109
  	switch (ctrl) {
  	case CAIF_MODEMCMD_FLOW_ON_REQ:
  		{
  			struct cfpkt *pkt;
  			struct caif_payload_info *info;
  			u8 flow_on = SRVL_FLOW_ON;
  			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
  			if (!pkt) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
110
111
  				pr_warn("Out of memory
  ");
b482cd205   Sjur Braendeland   net-caif: add CAI...
112
113
114
115
  				return -ENOMEM;
  			}
  
  			if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
116
117
  				pr_err("Packet is erroneous!
  ");
b482cd205   Sjur Braendeland   net-caif: add CAI...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  				cfpkt_destroy(pkt);
  				return -EPROTO;
  			}
  			info = cfpkt_info(pkt);
  			info->channel_id = service->layer.id;
  			info->hdr_len = 1;
  			info->dev_info = &service->dev_info;
  			return layr->dn->transmit(layr->dn, pkt);
  		}
  	case CAIF_MODEMCMD_FLOW_OFF_REQ:
  		{
  			struct cfpkt *pkt;
  			struct caif_payload_info *info;
  			u8 flow_off = SRVL_FLOW_OFF;
  			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
638e628a6   Sjur Braendeland   caif: Bugfix - ha...
133
  			if (!pkt) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
134
135
  				pr_warn("Out of memory
  ");
638e628a6   Sjur Braendeland   caif: Bugfix - ha...
136
137
  				return -ENOMEM;
  			}
b482cd205   Sjur Braendeland   net-caif: add CAI...
138
  			if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
139
140
  				pr_err("Packet is erroneous!
  ");
b482cd205   Sjur Braendeland   net-caif: add CAI...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  				cfpkt_destroy(pkt);
  				return -EPROTO;
  			}
  			info = cfpkt_info(pkt);
  			info->channel_id = service->layer.id;
  			info->hdr_len = 1;
  			info->dev_info = &service->dev_info;
  			return layr->dn->transmit(layr->dn, pkt);
  		}
  	default:
  	  break;
  	}
  	return -EINVAL;
  }
43e369210   sjur.brandeland@stericsson.com   caif: Move refcou...
155
  static void cfsrvl_release(struct cflayer *layer)
a7da1f55a   Sjur Braendeland   caif: Bugfix - RF...
156
  {
43e369210   sjur.brandeland@stericsson.com   caif: Move refcou...
157
  	struct cfsrvl *service = container_of(layer, struct cfsrvl, layer);
a7da1f55a   Sjur Braendeland   caif: Bugfix - RF...
158
159
  	kfree(service);
  }
b482cd205   Sjur Braendeland   net-caif: add CAI...
160
  void cfsrvl_init(struct cfsrvl *service,
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
161
162
163
164
  			u8 channel_id,
  			struct dev_info *dev_info,
  			bool supports_flowctrl
  			)
b482cd205   Sjur Braendeland   net-caif: add CAI...
165
166
167
168
169
170
171
172
173
  {
  	caif_assert(offsetof(struct cfsrvl, layer) == 0);
  	service->open = false;
  	service->modem_flow_on = true;
  	service->phy_flow_on = true;
  	service->layer.id = channel_id;
  	service->layer.ctrlcmd = cfservl_ctrlcmd;
  	service->layer.modemcmd = cfservl_modemcmd;
  	service->dev_info = *dev_info;
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
174
  	service->supports_flowctrl = supports_flowctrl;
a7da1f55a   Sjur Braendeland   caif: Bugfix - RF...
175
  	service->release = cfsrvl_release;
5b2086567   Sjur Braendeland   caif: Add referen...
176
  }
b482cd205   Sjur Braendeland   net-caif: add CAI...
177
178
179
180
181
182
183
184
185
186
187
188
  bool cfsrvl_ready(struct cfsrvl *service, int *err)
  {
  	if (service->open && service->modem_flow_on && service->phy_flow_on)
  		return true;
  	if (!service->open) {
  		*err = -ENOTCONN;
  		return false;
  	}
  	caif_assert(!(service->modem_flow_on && service->phy_flow_on));
  	*err = -EAGAIN;
  	return false;
  }
43e369210   sjur.brandeland@stericsson.com   caif: Move refcou...
189

b482cd205   Sjur Braendeland   net-caif: add CAI...
190
191
192
193
194
195
196
197
198
199
200
  u8 cfsrvl_getphyid(struct cflayer *layer)
  {
  	struct cfsrvl *servl = container_obj(layer);
  	return servl->dev_info.id;
  }
  
  bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
  {
  	struct cfsrvl *servl = container_obj(layer);
  	return servl->dev_info.id == phyid;
  }
43e369210   sjur.brandeland@stericsson.com   caif: Move refcou...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  
  void caif_free_client(struct cflayer *adap_layer)
  {
  	struct cfsrvl *servl;
  	if (adap_layer == NULL || adap_layer->dn == NULL)
  		return;
  	servl = container_obj(adap_layer->dn);
  	servl->release(&servl->layer);
  }
  EXPORT_SYMBOL(caif_free_client);
  
  void caif_client_register_refcnt(struct cflayer *adapt_layer,
  					void (*hold)(struct cflayer *lyr),
  					void (*put)(struct cflayer *lyr))
  {
  	struct cfsrvl *service;
  	service = container_of(adapt_layer->dn, struct cfsrvl, layer);
  
  	WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL);
  	service->hold = hold;
  	service->put = put;
  }
  EXPORT_SYMBOL(caif_client_register_refcnt);