mfd: Fix wm8994_device_init() return value
[pandora-kernel.git] / net / caif / cfcnfg.c
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 #include <linux/kernel.h>
7 #include <linux/stddef.h>
8 #include <linux/slab.h>
9 #include <linux/netdevice.h>
10 #include <net/caif/caif_layer.h>
11 #include <net/caif/cfpkt.h>
12 #include <net/caif/cfcnfg.h>
13 #include <net/caif/cfctrl.h>
14 #include <net/caif/cfmuxl.h>
15 #include <net/caif/cffrml.h>
16 #include <net/caif/cfserl.h>
17 #include <net/caif/cfsrvl.h>
18
19 #include <linux/module.h>
20 #include <asm/atomic.h>
21
22 #define MAX_PHY_LAYERS 7
23 #define PHY_NAME_LEN 20
24
25 #define container_obj(layr) container_of(layr, struct cfcnfg, layer)
26 #define RFM_FRAGMENT_SIZE 4030
27
28 /* Information about CAIF physical interfaces held by Config Module in order
29  * to manage physical interfaces
30  */
31 struct cfcnfg_phyinfo {
32         /* Pointer to the layer below the MUX (framing layer) */
33         struct cflayer *frm_layer;
34         /* Pointer to the lowest actual physical layer */
35         struct cflayer *phy_layer;
36         /* Unique identifier of the physical interface */
37         unsigned int id;
38         /* Preference of the physical in interface */
39         enum cfcnfg_phy_preference pref;
40
41         /* Reference count, number of channels using the device */
42         int phy_ref_count;
43
44         /* Information about the physical device */
45         struct dev_info dev_info;
46
47         /* Interface index */
48         int ifindex;
49
50         /* Use Start of frame extension */
51         bool use_stx;
52
53         /* Use Start of frame checksum */
54         bool use_fcs;
55 };
56
57 struct cfcnfg {
58         struct cflayer layer;
59         struct cflayer *ctrl;
60         struct cflayer *mux;
61         u8 last_phyid;
62         struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS];
63 };
64
65 static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
66                              enum cfctrl_srv serv, u8 phyid,
67                              struct cflayer *adapt_layer);
68 static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
69 static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
70                              struct cflayer *adapt_layer);
71 static void cfctrl_resp_func(void);
72 static void cfctrl_enum_resp(void);
73
74 struct cfcnfg *cfcnfg_create(void)
75 {
76         struct cfcnfg *this;
77         struct cfctrl_rsp *resp;
78         /* Initiate this layer */
79         this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
80         if (!this) {
81                 pr_warning("CAIF: %s(): Out of memory\n", __func__);
82                 return NULL;
83         }
84         this->mux = cfmuxl_create();
85         if (!this->mux)
86                 goto out_of_mem;
87         this->ctrl = cfctrl_create();
88         if (!this->ctrl)
89                 goto out_of_mem;
90         /* Initiate response functions */
91         resp = cfctrl_get_respfuncs(this->ctrl);
92         resp->enum_rsp = cfctrl_enum_resp;
93         resp->linkerror_ind = cfctrl_resp_func;
94         resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
95         resp->sleep_rsp = cfctrl_resp_func;
96         resp->wake_rsp = cfctrl_resp_func;
97         resp->restart_rsp = cfctrl_resp_func;
98         resp->radioset_rsp = cfctrl_resp_func;
99         resp->linksetup_rsp = cfcnfg_linkup_rsp;
100         resp->reject_rsp = cfcnfg_reject_rsp;
101
102         this->last_phyid = 1;
103
104         cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
105         layer_set_dn(this->ctrl, this->mux);
106         layer_set_up(this->ctrl, this);
107         return this;
108 out_of_mem:
109         pr_warning("CAIF: %s(): Out of memory\n", __func__);
110         kfree(this->mux);
111         kfree(this->ctrl);
112         kfree(this);
113         return NULL;
114 }
115 EXPORT_SYMBOL(cfcnfg_create);
116
117 void cfcnfg_remove(struct cfcnfg *cfg)
118 {
119         if (cfg) {
120                 kfree(cfg->mux);
121                 kfree(cfg->ctrl);
122                 kfree(cfg);
123         }
124 }
125
126 static void cfctrl_resp_func(void)
127 {
128 }
129
130 static void cfctrl_enum_resp(void)
131 {
132 }
133
134 struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
135                                   enum cfcnfg_phy_preference phy_pref)
136 {
137         u16 i;
138
139         /* Try to match with specified preference */
140         for (i = 1; i < MAX_PHY_LAYERS; i++) {
141                 if (cnfg->phy_layers[i].id == i &&
142                      cnfg->phy_layers[i].pref == phy_pref &&
143                      cnfg->phy_layers[i].frm_layer != NULL) {
144                         caif_assert(cnfg->phy_layers != NULL);
145                         caif_assert(cnfg->phy_layers[i].id == i);
146                         return &cnfg->phy_layers[i].dev_info;
147                 }
148         }
149         /* Otherwise just return something */
150         for (i = 1; i < MAX_PHY_LAYERS; i++) {
151                 if (cnfg->phy_layers[i].id == i) {
152                         caif_assert(cnfg->phy_layers != NULL);
153                         caif_assert(cnfg->phy_layers[i].id == i);
154                         return &cnfg->phy_layers[i].dev_info;
155                 }
156         }
157
158         return NULL;
159 }
160
161 static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
162                                                         u8 phyid)
163 {
164         int i;
165         /* Try to match with specified preference */
166         for (i = 0; i < MAX_PHY_LAYERS; i++)
167                 if (cnfg->phy_layers[i].frm_layer != NULL &&
168                     cnfg->phy_layers[i].id == phyid)
169                         return &cnfg->phy_layers[i];
170         return NULL;
171 }
172
173 int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
174 {
175         int i;
176
177         /* Try to match with specified name */
178         for (i = 0; i < MAX_PHY_LAYERS; i++) {
179                 if (cnfg->phy_layers[i].frm_layer != NULL
180                     && strcmp(cnfg->phy_layers[i].phy_layer->name,
181                               name) == 0)
182                         return cnfg->phy_layers[i].frm_layer->id;
183         }
184         return 0;
185 }
186
187 int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
188 {
189         u8 channel_id = 0;
190         int ret = 0;
191         struct cflayer *servl = NULL;
192         struct cfcnfg_phyinfo *phyinfo = NULL;
193         u8 phyid = 0;
194         caif_assert(adap_layer != NULL);
195         channel_id = adap_layer->id;
196         if (adap_layer->dn == NULL || channel_id == 0) {
197                 pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
198                 ret = -ENOTCONN;
199                 goto end;
200         }
201         servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
202         if (servl == NULL)
203                 goto end;
204         layer_set_up(servl, NULL);
205         ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
206         if (servl == NULL) {
207                 pr_err("CAIF: %s(): PROTOCOL ERROR "
208                        "- Error removing service_layer Channel_Id(%d)",
209                         __func__, channel_id);
210                 ret = -EINVAL;
211                 goto end;
212         }
213         caif_assert(channel_id == servl->id);
214         if (adap_layer->dn != NULL) {
215                 phyid = cfsrvl_getphyid(adap_layer->dn);
216
217                 phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
218                 if (phyinfo == NULL) {
219                         pr_warning("CAIF: %s(): "
220                                 "No interface to send disconnect to\n",
221                                 __func__);
222                         ret = -ENODEV;
223                         goto end;
224                 }
225                 if (phyinfo->id != phyid ||
226                         phyinfo->phy_layer->id != phyid ||
227                         phyinfo->frm_layer->id != phyid) {
228                         pr_err("CAIF: %s(): "
229                                 "Inconsistency in phy registration\n",
230                                 __func__);
231                         ret = -EINVAL;
232                         goto end;
233                 }
234         }
235         if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
236                 phyinfo->phy_layer != NULL &&
237                 phyinfo->phy_layer->modemcmd != NULL) {
238                 phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
239                                              _CAIF_MODEMCMD_PHYIF_USELESS);
240         }
241 end:
242         cfsrvl_put(servl);
243         cfctrl_cancel_req(cnfg->ctrl, adap_layer);
244         if (adap_layer->ctrlcmd != NULL)
245                 adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
246         return ret;
247
248 }
249 EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer);
250
251 void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
252 {
253         if (adap_layer->dn)
254                 cfsrvl_put(adap_layer->dn);
255 }
256 EXPORT_SYMBOL(cfcnfg_release_adap_layer);
257
258 static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
259 {
260 }
261
262 int protohead[CFCTRL_SRV_MASK] = {
263         [CFCTRL_SRV_VEI] = 4,
264         [CFCTRL_SRV_DATAGRAM] = 7,
265         [CFCTRL_SRV_UTIL] = 4,
266         [CFCTRL_SRV_RFM] = 3,
267         [CFCTRL_SRV_DBG] = 3,
268 };
269
270 int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
271                                 struct cfctrl_link_param *param,
272                                 struct cflayer *adap_layer,
273                                 int *ifindex,
274                                 int *proto_head,
275                                 int *proto_tail)
276 {
277         struct cflayer *frml;
278         if (adap_layer == NULL) {
279                 pr_err("CAIF: %s(): adap_layer is zero", __func__);
280                 return -EINVAL;
281         }
282         if (adap_layer->receive == NULL) {
283                 pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__);
284                 return -EINVAL;
285         }
286         if (adap_layer->ctrlcmd == NULL) {
287                 pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__);
288                 return -EINVAL;
289         }
290         frml = cnfg->phy_layers[param->phyid].frm_layer;
291         if (frml == NULL) {
292                 pr_err("CAIF: %s(): Specified PHY type does not exist!",
293                         __func__);
294                 return -ENODEV;
295         }
296         caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
297         caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id ==
298                      param->phyid);
299         caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
300                      param->phyid);
301
302         *ifindex = cnfg->phy_layers[param->phyid].ifindex;
303         *proto_head =
304                 protohead[param->linktype]+
305                 (cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);
306
307         *proto_tail = 2;
308
309         /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
310         cfctrl_enum_req(cnfg->ctrl, param->phyid);
311         return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
312 }
313 EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);
314
315 static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
316                              struct cflayer *adapt_layer)
317 {
318         if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
319                 adapt_layer->ctrlcmd(adapt_layer,
320                                      CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
321 }
322
323 static void
324 cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
325                  u8 phyid, struct cflayer *adapt_layer)
326 {
327         struct cfcnfg *cnfg = container_obj(layer);
328         struct cflayer *servicel = NULL;
329         struct cfcnfg_phyinfo *phyinfo;
330         struct net_device *netdev;
331
332         if (adapt_layer == NULL) {
333                 pr_debug("CAIF: %s(): link setup response "
334                                 "but no client exist, send linkdown back\n",
335                                 __func__);
336                 cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
337                 return;
338         }
339
340         caif_assert(cnfg != NULL);
341         caif_assert(phyid != 0);
342         phyinfo = &cnfg->phy_layers[phyid];
343         caif_assert(phyinfo->id == phyid);
344         caif_assert(phyinfo->phy_layer != NULL);
345         caif_assert(phyinfo->phy_layer->id == phyid);
346
347         phyinfo->phy_ref_count++;
348         if (phyinfo->phy_ref_count == 1 &&
349             phyinfo->phy_layer->modemcmd != NULL) {
350                 phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
351                                              _CAIF_MODEMCMD_PHYIF_USEFULL);
352         }
353         adapt_layer->id = channel_id;
354
355         switch (serv) {
356         case CFCTRL_SRV_VEI:
357                 servicel = cfvei_create(channel_id, &phyinfo->dev_info);
358                 break;
359         case CFCTRL_SRV_DATAGRAM:
360                 servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
361                 break;
362         case CFCTRL_SRV_RFM:
363                 netdev = phyinfo->dev_info.dev;
364                 servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
365                                                 netdev->mtu);
366                 break;
367         case CFCTRL_SRV_UTIL:
368                 servicel = cfutill_create(channel_id, &phyinfo->dev_info);
369                 break;
370         case CFCTRL_SRV_VIDEO:
371                 servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
372                 break;
373         case CFCTRL_SRV_DBG:
374                 servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
375                 break;
376         default:
377                 pr_err("CAIF: %s(): Protocol error. "
378                         "Link setup response - unknown channel type\n",
379                         __func__);
380                 return;
381         }
382         if (!servicel) {
383                 pr_warning("CAIF: %s(): Out of memory\n", __func__);
384                 return;
385         }
386         layer_set_dn(servicel, cnfg->mux);
387         cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
388         layer_set_up(servicel, adapt_layer);
389         layer_set_dn(adapt_layer, servicel);
390         cfsrvl_get(servicel);
391         servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
392 }
393
394 void
395 cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
396                      struct net_device *dev, struct cflayer *phy_layer,
397                      u16 *phyid, enum cfcnfg_phy_preference pref,
398                      bool fcs, bool stx)
399 {
400         struct cflayer *frml;
401         struct cflayer *phy_driver = NULL;
402         int i;
403
404
405         if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) {
406                 *phyid = cnfg->last_phyid;
407
408                 /* range: * 1..(MAX_PHY_LAYERS-1) */
409                 cnfg->last_phyid =
410                     (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1;
411         } else {
412                 *phyid = 0;
413                 for (i = 1; i < MAX_PHY_LAYERS; i++) {
414                         if (cnfg->phy_layers[i].frm_layer == NULL) {
415                                 *phyid = i;
416                                 break;
417                         }
418                 }
419         }
420         if (*phyid == 0) {
421                 pr_err("CAIF: %s(): No Available PHY ID\n", __func__);
422                 return;
423         }
424
425         switch (phy_type) {
426         case CFPHYTYPE_FRAG:
427                 phy_driver =
428                     cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
429                 if (!phy_driver) {
430                         pr_warning("CAIF: %s(): Out of memory\n", __func__);
431                         return;
432                 }
433
434                 break;
435         case CFPHYTYPE_CAIF:
436                 phy_driver = NULL;
437                 break;
438         default:
439                 pr_err("CAIF: %s(): %d", __func__, phy_type);
440                 return;
441                 break;
442         }
443
444         phy_layer->id = *phyid;
445         cnfg->phy_layers[*phyid].pref = pref;
446         cnfg->phy_layers[*phyid].id = *phyid;
447         cnfg->phy_layers[*phyid].dev_info.id = *phyid;
448         cnfg->phy_layers[*phyid].dev_info.dev = dev;
449         cnfg->phy_layers[*phyid].phy_layer = phy_layer;
450         cnfg->phy_layers[*phyid].phy_ref_count = 0;
451         cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
452         cnfg->phy_layers[*phyid].use_stx = stx;
453         cnfg->phy_layers[*phyid].use_fcs = fcs;
454
455         phy_layer->type = phy_type;
456         frml = cffrml_create(*phyid, fcs);
457         if (!frml) {
458                 pr_warning("CAIF: %s(): Out of memory\n", __func__);
459                 return;
460         }
461         cnfg->phy_layers[*phyid].frm_layer = frml;
462         cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
463         layer_set_up(frml, cnfg->mux);
464
465         if (phy_driver != NULL) {
466                 phy_driver->id = *phyid;
467                 layer_set_dn(frml, phy_driver);
468                 layer_set_up(phy_driver, frml);
469                 layer_set_dn(phy_driver, phy_layer);
470                 layer_set_up(phy_layer, phy_driver);
471         } else {
472                 layer_set_dn(frml, phy_layer);
473                 layer_set_up(phy_layer, frml);
474         }
475 }
476 EXPORT_SYMBOL(cfcnfg_add_phy_layer);
477
478 int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
479 {
480         struct cflayer *frml, *frml_dn;
481         u16 phyid;
482         phyid = phy_layer->id;
483         caif_assert(phyid == cnfg->phy_layers[phyid].id);
484         caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer);
485         caif_assert(phy_layer->id == phyid);
486         caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid);
487
488         memset(&cnfg->phy_layers[phy_layer->id], 0,
489                sizeof(struct cfcnfg_phyinfo));
490         frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
491         frml_dn = frml->dn;
492         cffrml_set_uplayer(frml, NULL);
493         cffrml_set_dnlayer(frml, NULL);
494         kfree(frml);
495
496         if (phy_layer != frml_dn) {
497                 layer_set_up(frml_dn, NULL);
498                 layer_set_dn(frml_dn, NULL);
499                 kfree(frml_dn);
500         }
501         layer_set_up(phy_layer, NULL);
502         return 0;
503 }
504 EXPORT_SYMBOL(cfcnfg_del_phy_layer);