aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/dhd_cdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_cdc.c')
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cdc.c2530
1 files changed, 2530 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
new file mode 100644
index 00000000000..3a4de96c002
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c
@@ -0,0 +1,2530 @@
1/*
2 * DHD Protocol Module for CDC and BDC.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_cdc.c,v 1.51.6.31 2011-02-09 14:31:43 Exp $
25 *
26 * BDC is like CDC, except it includes a header for data packets to convey
27 * packet priority over the bus, and flags (e.g. to indicate checksum status
28 * for dongle offload.)
29 */
30
31#include <typedefs.h>
32#include <osl.h>
33
34#include <bcmutils.h>
35#include <bcmcdc.h>
36#include <bcmendian.h>
37
38#include <dngl_stats.h>
39#include <dhd.h>
40#include <dhd_proto.h>
41#include <dhd_bus.h>
42#include <dhd_dbg.h>
43
44
45#ifdef PROP_TXSTATUS
46#include <wlfc_proto.h>
47#include <dhd_wlfc.h>
48#endif
49
50
51#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
52#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE
53 * defined in dhd_sdio.c (amount of header tha might be added)
54 * plus any space that might be needed for alignment padding.
55 */
56#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
57 * round off at the end of buffer
58 */
59
60#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */
61
62#ifdef PROP_TXSTATUS
63typedef struct dhd_wlfc_commit_info {
64 uint8 needs_hdr;
65 uint8 ac_fifo_credit_spent;
66 ewlfc_packet_state_t pkt_type;
67 wlfc_mac_descriptor_t* mac_entry;
68 void* p;
69} dhd_wlfc_commit_info_t;
70#endif /* PROP_TXSTATUS */
71
72typedef struct dhd_prot {
73 uint16 reqid;
74 uint8 pending;
75 uint32 lastcmd;
76 uint8 bus_header[BUS_HEADER_LEN];
77 cdc_ioctl_t msg;
78 unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
79} dhd_prot_t;
80
81static int
82dhdcdc_msg(dhd_pub_t *dhd)
83{
84 int err = 0;
85 dhd_prot_t *prot = dhd->prot;
86 int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
87
88 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
89
90 DHD_OS_WAKE_LOCK(dhd);
91
92 /* NOTE : cdc->msg.len holds the desired length of the buffer to be
93 * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
94 * is actually sent to the dongle
95 */
96 if (len > CDC_MAX_MSG_SIZE)
97 len = CDC_MAX_MSG_SIZE;
98
99 /* Send request */
100 err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
101
102 DHD_OS_WAKE_UNLOCK(dhd);
103 return err;
104}
105
106static int
107dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
108{
109 int ret;
110 int cdc_len = len+sizeof(cdc_ioctl_t);
111 dhd_prot_t *prot = dhd->prot;
112
113 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
114
115 do {
116 ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
117 if (ret < 0)
118 break;
119 } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
120
121 return ret;
122}
123
124static int
125dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
126{
127 dhd_prot_t *prot = dhd->prot;
128 cdc_ioctl_t *msg = &prot->msg;
129 void *info;
130 int ret = 0, retries = 0;
131 uint32 id, flags = 0;
132
133 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
134 DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
135
136
137 /* Respond "bcmerror" and "bcmerrorstr" with local cache */
138 if (cmd == WLC_GET_VAR && buf)
139 {
140 if (!strcmp((char *)buf, "bcmerrorstr"))
141 {
142 strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
143 goto done;
144 }
145 else if (!strcmp((char *)buf, "bcmerror"))
146 {
147 *(int *)buf = dhd->dongle_error;
148 goto done;
149 }
150 }
151
152 memset(msg, 0, sizeof(cdc_ioctl_t));
153
154 msg->cmd = htol32(cmd);
155 msg->len = htol32(len);
156 msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
157 CDC_SET_IF_IDX(msg, ifidx);
158 /* add additional action bits */
159 action &= WL_IOCTL_ACTION_MASK;
160 msg->flags |= (action << CDCF_IOC_ACTION_SHIFT);
161 msg->flags = htol32(msg->flags);
162
163 if (buf)
164 memcpy(prot->buf, buf, len);
165
166 if ((ret = dhdcdc_msg(dhd)) < 0) {
167 if (!dhd->hang_was_sent)
168 DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
169 goto done;
170 }
171
172retry:
173 /* wait for interrupt and get first fragment */
174 if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
175 goto done;
176
177 flags = ltoh32(msg->flags);
178 id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
179
180 if ((id < prot->reqid) && (++retries < RETRIES))
181 goto retry;
182 if (id != prot->reqid) {
183 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
184 dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
185 ret = -EINVAL;
186 goto done;
187 }
188
189 /* Check info buffer */
190 info = (void*)&msg[1];
191
192 /* Copy info buffer */
193 if (buf)
194 {
195 if (ret < (int)len)
196 len = ret;
197 memcpy(buf, info, len);
198 }
199
200 /* Check the ERROR flag */
201 if (flags & CDCF_IOC_ERROR)
202 {
203 ret = ltoh32(msg->status);
204 /* Cache error from dongle */
205 dhd->dongle_error = ret;
206 }
207
208done:
209 return ret;
210}
211