2 #include <linux/usb/wusb.h>
3 #include <linux/slab.h>
6 /* Initialize the MMCIEs handling mechanism */
7 int wusbhc_mmcie_create(struct wusbhc
*wusbhc
)
9 u8 mmcies
= wusbhc
->mmcies_max
;
10 wusbhc
->mmcie
= kcalloc(mmcies
, sizeof(wusbhc
->mmcie
[0]), GFP_KERNEL
);
11 if (wusbhc
->mmcie
== NULL
)
13 mutex_init(&wusbhc
->mmcie_mutex
);
17 /* Release resources used by the MMCIEs handling mechanism */
18 void wusbhc_mmcie_destroy(struct wusbhc
*wusbhc
)
24 * Add or replace an MMC Wireless USB IE.
26 * @interval: See WUSB1.0[8.5.3.1]
27 * @repeat_cnt: See WUSB1.0[8.5.3.1]
28 * @handle: See WUSB1.0[8.5.3.1]
29 * @wuie: Pointer to the header of the WUSB IE data to add.
30 * MUST BE allocated in a kmalloc buffer (no stack or
32 * THE CALLER ALWAYS OWNS THE POINTER (we don't free it
33 * on remove, we just forget about it).
34 * @returns: 0 if ok, < 0 errno code on error.
36 * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
37 * first free spot and (b) if @wuie is already in the array (aka:
38 * transmitted in the MMCs) the spot were it is.
40 * If present, we "overwrite it" (update).
43 * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
44 * The host uses the handle as the 'sort' index. We
45 * allocate the last one always for the WUIE_ID_HOST_INFO, and
46 * the rest, first come first serve in inverse order.
48 * Host software must make sure that it adds the other IEs in
49 * the right order... the host hardware is responsible for
50 * placing the WCTA IEs in the right place with the other IEs
51 * set by host software.
53 * NOTE: we can access wusbhc->wa_descr without locking because it is
56 int wusbhc_mmcie_set(struct wusbhc
*wusbhc
, u8 interval
, u8 repeat_cnt
,
57 struct wuie_hdr
*wuie
)
59 int result
= -ENOBUFS
;
62 /* Search a handle, taking into account the ordering */
63 mutex_lock(&wusbhc
->mmcie_mutex
);
64 switch (wuie
->bIEIdentifier
) {
65 case WUIE_ID_HOST_INFO
:
67 handle
= wusbhc
->mmcies_max
- 1;
69 case WUIE_ID_ISOCH_DISCARD
:
70 dev_err(wusbhc
->dev
, "Special ordering case for WUIE ID 0x%x "
71 "unimplemented\n", wuie
->bIEIdentifier
);
75 /* search for it or find the last empty slot */
77 for (itr
= 0; itr
< wusbhc
->mmcies_max
- 1; itr
++) {
78 if (wusbhc
->mmcie
[itr
] == wuie
) {
82 if (wusbhc
->mmcie
[itr
] == NULL
)
88 result
= (wusbhc
->mmcie_add
)(wusbhc
, interval
, repeat_cnt
, handle
,
91 wusbhc
->mmcie
[handle
] = wuie
;
93 mutex_unlock(&wusbhc
->mmcie_mutex
);
96 EXPORT_SYMBOL_GPL(wusbhc_mmcie_set
);
99 * Remove an MMC IE previously added with wusbhc_mmcie_set()
101 * @wuie Pointer used to add the WUIE
103 void wusbhc_mmcie_rm(struct wusbhc
*wusbhc
, struct wuie_hdr
*wuie
)
106 unsigned handle
, itr
;
108 mutex_lock(&wusbhc
->mmcie_mutex
);
109 for (itr
= 0; itr
< wusbhc
->mmcies_max
; itr
++) {
110 if (wusbhc
->mmcie
[itr
] == wuie
) {
115 mutex_unlock(&wusbhc
->mmcie_mutex
);
119 result
= (wusbhc
->mmcie_rm
)(wusbhc
, handle
);
121 wusbhc
->mmcie
[itr
] = NULL
;
122 mutex_unlock(&wusbhc
->mmcie_mutex
);
124 EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm
);
126 static int wusbhc_mmc_start(struct wusbhc
*wusbhc
)
130 mutex_lock(&wusbhc
->mutex
);
131 ret
= wusbhc
->start(wusbhc
);
134 mutex_unlock(&wusbhc
->mutex
);
139 static void wusbhc_mmc_stop(struct wusbhc
*wusbhc
)
141 mutex_lock(&wusbhc
->mutex
);
143 wusbhc
->stop(wusbhc
, WUSB_CHANNEL_STOP_DELAY_MS
);
144 mutex_unlock(&wusbhc
->mutex
);
148 * wusbhc_start - start transmitting MMCs and accepting connections
149 * @wusbhc: the HC to start
151 * Establishes a cluster reservation, enables device connections, and
152 * starts MMCs with appropriate DNTS parameters.
154 int wusbhc_start(struct wusbhc
*wusbhc
)
157 struct device
*dev
= wusbhc
->dev
;
159 WARN_ON(wusbhc
->wuie_host_info
!= NULL
);
161 result
= wusbhc_rsv_establish(wusbhc
);
163 dev_err(dev
, "cannot establish cluster reservation: %d\n",
165 goto error_rsv_establish
;
168 result
= wusbhc_devconnect_start(wusbhc
);
170 dev_err(dev
, "error enabling device connections: %d\n", result
);
171 goto error_devconnect_start
;
174 result
= wusbhc_sec_start(wusbhc
);
176 dev_err(dev
, "error starting security in the HC: %d\n", result
);
177 goto error_sec_start
;
179 result
= wusbhc
->set_num_dnts(wusbhc
, 0, 15);
181 dev_err(dev
, "Cannot set DNTS parameters: %d\n", result
);
182 goto error_set_num_dnts
;
184 result
= wusbhc_mmc_start(wusbhc
);
186 dev_err(dev
, "error starting wusbch: %d\n", result
);
187 goto error_wusbhc_start
;
193 wusbhc_sec_stop(wusbhc
);
196 wusbhc_devconnect_stop(wusbhc
);
197 error_devconnect_start
:
198 wusbhc_rsv_terminate(wusbhc
);
204 * wusbhc_stop - stop transmitting MMCs
205 * @wusbhc: the HC to stop
207 * Stops the WUSB channel and removes the cluster reservation.
209 void wusbhc_stop(struct wusbhc
*wusbhc
)
211 wusbhc_mmc_stop(wusbhc
);
212 wusbhc_sec_stop(wusbhc
);
213 wusbhc_devconnect_stop(wusbhc
);
214 wusbhc_rsv_terminate(wusbhc
);
218 * Set/reset/update a new CHID
220 * Depending on the previous state of the MMCs, start, stop or change
221 * the sent MMC. This effectively switches the host controller on and
224 int wusbhc_chid_set(struct wusbhc
*wusbhc
, const struct wusb_ckhdid
*chid
)
228 if (memcmp(chid
, &wusb_ckhdid_zero
, sizeof(*chid
)) == 0)
231 mutex_lock(&wusbhc
->mutex
);
233 if (wusbhc
->active
) {
234 mutex_unlock(&wusbhc
->mutex
);
237 wusbhc
->chid
= *chid
;
239 mutex_unlock(&wusbhc
->mutex
);
242 result
= uwb_radio_start(&wusbhc
->pal
);
244 uwb_radio_stop(&wusbhc
->pal
);
247 EXPORT_SYMBOL_GPL(wusbhc_chid_set
);