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
6 #include <linux/kernel.h>
7 #include <linux/stddef.h>
8 #include <net/caif/caif_layer.h>
9 #include <net/caif/cfpkt.h>
10 #include <net/caif/cfcnfg.h>
11 #include <net/caif/cfctrl.h>
12 #include <net/caif/cfmuxl.h>
13 #include <net/caif/cffrml.h>
14 #include <net/caif/cfserl.h>
15 #include <net/caif/cfsrvl.h>
17 #include <linux/module.h>
18 #include <asm/atomic.h>
20 #define MAX_PHY_LAYERS 7
21 #define PHY_NAME_LEN 20
23 #define container_obj(layr) container_of(layr, struct cfcnfg, layer)
25 /* Information about CAIF physical interfaces held by Config Module in order
26 * to manage physical interfaces
28 struct cfcnfg_phyinfo
{
29 /* Pointer to the layer below the MUX (framing layer) */
30 struct cflayer
*frm_layer
;
31 /* Pointer to the lowest actual physical layer */
32 struct cflayer
*phy_layer
;
33 /* Unique identifier of the physical interface */
35 /* Preference of the physical in interface */
36 enum cfcnfg_phy_preference pref
;
38 /* Reference count, number of channels using the device */
41 /* Information about the physical device */
42 struct dev_info dev_info
;
50 struct cfcnfg_phyinfo phy_layers
[MAX_PHY_LAYERS
];
53 static void cncfg_linkup_rsp(struct cflayer
*layer
, u8 linkid
,
54 enum cfctrl_srv serv
, u8 phyid
,
55 struct cflayer
*adapt_layer
);
56 static void cncfg_linkdestroy_rsp(struct cflayer
*layer
, u8 linkid
,
57 struct cflayer
*client_layer
);
58 static void cncfg_reject_rsp(struct cflayer
*layer
, u8 linkid
,
59 struct cflayer
*adapt_layer
);
60 static void cfctrl_resp_func(void);
61 static void cfctrl_enum_resp(void);
63 struct cfcnfg
*cfcnfg_create(void)
66 struct cfctrl_rsp
*resp
;
67 /* Initiate this layer */
68 this = kmalloc(sizeof(struct cfcnfg
), GFP_ATOMIC
);
70 pr_warning("CAIF: %s(): Out of memory\n", __func__
);
73 memset(this, 0, sizeof(struct cfcnfg
));
74 this->mux
= cfmuxl_create();
77 this->ctrl
= cfctrl_create();
80 /* Initiate response functions */
81 resp
= cfctrl_get_respfuncs(this->ctrl
);
82 resp
->enum_rsp
= cfctrl_enum_resp
;
83 resp
->linkerror_ind
= cfctrl_resp_func
;
84 resp
->linkdestroy_rsp
= cncfg_linkdestroy_rsp
;
85 resp
->sleep_rsp
= cfctrl_resp_func
;
86 resp
->wake_rsp
= cfctrl_resp_func
;
87 resp
->restart_rsp
= cfctrl_resp_func
;
88 resp
->radioset_rsp
= cfctrl_resp_func
;
89 resp
->linksetup_rsp
= cncfg_linkup_rsp
;
90 resp
->reject_rsp
= cncfg_reject_rsp
;
94 cfmuxl_set_uplayer(this->mux
, this->ctrl
, 0);
95 layer_set_dn(this->ctrl
, this->mux
);
96 layer_set_up(this->ctrl
, this);
99 pr_warning("CAIF: %s(): Out of memory\n", __func__
);
105 EXPORT_SYMBOL(cfcnfg_create
);
107 void cfcnfg_remove(struct cfcnfg
*cfg
)
116 static void cfctrl_resp_func(void)
120 static void cfctrl_enum_resp(void)
124 struct dev_info
*cfcnfg_get_phyid(struct cfcnfg
*cnfg
,
125 enum cfcnfg_phy_preference phy_pref
)
129 /* Try to match with specified preference */
130 for (i
= 1; i
< MAX_PHY_LAYERS
; i
++) {
131 if (cnfg
->phy_layers
[i
].id
== i
&&
132 cnfg
->phy_layers
[i
].pref
== phy_pref
&&
133 cnfg
->phy_layers
[i
].frm_layer
!= NULL
) {
134 caif_assert(cnfg
->phy_layers
!= NULL
);
135 caif_assert(cnfg
->phy_layers
[i
].id
== i
);
136 return &cnfg
->phy_layers
[i
].dev_info
;
139 /* Otherwise just return something */
140 for (i
= 1; i
< MAX_PHY_LAYERS
; i
++) {
141 if (cnfg
->phy_layers
[i
].id
== i
) {
142 caif_assert(cnfg
->phy_layers
!= NULL
);
143 caif_assert(cnfg
->phy_layers
[i
].id
== i
);
144 return &cnfg
->phy_layers
[i
].dev_info
;
151 static struct cfcnfg_phyinfo
*cfcnfg_get_phyinfo(struct cfcnfg
*cnfg
,
155 /* Try to match with specified preference */
156 for (i
= 0; i
< MAX_PHY_LAYERS
; i
++)
157 if (cnfg
->phy_layers
[i
].frm_layer
!= NULL
&&
158 cnfg
->phy_layers
[i
].id
== phyid
)
159 return &cnfg
->phy_layers
[i
];
163 int cfcnfg_get_named(struct cfcnfg
*cnfg
, char *name
)
167 /* Try to match with specified name */
168 for (i
= 0; i
< MAX_PHY_LAYERS
; i
++) {
169 if (cnfg
->phy_layers
[i
].frm_layer
!= NULL
170 && strcmp(cnfg
->phy_layers
[i
].phy_layer
->name
,
172 return cnfg
->phy_layers
[i
].frm_layer
->id
;
178 * NOTE: What happens on destroy failure:
179 * 1a) No response - Too early
180 * This will not happen because enumerate has already
182 * 1b) No response - FATAL
183 * Not handled, but this should be a CAIF PROTOCOL ERROR
184 * Modem error, response is really expected - this
185 * case is not really handled.
186 * 2) O/E-bit indicate error
187 * Ignored - this link is destroyed anyway.
188 * 3) Not able to match on request
189 * Not handled, but this should be a CAIF PROTOCOL ERROR
190 * 4) Link-Error - (no response)
191 * Not handled, but this should be a CAIF PROTOCOL ERROR
194 int cfcnfg_del_adapt_layer(struct cfcnfg
*cnfg
, struct cflayer
*adap_layer
)
198 struct cfcnfg_phyinfo
*phyinfo
= NULL
;
201 caif_assert(adap_layer
!= NULL
);
202 channel_id
= adap_layer
->id
;
203 if (channel_id
== 0) {
204 pr_err("CAIF: %s():adap_layer->id is 0\n", __func__
);
209 if (adap_layer
->dn
== NULL
) {
210 pr_err("CAIF: %s():adap_layer->dn is NULL\n", __func__
);
215 if (adap_layer
->dn
!= NULL
)
216 phyid
= cfsrvl_getphyid(adap_layer
->dn
);
218 phyinfo
= cfcnfg_get_phyinfo(cnfg
, phyid
);
219 if (phyinfo
== NULL
) {
220 pr_warning("CAIF: %s(): No interface to send disconnect to\n",
226 if (phyinfo
->id
!= phyid
227 || phyinfo
->phy_layer
->id
!= phyid
228 || phyinfo
->frm_layer
->id
!= phyid
) {
230 pr_err("CAIF: %s(): Inconsistency in phy registration\n",
236 ret
= cfctrl_linkdown_req(cnfg
->ctrl
, channel_id
, adap_layer
);
239 if (phyinfo
!= NULL
&& --phyinfo
->phy_ref_count
== 0 &&
240 phyinfo
->phy_layer
!= NULL
&&
241 phyinfo
->phy_layer
->modemcmd
!= NULL
) {
242 phyinfo
->phy_layer
->modemcmd(phyinfo
->phy_layer
,
243 _CAIF_MODEMCMD_PHYIF_USELESS
);
248 EXPORT_SYMBOL(cfcnfg_del_adapt_layer
);
250 static void cncfg_linkdestroy_rsp(struct cflayer
*layer
, u8 linkid
,
251 struct cflayer
*client_layer
)
253 struct cfcnfg
*cnfg
= container_obj(layer
);
254 struct cflayer
*servl
;
257 * 1) Remove service from the MUX layer. The MUX must
258 * guarante that no more payload sent "upwards" (receive)
260 servl
= cfmuxl_remove_uplayer(cnfg
->mux
, linkid
);
263 pr_err("CAIF: %s(): PROTOCOL ERROR "
264 "- Error removing service_layer Linkid(%d)",
268 caif_assert(linkid
== servl
->id
);
270 if (servl
!= client_layer
&& servl
->up
!= client_layer
) {
271 pr_err("CAIF: %s(): Error removing service_layer "
273 __func__
, linkid
, (void *) servl
,
274 (void *) client_layer
);
279 * 2) DEINIT_RSP must guarantee that no more packets are transmitted
280 * from client (adap_layer) when it returns.
283 if (servl
->ctrlcmd
== NULL
) {
284 pr_err("CAIF: %s(): Error servl->ctrlcmd == NULL", __func__
);
288 servl
->ctrlcmd(servl
, CAIF_CTRLCMD_DEINIT_RSP
, 0);
290 /* 3) It is now safe to destroy the service layer. */
291 cfservl_destroy(servl
);
295 * NOTE: What happens on linksetup failure:
296 * 1a) No response - Too early
297 * This will not happen because enumerate is secured
298 * before using interface.
299 * 1b) No response - FATAL
300 * Not handled, but this should be a CAIF PROTOCOL ERROR
301 * Modem error, response is really expected - this case is
302 * not really handled.
303 * 2) O/E-bit indicate error
304 * Handled in cnfg_reject_rsp
305 * 3) Not able to match on request
306 * Not handled, but this should be a CAIF PROTOCOL ERROR
307 * 4) Link-Error - (no response)
308 * Not handled, but this should be a CAIF PROTOCOL ERROR
312 cfcnfg_add_adaptation_layer(struct cfcnfg
*cnfg
,
313 struct cfctrl_link_param
*param
,
314 struct cflayer
*adap_layer
)
316 struct cflayer
*frml
;
317 if (adap_layer
== NULL
) {
318 pr_err("CAIF: %s(): adap_layer is zero", __func__
);
321 if (adap_layer
->receive
== NULL
) {
322 pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__
);
325 if (adap_layer
->ctrlcmd
== NULL
) {
326 pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__
);
329 frml
= cnfg
->phy_layers
[param
->phyid
].frm_layer
;
331 pr_err("CAIF: %s(): Specified PHY type does not exist!",
335 caif_assert(param
->phyid
== cnfg
->phy_layers
[param
->phyid
].id
);
336 caif_assert(cnfg
->phy_layers
[param
->phyid
].frm_layer
->id
==
338 caif_assert(cnfg
->phy_layers
[param
->phyid
].phy_layer
->id
==
340 /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
341 cfctrl_enum_req(cnfg
->ctrl
, param
->phyid
);
342 cfctrl_linkup_request(cnfg
->ctrl
, param
, adap_layer
);
345 EXPORT_SYMBOL(cfcnfg_add_adaptation_layer
);
347 static void cncfg_reject_rsp(struct cflayer
*layer
, u8 linkid
,
348 struct cflayer
*adapt_layer
)
350 if (adapt_layer
!= NULL
&& adapt_layer
->ctrlcmd
!= NULL
)
351 adapt_layer
->ctrlcmd(adapt_layer
,
352 CAIF_CTRLCMD_INIT_FAIL_RSP
, 0);
356 cncfg_linkup_rsp(struct cflayer
*layer
, u8 linkid
, enum cfctrl_srv serv
,
357 u8 phyid
, struct cflayer
*adapt_layer
)
359 struct cfcnfg
*cnfg
= container_obj(layer
);
360 struct cflayer
*servicel
= NULL
;
361 struct cfcnfg_phyinfo
*phyinfo
;
362 if (adapt_layer
== NULL
) {
363 pr_err("CAIF: %s(): PROTOCOL ERROR "
364 "- LinkUp Request/Response did not match\n", __func__
);
368 caif_assert(cnfg
!= NULL
);
369 caif_assert(phyid
!= 0);
370 phyinfo
= &cnfg
->phy_layers
[phyid
];
371 caif_assert(phyinfo
!= NULL
);
372 caif_assert(phyinfo
->id
== phyid
);
373 caif_assert(phyinfo
->phy_layer
!= NULL
);
374 caif_assert(phyinfo
->phy_layer
->id
== phyid
);
376 if (phyinfo
!= NULL
&&
377 phyinfo
->phy_ref_count
++ == 0 &&
378 phyinfo
->phy_layer
!= NULL
&&
379 phyinfo
->phy_layer
->modemcmd
!= NULL
) {
380 caif_assert(phyinfo
->phy_layer
->id
== phyid
);
381 phyinfo
->phy_layer
->modemcmd(phyinfo
->phy_layer
,
382 _CAIF_MODEMCMD_PHYIF_USEFULL
);
385 adapt_layer
->id
= linkid
;
389 servicel
= cfvei_create(linkid
, &phyinfo
->dev_info
);
391 case CFCTRL_SRV_DATAGRAM
:
392 servicel
= cfdgml_create(linkid
, &phyinfo
->dev_info
);
395 servicel
= cfrfml_create(linkid
, &phyinfo
->dev_info
);
397 case CFCTRL_SRV_UTIL
:
398 servicel
= cfutill_create(linkid
, &phyinfo
->dev_info
);
400 case CFCTRL_SRV_VIDEO
:
401 servicel
= cfvidl_create(linkid
, &phyinfo
->dev_info
);
404 servicel
= cfdbgl_create(linkid
, &phyinfo
->dev_info
);
407 pr_err("CAIF: %s(): Protocol error. "
408 "Link setup response - unknown channel type\n",
413 pr_warning("CAIF: %s(): Out of memory\n", __func__
);
416 layer_set_dn(servicel
, cnfg
->mux
);
417 cfmuxl_set_uplayer(cnfg
->mux
, servicel
, linkid
);
418 layer_set_up(servicel
, adapt_layer
);
419 layer_set_dn(adapt_layer
, servicel
);
420 servicel
->ctrlcmd(servicel
, CAIF_CTRLCMD_INIT_RSP
, 0);
424 cfcnfg_add_phy_layer(struct cfcnfg
*cnfg
, enum cfcnfg_phy_type phy_type
,
425 void *dev
, struct cflayer
*phy_layer
, u16
*phyid
,
426 enum cfcnfg_phy_preference pref
,
429 struct cflayer
*frml
;
430 struct cflayer
*phy_driver
= NULL
;
434 if (cnfg
->phy_layers
[cnfg
->last_phyid
].frm_layer
== NULL
) {
435 *phyid
= cnfg
->last_phyid
;
437 /* range: * 1..(MAX_PHY_LAYERS-1) */
439 (cnfg
->last_phyid
% (MAX_PHY_LAYERS
- 1)) + 1;
442 for (i
= 1; i
< MAX_PHY_LAYERS
; i
++) {
443 if (cnfg
->phy_layers
[i
].frm_layer
== NULL
) {
450 pr_err("CAIF: %s(): No Available PHY ID\n", __func__
);
457 cfserl_create(CFPHYTYPE_FRAG
, *phyid
, stx
);
459 pr_warning("CAIF: %s(): Out of memory\n", __func__
);
468 pr_err("CAIF: %s(): %d", __func__
, phy_type
);
473 phy_layer
->id
= *phyid
;
474 cnfg
->phy_layers
[*phyid
].pref
= pref
;
475 cnfg
->phy_layers
[*phyid
].id
= *phyid
;
476 cnfg
->phy_layers
[*phyid
].dev_info
.id
= *phyid
;
477 cnfg
->phy_layers
[*phyid
].dev_info
.dev
= dev
;
478 cnfg
->phy_layers
[*phyid
].phy_layer
= phy_layer
;
479 cnfg
->phy_layers
[*phyid
].phy_ref_count
= 0;
480 phy_layer
->type
= phy_type
;
481 frml
= cffrml_create(*phyid
, fcs
);
483 pr_warning("CAIF: %s(): Out of memory\n", __func__
);
486 cnfg
->phy_layers
[*phyid
].frm_layer
= frml
;
487 cfmuxl_set_dnlayer(cnfg
->mux
, frml
, *phyid
);
488 layer_set_up(frml
, cnfg
->mux
);
490 if (phy_driver
!= NULL
) {
491 phy_driver
->id
= *phyid
;
492 layer_set_dn(frml
, phy_driver
);
493 layer_set_up(phy_driver
, frml
);
494 layer_set_dn(phy_driver
, phy_layer
);
495 layer_set_up(phy_layer
, phy_driver
);
497 layer_set_dn(frml
, phy_layer
);
498 layer_set_up(phy_layer
, frml
);
501 EXPORT_SYMBOL(cfcnfg_add_phy_layer
);
503 int cfcnfg_del_phy_layer(struct cfcnfg
*cnfg
, struct cflayer
*phy_layer
)
505 struct cflayer
*frml
, *frml_dn
;
507 phyid
= phy_layer
->id
;
508 caif_assert(phyid
== cnfg
->phy_layers
[phyid
].id
);
509 caif_assert(phy_layer
== cnfg
->phy_layers
[phyid
].phy_layer
);
510 caif_assert(phy_layer
->id
== phyid
);
511 caif_assert(cnfg
->phy_layers
[phyid
].frm_layer
->id
== phyid
);
513 memset(&cnfg
->phy_layers
[phy_layer
->id
], 0,
514 sizeof(struct cfcnfg_phyinfo
));
515 frml
= cfmuxl_remove_dnlayer(cnfg
->mux
, phy_layer
->id
);
517 cffrml_set_uplayer(frml
, NULL
);
518 cffrml_set_dnlayer(frml
, NULL
);
521 if (phy_layer
!= frml_dn
) {
522 layer_set_up(frml_dn
, NULL
);
523 layer_set_dn(frml_dn
, NULL
);
526 layer_set_up(phy_layer
, NULL
);
529 EXPORT_SYMBOL(cfcnfg_del_phy_layer
);