Staging: ath6kl, remove unneeded ptr checking
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / net / caif / cfsrvl.c
blobf40939a91211b8e2b6ba985f2e1562064723e681
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 */
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/slab.h>
11 #include <net/caif/caif_layer.h>
12 #include <net/caif/cfsrvl.h>
13 #include <net/caif/cfpkt.h>
15 #define SRVL_CTRL_PKT_SIZE 1
16 #define SRVL_FLOW_OFF 0x81
17 #define SRVL_FLOW_ON 0x80
18 #define SRVL_SET_PIN 0x82
19 #define SRVL_CTRL_PKT_SIZE 1
21 #define container_obj(layr) container_of(layr, struct cfsrvl, layer)
23 static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
24 int phyid)
26 struct cfsrvl *service = container_obj(layr);
28 caif_assert(layr->up != NULL);
29 caif_assert(layr->up->ctrlcmd != NULL);
31 switch (ctrl) {
32 case CAIF_CTRLCMD_INIT_RSP:
33 service->open = true;
34 layr->up->ctrlcmd(layr->up, ctrl, phyid);
35 break;
36 case CAIF_CTRLCMD_DEINIT_RSP:
37 case CAIF_CTRLCMD_INIT_FAIL_RSP:
38 service->open = false;
39 layr->up->ctrlcmd(layr->up, ctrl, phyid);
40 break;
41 case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
42 if (phyid != service->dev_info.id)
43 break;
44 if (service->modem_flow_on)
45 layr->up->ctrlcmd(layr->up,
46 CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
47 service->phy_flow_on = false;
48 break;
49 case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
50 if (phyid != service->dev_info.id)
51 return;
52 if (service->modem_flow_on) {
53 layr->up->ctrlcmd(layr->up,
54 CAIF_CTRLCMD_FLOW_ON_IND,
55 phyid);
57 service->phy_flow_on = true;
58 break;
59 case CAIF_CTRLCMD_FLOW_OFF_IND:
60 if (service->phy_flow_on) {
61 layr->up->ctrlcmd(layr->up,
62 CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
64 service->modem_flow_on = false;
65 break;
66 case CAIF_CTRLCMD_FLOW_ON_IND:
67 if (service->phy_flow_on) {
68 layr->up->ctrlcmd(layr->up,
69 CAIF_CTRLCMD_FLOW_ON_IND, phyid);
71 service->modem_flow_on = true;
72 break;
73 case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
74 /* In case interface is down, let's fake a remove shutdown */
75 layr->up->ctrlcmd(layr->up,
76 CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
77 break;
78 case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
79 layr->up->ctrlcmd(layr->up, ctrl, phyid);
80 break;
81 default:
82 pr_warning("CAIF: %s(): "
83 "Unexpected ctrl in cfsrvl (%d)\n", __func__, ctrl);
84 /* We have both modem and phy flow on, send flow on */
85 layr->up->ctrlcmd(layr->up, ctrl, phyid);
86 service->phy_flow_on = true;
87 break;
91 static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
93 struct cfsrvl *service = container_obj(layr);
95 caif_assert(layr != NULL);
96 caif_assert(layr->dn != NULL);
97 caif_assert(layr->dn->transmit != NULL);
99 if (!service->supports_flowctrl)
100 return 0;
102 switch (ctrl) {
103 case CAIF_MODEMCMD_FLOW_ON_REQ:
105 struct cfpkt *pkt;
106 struct caif_payload_info *info;
107 u8 flow_on = SRVL_FLOW_ON;
108 pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
109 if (!pkt) {
110 pr_warning("CAIF: %s(): Out of memory\n",
111 __func__);
112 return -ENOMEM;
115 if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
116 pr_err("CAIF: %s(): Packet is erroneous!\n",
117 __func__);
118 cfpkt_destroy(pkt);
119 return -EPROTO;
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 return layr->dn->transmit(layr->dn, pkt);
127 case CAIF_MODEMCMD_FLOW_OFF_REQ:
129 struct cfpkt *pkt;
130 struct caif_payload_info *info;
131 u8 flow_off = SRVL_FLOW_OFF;
132 pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
133 if (!pkt) {
134 pr_warning("CAIF: %s(): Out of memory\n",
135 __func__);
136 return -ENOMEM;
139 if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
140 pr_err("CAIF: %s(): Packet is erroneous!\n",
141 __func__);
142 cfpkt_destroy(pkt);
143 return -EPROTO;
145 info = cfpkt_info(pkt);
146 info->channel_id = service->layer.id;
147 info->hdr_len = 1;
148 info->dev_info = &service->dev_info;
149 return layr->dn->transmit(layr->dn, pkt);
151 default:
152 break;
154 return -EINVAL;
157 void cfservl_destroy(struct cflayer *layer)
159 kfree(layer);
162 void cfsrvl_release(struct kref *kref)
164 struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
165 kfree(service);
168 void cfsrvl_init(struct cfsrvl *service,
169 u8 channel_id,
170 struct dev_info *dev_info,
171 bool supports_flowctrl
174 caif_assert(offsetof(struct cfsrvl, layer) == 0);
175 service->open = false;
176 service->modem_flow_on = true;
177 service->phy_flow_on = true;
178 service->layer.id = channel_id;
179 service->layer.ctrlcmd = cfservl_ctrlcmd;
180 service->layer.modemcmd = cfservl_modemcmd;
181 service->dev_info = *dev_info;
182 service->supports_flowctrl = supports_flowctrl;
183 service->release = cfsrvl_release;
184 kref_init(&service->ref);
188 bool cfsrvl_ready(struct cfsrvl *service, int *err)
190 if (service->open && service->modem_flow_on && service->phy_flow_on)
191 return true;
192 if (!service->open) {
193 *err = -ENOTCONN;
194 return false;
196 caif_assert(!(service->modem_flow_on && service->phy_flow_on));
197 *err = -EAGAIN;
198 return false;
200 u8 cfsrvl_getphyid(struct cflayer *layer)
202 struct cfsrvl *servl = container_obj(layer);
203 return servl->dev_info.id;
206 bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
208 struct cfsrvl *servl = container_obj(layer);
209 return servl->dev_info.id == phyid;