• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/usb/wusbcore/
1
2#include <linux/usb/wusb.h>
3#include <linux/slab.h>
4#include "wusbhc.h"
5
6/* Initialize the MMCIEs handling mechanism */
7int wusbhc_mmcie_create(struct wusbhc *wusbhc)
8{
9	u8 mmcies = wusbhc->mmcies_max;
10	wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
11	if (wusbhc->mmcie == NULL)
12		return -ENOMEM;
13	mutex_init(&wusbhc->mmcie_mutex);
14	return 0;
15}
16
17/* Release resources used by the MMCIEs handling mechanism */
18void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
19{
20	kfree(wusbhc->mmcie);
21}
22
23/*
24 * Add or replace an MMC Wireless USB IE.
25 *
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
31 *               vmalloc).
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.
35 *
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.
39 *
40 * If present, we "overwrite it" (update).
41 *
42 *
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.
47 *
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.
52 *
53 * NOTE: we can access wusbhc->wa_descr without locking because it is
54 *       read only.
55 */
56int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
57		     struct wuie_hdr *wuie)
58{
59	int result = -ENOBUFS;
60	unsigned handle, itr;
61
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:
66		/* Always last */
67		handle = wusbhc->mmcies_max - 1;
68		break;
69	case WUIE_ID_ISOCH_DISCARD:
70		dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
71			"unimplemented\n", wuie->bIEIdentifier);
72		result = -ENOSYS;
73		goto error_unlock;
74	default:
75		/* search for it or find the last empty slot */
76		handle = ~0;
77		for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
78			if (wusbhc->mmcie[itr] == wuie) {
79				handle = itr;
80				break;
81			}
82			if (wusbhc->mmcie[itr] == NULL)
83				handle = itr;
84		}
85		if (handle == ~0)
86			goto error_unlock;
87	}
88	result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
89				     wuie);
90	if (result >= 0)
91		wusbhc->mmcie[handle] = wuie;
92error_unlock:
93	mutex_unlock(&wusbhc->mmcie_mutex);
94	return result;
95}
96EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
97
98/*
99 * Remove an MMC IE previously added with wusbhc_mmcie_set()
100 *
101 * @wuie	Pointer used to add the WUIE
102 */
103void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
104{
105	int result;
106	unsigned handle, itr;
107
108	mutex_lock(&wusbhc->mmcie_mutex);
109	for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
110		if (wusbhc->mmcie[itr] == wuie) {
111			handle = itr;
112			goto found;
113		}
114	}
115	mutex_unlock(&wusbhc->mmcie_mutex);
116	return;
117
118found:
119	result = (wusbhc->mmcie_rm)(wusbhc, handle);
120	if (result == 0)
121		wusbhc->mmcie[itr] = NULL;
122	mutex_unlock(&wusbhc->mmcie_mutex);
123}
124EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
125
126static int wusbhc_mmc_start(struct wusbhc *wusbhc)
127{
128	int ret;
129
130	mutex_lock(&wusbhc->mutex);
131	ret = wusbhc->start(wusbhc);
132	if (ret >= 0)
133		wusbhc->active = 1;
134	mutex_unlock(&wusbhc->mutex);
135
136	return ret;
137}
138
139static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
140{
141	mutex_lock(&wusbhc->mutex);
142	wusbhc->active = 0;
143	wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
144	mutex_unlock(&wusbhc->mutex);
145}
146
147/*
148 * wusbhc_start - start transmitting MMCs and accepting connections
149 * @wusbhc: the HC to start
150 *
151 * Establishes a cluster reservation, enables device connections, and
152 * starts MMCs with appropriate DNTS parameters.
153 */
154int wusbhc_start(struct wusbhc *wusbhc)
155{
156	int result;
157	struct device *dev = wusbhc->dev;
158
159	WARN_ON(wusbhc->wuie_host_info != NULL);
160
161	result = wusbhc_rsv_establish(wusbhc);
162	if (result < 0) {
163		dev_err(dev, "cannot establish cluster reservation: %d\n",
164			result);
165		goto error_rsv_establish;
166	}
167
168	result = wusbhc_devconnect_start(wusbhc);
169	if (result < 0) {
170		dev_err(dev, "error enabling device connections: %d\n", result);
171		goto error_devconnect_start;
172	}
173
174	result = wusbhc_sec_start(wusbhc);
175	if (result < 0) {
176		dev_err(dev, "error starting security in the HC: %d\n", result);
177		goto error_sec_start;
178	}
179	result = wusbhc->set_num_dnts(wusbhc, 0, 15);
180	if (result < 0) {
181		dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
182		goto error_set_num_dnts;
183	}
184	result = wusbhc_mmc_start(wusbhc);
185	if (result < 0) {
186		dev_err(dev, "error starting wusbch: %d\n", result);
187		goto error_wusbhc_start;
188	}
189
190	return 0;
191
192error_wusbhc_start:
193	wusbhc_sec_stop(wusbhc);
194error_set_num_dnts:
195error_sec_start:
196	wusbhc_devconnect_stop(wusbhc);
197error_devconnect_start:
198	wusbhc_rsv_terminate(wusbhc);
199error_rsv_establish:
200	return result;
201}
202
203/*
204 * wusbhc_stop - stop transmitting MMCs
205 * @wusbhc: the HC to stop
206 *
207 * Stops the WUSB channel and removes the cluster reservation.
208 */
209void wusbhc_stop(struct wusbhc *wusbhc)
210{
211	wusbhc_mmc_stop(wusbhc);
212	wusbhc_sec_stop(wusbhc);
213	wusbhc_devconnect_stop(wusbhc);
214	wusbhc_rsv_terminate(wusbhc);
215}
216
217/*
218 * Set/reset/update a new CHID
219 *
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
222 * off (radio wise).
223 */
224int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
225{
226	int result = 0;
227
228	if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
229		chid = NULL;
230
231	mutex_lock(&wusbhc->mutex);
232	if (chid) {
233		if (wusbhc->active) {
234			mutex_unlock(&wusbhc->mutex);
235			return -EBUSY;
236		}
237		wusbhc->chid = *chid;
238	}
239	mutex_unlock(&wusbhc->mutex);
240
241	if (chid)
242		result = uwb_radio_start(&wusbhc->pal);
243	else
244		uwb_radio_stop(&wusbhc->pal);
245	return result;
246}
247EXPORT_SYMBOL_GPL(wusbhc_chid_set);
248