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
usb
wusbcore
mmc.c
Go to the documentation of this file.
1
/*
2
* WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
3
* MMC (Microscheduled Management Command) handling
4
*
5
* Copyright (C) 2005-2006 Intel Corporation
6
* Inaky Perez-Gonzalez <
[email protected]
>
7
*
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License version
10
* 2 as published by the Free Software Foundation.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
* 02110-1301, USA.
21
*
22
*
23
* WUIEs and MMC IEs...well, they are almost the same at the end. MMC
24
* IEs are Wireless USB IEs that go into the MMC period...[what is
25
* that? look in Design-overview.txt].
26
*
27
*
28
* This is a simple subsystem to keep track of which IEs are being
29
* sent by the host in the MMC period.
30
*
31
* For each WUIE we ask to send, we keep it in an array, so we can
32
* request its removal later, or replace the content. They are tracked
33
* by pointer, so be sure to use the same pointer if you want to
34
* remove it or update the contents.
35
*
36
* FIXME:
37
* - add timers that autoremove intervalled IEs?
38
*/
39
#include <
linux/usb/wusb.h
>
40
#include <linux/slab.h>
41
#include <linux/export.h>
42
#include "
wusbhc.h
"
43
44
/* Initialize the MMCIEs handling mechanism */
45
int
wusbhc_mmcie_create
(
struct
wusbhc
*
wusbhc
)
46
{
47
u8
mmcies = wusbhc->
mmcies_max
;
48
wusbhc->
mmcie
= kcalloc(mmcies,
sizeof
(wusbhc->
mmcie
[0]),
GFP_KERNEL
);
49
if
(wusbhc->
mmcie
==
NULL
)
50
return
-
ENOMEM
;
51
mutex_init
(&wusbhc->
mmcie_mutex
);
52
return
0;
53
}
54
55
/* Release resources used by the MMCIEs handling mechanism */
56
void
wusbhc_mmcie_destroy
(
struct
wusbhc
*
wusbhc
)
57
{
58
kfree
(wusbhc->
mmcie
);
59
}
60
61
/*
62
* Add or replace an MMC Wireless USB IE.
63
*
64
* @interval: See WUSB1.0[8.5.3.1]
65
* @repeat_cnt: See WUSB1.0[8.5.3.1]
66
* @handle: See WUSB1.0[8.5.3.1]
67
* @wuie: Pointer to the header of the WUSB IE data to add.
68
* MUST BE allocated in a kmalloc buffer (no stack or
69
* vmalloc).
70
* THE CALLER ALWAYS OWNS THE POINTER (we don't free it
71
* on remove, we just forget about it).
72
* @returns: 0 if ok, < 0 errno code on error.
73
*
74
* Goes over the *whole* @wusbhc->mmcie array looking for (a) the
75
* first free spot and (b) if @wuie is already in the array (aka:
76
* transmitted in the MMCs) the spot were it is.
77
*
78
* If present, we "overwrite it" (update).
79
*
80
*
81
* NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
82
* The host uses the handle as the 'sort' index. We
83
* allocate the last one always for the WUIE_ID_HOST_INFO, and
84
* the rest, first come first serve in inverse order.
85
*
86
* Host software must make sure that it adds the other IEs in
87
* the right order... the host hardware is responsible for
88
* placing the WCTA IEs in the right place with the other IEs
89
* set by host software.
90
*
91
* NOTE: we can access wusbhc->wa_descr without locking because it is
92
* read only.
93
*/
94
int
wusbhc_mmcie_set
(
struct
wusbhc
*
wusbhc
,
u8
interval
,
u8
repeat_cnt,
95
struct
wuie_hdr
*wuie)
96
{
97
int
result
= -
ENOBUFS
;
98
unsigned
handle
, itr;
99
100
/* Search a handle, taking into account the ordering */
101
mutex_lock
(&wusbhc->
mmcie_mutex
);
102
switch
(wuie->
bIEIdentifier
) {
103
case
WUIE_ID_HOST_INFO
:
104
/* Always last */
105
handle = wusbhc->
mmcies_max
- 1;
106
break
;
107
case
WUIE_ID_ISOCH_DISCARD
:
108
dev_err
(wusbhc->
dev
,
"Special ordering case for WUIE ID 0x%x "
109
"unimplemented\n"
, wuie->
bIEIdentifier
);
110
result = -
ENOSYS
;
111
goto
error_unlock;
112
default
:
113
/* search for it or find the last empty slot */
114
handle = ~0;
115
for
(itr = 0; itr < wusbhc->
mmcies_max
- 1; itr++) {
116
if
(wusbhc->
mmcie
[itr] == wuie) {
117
handle = itr;
118
break
;
119
}
120
if
(wusbhc->
mmcie
[itr] ==
NULL
)
121
handle = itr;
122
}
123
if
(handle == ~0)
124
goto
error_unlock;
125
}
126
result = (wusbhc->
mmcie_add
)(wusbhc, interval, repeat_cnt, handle,
127
wuie);
128
if
(result >= 0)
129
wusbhc->
mmcie
[
handle
] = wuie;
130
error_unlock:
131
mutex_unlock
(&wusbhc->
mmcie_mutex
);
132
return
result
;
133
}
134
EXPORT_SYMBOL_GPL
(
wusbhc_mmcie_set
);
135
136
/*
137
* Remove an MMC IE previously added with wusbhc_mmcie_set()
138
*
139
* @wuie Pointer used to add the WUIE
140
*/
141
void
wusbhc_mmcie_rm
(
struct
wusbhc
*
wusbhc
,
struct
wuie_hdr
*wuie)
142
{
143
int
result
;
144
unsigned
handle
, itr;
145
146
mutex_lock
(&wusbhc->
mmcie_mutex
);
147
for
(itr = 0; itr < wusbhc->
mmcies_max
; itr++) {
148
if
(wusbhc->
mmcie
[itr] == wuie) {
149
handle = itr;
150
goto
found;
151
}
152
}
153
mutex_unlock
(&wusbhc->
mmcie_mutex
);
154
return
;
155
156
found:
157
result = (wusbhc->
mmcie_rm
)(wusbhc, handle);
158
if
(result == 0)
159
wusbhc->
mmcie
[itr] =
NULL
;
160
mutex_unlock
(&wusbhc->
mmcie_mutex
);
161
}
162
EXPORT_SYMBOL_GPL
(
wusbhc_mmcie_rm
);
163
164
static
int
wusbhc_mmc_start(
struct
wusbhc
*
wusbhc
)
165
{
166
int
ret
;
167
168
mutex_lock
(&wusbhc->
mutex
);
169
ret = wusbhc->
start
(wusbhc);
170
if
(ret >= 0)
171
wusbhc->
active
= 1;
172
mutex_unlock
(&wusbhc->
mutex
);
173
174
return
ret
;
175
}
176
177
static
void
wusbhc_mmc_stop(
struct
wusbhc *wusbhc)
178
{
179
mutex_lock
(&wusbhc->
mutex
);
180
wusbhc->
active
= 0;
181
wusbhc->
stop
(wusbhc,
WUSB_CHANNEL_STOP_DELAY_MS
);
182
mutex_unlock
(&wusbhc->
mutex
);
183
}
184
185
/*
186
* wusbhc_start - start transmitting MMCs and accepting connections
187
* @wusbhc: the HC to start
188
*
189
* Establishes a cluster reservation, enables device connections, and
190
* starts MMCs with appropriate DNTS parameters.
191
*/
192
int
wusbhc_start
(
struct
wusbhc *wusbhc)
193
{
194
int
result
;
195
struct
device
*
dev
= wusbhc->
dev
;
196
197
WARN_ON
(wusbhc->
wuie_host_info
!=
NULL
);
198
199
result =
wusbhc_rsv_establish
(wusbhc);
200
if
(result < 0) {
201
dev_err
(dev,
"cannot establish cluster reservation: %d\n"
,
202
result);
203
goto
error_rsv_establish;
204
}
205
206
result =
wusbhc_devconnect_start
(wusbhc);
207
if
(result < 0) {
208
dev_err
(dev,
"error enabling device connections: %d\n"
, result);
209
goto
error_devconnect_start;
210
}
211
212
result =
wusbhc_sec_start
(wusbhc);
213
if
(result < 0) {
214
dev_err
(dev,
"error starting security in the HC: %d\n"
, result);
215
goto
error_sec_start;
216
}
217
/* FIXME: the choice of the DNTS parameters is somewhat
218
* arbitrary */
219
result = wusbhc->
set_num_dnts
(wusbhc, 0, 15);
220
if
(result < 0) {
221
dev_err
(dev,
"Cannot set DNTS parameters: %d\n"
, result);
222
goto
error_set_num_dnts;
223
}
224
result = wusbhc_mmc_start(wusbhc);
225
if
(result < 0) {
226
dev_err
(dev,
"error starting wusbch: %d\n"
, result);
227
goto
error_wusbhc_start;
228
}
229
230
return
0;
231
232
error_wusbhc_start:
233
wusbhc_sec_stop
(wusbhc);
234
error_set_num_dnts:
235
error_sec_start:
236
wusbhc_devconnect_stop
(wusbhc);
237
error_devconnect_start:
238
wusbhc_rsv_terminate
(wusbhc);
239
error_rsv_establish:
240
return
result
;
241
}
242
243
/*
244
* wusbhc_stop - stop transmitting MMCs
245
* @wusbhc: the HC to stop
246
*
247
* Stops the WUSB channel and removes the cluster reservation.
248
*/
249
void
wusbhc_stop
(
struct
wusbhc *wusbhc)
250
{
251
wusbhc_mmc_stop(wusbhc);
252
wusbhc_sec_stop
(wusbhc);
253
wusbhc_devconnect_stop
(wusbhc);
254
wusbhc_rsv_terminate
(wusbhc);
255
}
256
257
/*
258
* Set/reset/update a new CHID
259
*
260
* Depending on the previous state of the MMCs, start, stop or change
261
* the sent MMC. This effectively switches the host controller on and
262
* off (radio wise).
263
*/
264
int
wusbhc_chid_set
(
struct
wusbhc *wusbhc,
const
struct
wusb_ckhdid
*chid)
265
{
266
int
result
= 0;
267
268
if
(
memcmp
(chid, &wusb_ckhdid_zero,
sizeof
(*chid)) == 0)
269
chid =
NULL
;
270
271
mutex_lock
(&wusbhc->
mutex
);
272
if
(chid) {
273
if
(wusbhc->
active
) {
274
mutex_unlock
(&wusbhc->
mutex
);
275
return
-
EBUSY
;
276
}
277
wusbhc->
chid
= *chid;
278
}
279
mutex_unlock
(&wusbhc->
mutex
);
280
281
if
(chid)
282
result =
uwb_radio_start
(&wusbhc->
pal
);
283
else
284
uwb_radio_stop
(&wusbhc->
pal
);
285
return
result
;
286
}
287
EXPORT_SYMBOL_GPL
(
wusbhc_chid_set
);
Generated on Thu Jan 10 2013 13:55:24 for Linux Kernel by
1.8.2