Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
net
wireless
brcm80211
brcmfmac
dhd_cdc.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2010 Broadcom Corporation
3
*
4
* Permission to use, copy, modify, and/or distribute this software for any
5
* purpose with or without fee is hereby granted, provided that the above
6
* copyright notice and this permission notice appear in all copies.
7
*
8
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
*/
16
17
/*******************************************************************************
18
* Communicates with the dongle by using dcmd codes.
19
* For certain dcmd codes, the dongle interprets string data from the host.
20
******************************************************************************/
21
22
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
24
#include <linux/types.h>
25
#include <linux/netdevice.h>
26
#include <linux/sched.h>
27
#include <defs.h>
28
29
#include <
brcmu_utils.h
>
30
#include <
brcmu_wifi.h
>
31
32
#include "
dhd.h
"
33
#include "
dhd_proto.h
"
34
#include "
dhd_bus.h
"
35
#include "
dhd_dbg.h
"
36
37
struct
brcmf_proto_cdc_dcmd
{
38
__le32
cmd
;
/* dongle command value */
39
__le32
len
;
/* lower 16: output buflen;
40
* upper 16: input buflen (excludes header) */
41
__le32
flags
;
/* flag defns given below */
42
__le32
status
;
/* status code returned from the device */
43
};
44
45
/* Max valid buffer size that can be sent to the dongle */
46
#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
47
48
/* CDC flag definitions */
49
#define CDC_DCMD_ERROR 0x01
/* 1=cmd failed */
50
#define CDC_DCMD_SET 0x02
/* 0=get, 1=set cmd */
51
#define CDC_DCMD_IF_MASK 0xF000
/* I/F index */
52
#define CDC_DCMD_IF_SHIFT 12
53
#define CDC_DCMD_ID_MASK 0xFFFF0000
/* id an cmd pairing */
54
#define CDC_DCMD_ID_SHIFT 16
/* ID Mask shift bits */
55
#define CDC_DCMD_ID(flags) \
56
(((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
57
58
/*
59
* BDC header - Broadcom specific extension of CDC.
60
* Used on data packets to convey priority across USB.
61
*/
62
#define BDC_HEADER_LEN 4
63
#define BDC_PROTO_VER 2
/* Protocol version */
64
#define BDC_FLAG_VER_MASK 0xf0
/* Protocol version mask */
65
#define BDC_FLAG_VER_SHIFT 4
/* Protocol version shift */
66
#define BDC_FLAG_SUM_GOOD 0x04
/* Good RX checksums */
67
#define BDC_FLAG_SUM_NEEDED 0x08
/* Dongle needs to do TX checksums */
68
#define BDC_PRIORITY_MASK 0x7
69
#define BDC_FLAG2_IF_MASK 0x0f
/* packet rx interface in APSTA */
70
#define BDC_FLAG2_IF_SHIFT 0
71
72
#define BDC_GET_IF_IDX(hdr) \
73
((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
74
#define BDC_SET_IF_IDX(hdr, idx) \
75
((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
76
((idx) << BDC_FLAG2_IF_SHIFT)))
77
78
struct
brcmf_proto_bdc_header
{
79
u8
flags
;
80
u8
priority
;
/* 802.1d Priority, 4:7 flow control info for usb */
81
u8
flags2
;
82
u8
data_offset
;
83
};
84
85
86
#define RETRIES 2
/* # of retries to retrieve matching dcmd response */
87
#define BUS_HEADER_LEN (16+64)
/* Must be atleast SDPCM_RESERVE
88
* (amount of header tha might be added)
89
* plus any space that might be needed
90
* for bus alignment padding.
91
*/
92
#define ROUND_UP_MARGIN 2048
/* Biggest bus block size possible for
93
* round off at the end of buffer
94
* Currently is SDIO
95
*/
96
97
struct
brcmf_proto
{
98
u16
reqid
;
99
u8
pending
;
100
u32
lastcmd
;
101
u8
bus_header
[
BUS_HEADER_LEN
];
102
struct
brcmf_proto_cdc_dcmd
msg;
103
unsigned
char
buf
[
BRCMF_DCMD_MAXLEN
+
ROUND_UP_MARGIN
];
104
};
105
106
static
int
brcmf_proto_cdc_msg(
struct
brcmf_pub
*drvr)
107
{
108
struct
brcmf_proto
*prot = drvr->
prot
;
109
int
len
=
le32_to_cpu
(prot->
msg
.len) +
110
sizeof
(
struct
brcmf_proto_cdc_dcmd
);
111
112
brcmf_dbg
(
TRACE
,
"Enter\n"
);
113
114
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
115
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
116
* is actually sent to the dongle
117
*/
118
if
(len >
CDC_MAX_MSG_SIZE
)
119
len =
CDC_MAX_MSG_SIZE
;
120
121
/* Send request */
122
return
drvr->
bus_if
->brcmf_bus_txctl(drvr->
dev
,
123
(
unsigned
char
*)&prot->
msg
,
124
len);
125
}
126
127
static
int
brcmf_proto_cdc_cmplt(
struct
brcmf_pub
*drvr,
u32
id
,
u32
len)
128
{
129
int
ret
;
130
struct
brcmf_proto
*prot = drvr->
prot
;
131
132
brcmf_dbg
(
TRACE
,
"Enter\n"
);
133
134
do
{
135
ret = drvr->
bus_if
->brcmf_bus_rxctl(drvr->
dev
,
136
(
unsigned
char
*)&prot->
msg
,
137
len +
sizeof
(
struct
brcmf_proto_cdc_dcmd
));
138
if
(ret < 0)
139
break
;
140
}
while
(
CDC_DCMD_ID
(
le32_to_cpu
(prot->
msg
.flags)) !=
id
);
141
142
return
ret
;
143
}
144
145
int
146
brcmf_proto_cdc_query_dcmd
(
struct
brcmf_pub
*drvr,
int
ifidx,
uint
cmd
,
147
void
*
buf
,
uint
len)
148
{
149
struct
brcmf_proto
*prot = drvr->
prot
;
150
struct
brcmf_proto_cdc_dcmd
*
msg
= &prot->
msg
;
151
void
*
info
;
152
int
ret = 0,
retries
= 0;
153
u32
id
,
flags
;
154
155
brcmf_dbg
(
TRACE
,
"Enter\n"
);
156
brcmf_dbg
(
CTL
,
"cmd %d len %d\n"
, cmd, len);
157
158
/* Respond "bcmerror" and "bcmerrorstr" with local cache */
159
if
(cmd ==
BRCMF_C_GET_VAR
&& buf) {
160
if
(!
strcmp
((
char
*)buf,
"bcmerrorstr"
)) {
161
strncpy
((
char
*)buf,
"bcm_error"
,
162
BCME_STRLEN
);
163
goto
done
;
164
}
else
if
(!
strcmp
((
char
*)buf,
"bcmerror"
)) {
165
*(
int
*)buf = drvr->
dongle_error
;
166
goto
done
;
167
}
168
}
169
170
memset
(msg, 0,
sizeof
(
struct
brcmf_proto_cdc_dcmd
));
171
172
msg->
cmd
=
cpu_to_le32
(cmd);
173
msg->
len
=
cpu_to_le32
(len);
174
flags = (++prot->
reqid
<<
CDC_DCMD_ID_SHIFT
);
175
flags = (flags & ~
CDC_DCMD_IF_MASK
) |
176
(ifidx <<
CDC_DCMD_IF_SHIFT
);
177
msg->
flags
=
cpu_to_le32
(flags);
178
179
if
(buf)
180
memcpy
(prot->
buf
, buf, len);
181
182
ret = brcmf_proto_cdc_msg(drvr);
183
if
(ret < 0) {
184
brcmf_dbg
(
ERROR
,
"brcmf_proto_cdc_msg failed w/status %d\n"
,
185
ret);
186
goto
done
;
187
}
188
189
retry
:
190
/* wait for interrupt and get first fragment */
191
ret = brcmf_proto_cdc_cmplt(drvr, prot->
reqid
, len);
192
if
(ret < 0)
193
goto
done
;
194
195
flags =
le32_to_cpu
(msg->
flags
);
196
id
= (flags &
CDC_DCMD_ID_MASK
) >>
CDC_DCMD_ID_SHIFT
;
197
198
if
((
id < prot->
reqid) && (++
retries
<
RETRIES
))
199
goto
retry
;
200
if
(
id
!= prot->
reqid
) {
201
brcmf_dbg
(
ERROR
,
"%s: unexpected request id %d (expected %d)\n"
,
202
brcmf_ifname
(drvr, ifidx),
id
, prot->
reqid
);
203
ret = -
EINVAL
;
204
goto
done
;
205
}
206
207
/* Check info buffer */
208
info = (
void
*)&msg[1];
209
210
/* Copy info buffer */
211
if
(buf) {
212
if
(ret < (
int
)
len
)
213
len = ret;
214
memcpy
(buf, info, len);
215
}
216
217
/* Check the ERROR flag */
218
if
(flags &
CDC_DCMD_ERROR
) {
219
ret =
le32_to_cpu
(msg->
status
);
220
/* Cache error from dongle */
221
drvr->
dongle_error
=
ret
;
222
}
223
224
done
:
225
return
ret
;
226
}
227
228
int
brcmf_proto_cdc_set_dcmd
(
struct
brcmf_pub
*drvr,
int
ifidx,
uint
cmd,
229
void
*buf,
uint
len)
230
{
231
struct
brcmf_proto
*prot = drvr->
prot
;
232
struct
brcmf_proto_cdc_dcmd
*msg = &prot->
msg
;
233
int
ret = 0;
234
u32
flags
,
id
;
235
236
brcmf_dbg
(
TRACE
,
"Enter\n"
);
237
brcmf_dbg
(
CTL
,
"cmd %d len %d\n"
, cmd, len);
238
239
memset
(msg, 0,
sizeof
(
struct
brcmf_proto_cdc_dcmd
));
240
241
msg->
cmd
=
cpu_to_le32
(cmd);
242
msg->
len
=
cpu_to_le32
(len);
243
flags = (++prot->
reqid
<<
CDC_DCMD_ID_SHIFT
) |
CDC_DCMD_SET
;
244
flags = (flags & ~
CDC_DCMD_IF_MASK
) |
245
(ifidx <<
CDC_DCMD_IF_SHIFT
);
246
msg->
flags
=
cpu_to_le32
(flags);
247
248
if
(buf)
249
memcpy
(prot->
buf
, buf, len);
250
251
ret = brcmf_proto_cdc_msg(drvr);
252
if
(ret < 0)
253
goto
done
;
254
255
ret = brcmf_proto_cdc_cmplt(drvr, prot->
reqid
, len);
256
if
(ret < 0)
257
goto
done
;
258
259
flags =
le32_to_cpu
(msg->
flags
);
260
id
= (flags &
CDC_DCMD_ID_MASK
) >>
CDC_DCMD_ID_SHIFT
;
261
262
if
(
id
!= prot->
reqid
) {
263
brcmf_dbg
(
ERROR
,
"%s: unexpected request id %d (expected %d)\n"
,
264
brcmf_ifname
(drvr, ifidx),
id
, prot->
reqid
);
265
ret = -
EINVAL
;
266
goto
done
;
267
}
268
269
/* Check the ERROR flag */
270
if
(flags &
CDC_DCMD_ERROR
) {
271
ret =
le32_to_cpu
(msg->
status
);
272
/* Cache error from dongle */
273
drvr->
dongle_error
=
ret
;
274
}
275
276
done
:
277
return
ret
;
278
}
279
280
int
281
brcmf_proto_dcmd
(
struct
brcmf_pub
*drvr,
int
ifidx,
struct
brcmf_dcmd
*
dcmd
,
282
int
len)
283
{
284
struct
brcmf_proto
*prot = drvr->
prot
;
285
int
ret = -1;
286
287
if
(drvr->
bus_if
->state ==
BRCMF_BUS_DOWN
) {
288
brcmf_dbg
(
ERROR
,
"bus is down. we have nothing to do.\n"
);
289
return
ret
;
290
}
291
mutex_lock
(&drvr->
proto_block
);
292
293
brcmf_dbg
(
TRACE
,
"Enter\n"
);
294
295
if
(len >
BRCMF_DCMD_MAXLEN
)
296
goto
done
;
297
298
if
(prot->
pending
==
true
) {
299
brcmf_dbg
(
TRACE
,
"CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n"
,
300
dcmd->
cmd
, (
unsigned
long
)dcmd->
cmd
, prot->
lastcmd
,
301
(
unsigned
long
)prot->
lastcmd
);
302
if
(dcmd->
cmd
==
BRCMF_C_SET_VAR
||
303
dcmd->
cmd
==
BRCMF_C_GET_VAR
)
304
brcmf_dbg
(
TRACE
,
"iovar cmd=%s\n"
, (
char
*)dcmd->
buf
);
305
306
goto
done
;
307
}
308
309
prot->
pending
=
true
;
310
prot->
lastcmd
= dcmd->
cmd
;
311
if
(dcmd->
set
)
312
ret =
brcmf_proto_cdc_set_dcmd
(drvr, ifidx, dcmd->
cmd
,
313
dcmd->
buf
, len);
314
else
{
315
ret =
brcmf_proto_cdc_query_dcmd
(drvr, ifidx, dcmd->
cmd
,
316
dcmd->
buf
, len);
317
if
(ret > 0)
318
dcmd->
used
= ret -
319
sizeof
(
struct
brcmf_proto_cdc_dcmd
);
320
}
321
322
if
(ret >= 0)
323
ret = 0;
324
else
{
325
struct
brcmf_proto_cdc_dcmd
*msg = &prot->
msg
;
326
/* len == needed when set/query fails from dongle */
327
dcmd->
needed
=
le32_to_cpu
(msg->
len
);
328
}
329
330
/* Intercept the wme_dp dongle cmd here */
331
if
(!ret && dcmd->
cmd
==
BRCMF_C_SET_VAR
&&
332
!
strcmp
(dcmd->
buf
,
"wme_dp"
)) {
333
int
slen;
334
__le32
val
= 0;
335
336
slen =
strlen
(
"wme_dp"
) + 1;
337
if
(len >= (
int
)(slen +
sizeof
(
int
)))
338
memcpy
(&val, (
char
*)dcmd->
buf
+ slen,
sizeof
(
int
));
339
drvr->
wme_dp
= (
u8
)
le32_to_cpu
(val);
340
}
341
342
prot->
pending
=
false
;
343
344
done
:
345
mutex_unlock
(&drvr->
proto_block
);
346
347
return
ret
;
348
}
349
350
static
bool
pkt_sum_needed(
struct
sk_buff
*
skb
)
351
{
352
return
skb->
ip_summed
==
CHECKSUM_PARTIAL
;
353
}
354
355
static
void
pkt_set_sum_good(
struct
sk_buff
*
skb
,
bool
x
)
356
{
357
skb->
ip_summed
= (x ?
CHECKSUM_UNNECESSARY
:
CHECKSUM_NONE
);
358
}
359
360
void
brcmf_proto_hdrpush
(
struct
brcmf_pub
*drvr,
int
ifidx,
361
struct
sk_buff
*pktbuf)
362
{
363
struct
brcmf_proto_bdc_header
*
h
;
364
365
brcmf_dbg
(
TRACE
,
"Enter\n"
);
366
367
/* Push BDC header used to convey priority for buses that don't */
368
369
skb_push
(pktbuf,
BDC_HEADER_LEN
);
370
371
h = (
struct
brcmf_proto_bdc_header
*)(pktbuf->
data
);
372
373
h->
flags
= (
BDC_PROTO_VER
<<
BDC_FLAG_VER_SHIFT
);
374
if
(pkt_sum_needed(pktbuf))
375
h->
flags
|=
BDC_FLAG_SUM_NEEDED
;
376
377
h->
priority
= (pktbuf->
priority
&
BDC_PRIORITY_MASK
);
378
h->
flags2
= 0;
379
h->
data_offset
= 0;
380
BDC_SET_IF_IDX
(h, ifidx);
381
}
382
383
int
brcmf_proto_hdrpull
(
struct
device
*
dev
,
int
*ifidx,
384
struct
sk_buff
*pktbuf)
385
{
386
struct
brcmf_proto_bdc_header
*
h
;
387
struct
brcmf_bus
*bus_if =
dev_get_drvdata
(dev);
388
struct
brcmf_pub
*drvr = bus_if->
drvr
;
389
390
brcmf_dbg
(
TRACE
,
"Enter\n"
);
391
392
/* Pop BDC header used to convey priority for buses that don't */
393
394
if
(pktbuf->
len
<
BDC_HEADER_LEN
) {
395
brcmf_dbg
(
ERROR
,
"rx data too short (%d < %d)\n"
,
396
pktbuf->
len
,
BDC_HEADER_LEN
);
397
return
-
EBADE
;
398
}
399
400
h = (
struct
brcmf_proto_bdc_header
*)(pktbuf->
data
);
401
402
*ifidx =
BDC_GET_IF_IDX
(h);
403
if
(*ifidx >=
BRCMF_MAX_IFS
) {
404
brcmf_dbg
(
ERROR
,
"rx data ifnum out of range (%d)\n"
, *ifidx);
405
return
-
EBADE
;
406
}
407
408
if
(((h->
flags
&
BDC_FLAG_VER_MASK
) >>
BDC_FLAG_VER_SHIFT
) !=
409
BDC_PROTO_VER
) {
410
brcmf_dbg
(
ERROR
,
"%s: non-BDC packet received, flags 0x%x\n"
,
411
brcmf_ifname
(drvr, *ifidx), h->
flags
);
412
return
-
EBADE
;
413
}
414
415
if
(h->
flags
&
BDC_FLAG_SUM_GOOD
) {
416
brcmf_dbg
(
INFO
,
"%s: BDC packet received with good rx-csum, flags 0x%x\n"
,
417
brcmf_ifname
(drvr, *ifidx), h->
flags
);
418
pkt_set_sum_good(pktbuf,
true
);
419
}
420
421
pktbuf->
priority
= h->
priority
&
BDC_PRIORITY_MASK
;
422
423
skb_pull
(pktbuf,
BDC_HEADER_LEN
);
424
skb_pull
(pktbuf, h->
data_offset
<< 2);
425
426
return
0;
427
}
428
429
int
brcmf_proto_attach
(
struct
brcmf_pub
*drvr)
430
{
431
struct
brcmf_proto
*cdc;
432
433
cdc = kzalloc(
sizeof
(
struct
brcmf_proto
),
GFP_ATOMIC
);
434
if
(!cdc)
435
goto
fail;
436
437
/* ensure that the msg buf directly follows the cdc msg struct */
438
if
((
unsigned
long
)(&cdc->
msg
+ 1) != (
unsigned
long
)cdc->
buf
) {
439
brcmf_dbg
(
ERROR
,
"struct brcmf_proto is not correctly defined\n"
);
440
goto
fail;
441
}
442
443
drvr->
prot
= cdc;
444
drvr->
hdrlen
+=
BDC_HEADER_LEN
;
445
drvr->
bus_if
->maxctl =
BRCMF_DCMD_MAXLEN
+
446
sizeof
(
struct
brcmf_proto_cdc_dcmd
) +
ROUND_UP_MARGIN
;
447
return
0;
448
449
fail:
450
kfree
(cdc);
451
return
-
ENOMEM
;
452
}
453
454
/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
455
void
brcmf_proto_detach
(
struct
brcmf_pub
*drvr)
456
{
457
kfree
(drvr->
prot
);
458
drvr->
prot
=
NULL
;
459
}
460
461
int
brcmf_proto_init
(
struct
brcmf_pub
*drvr)
462
{
463
int
ret = 0;
464
char
buf[128];
465
466
brcmf_dbg
(
TRACE
,
"Enter\n"
);
467
468
mutex_lock
(&drvr->
proto_block
);
469
470
/* Get the device MAC address */
471
strcpy
(buf,
"cur_etheraddr"
);
472
ret =
brcmf_proto_cdc_query_dcmd
(drvr, 0,
BRCMF_C_GET_VAR
,
473
buf,
sizeof
(buf));
474
if
(ret < 0) {
475
mutex_unlock
(&drvr->
proto_block
);
476
return
ret
;
477
}
478
memcpy
(drvr->
mac
, buf,
ETH_ALEN
);
479
480
mutex_unlock
(&drvr->
proto_block
);
481
482
ret =
brcmf_c_preinit_dcmds
(drvr);
483
484
/* Always assumes wl for now */
485
drvr->
iswl
=
true
;
486
487
return
ret
;
488
}
489
490
void
brcmf_proto_stop
(
struct
brcmf_pub
*drvr)
491
{
492
/* Nothing to do for CDC */
493
}
Generated on Thu Jan 10 2013 14:10:24 for Linux Kernel by
1.8.2