aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2008-11-17 10:53:42 -0500
committerDavid Vrabel <david.vrabel@csr.com>2008-11-19 09:46:33 -0500
commit6fae35f9cea92793a98b2d9ab21235e5ae035581 (patch)
tree82142169ff2ccada8c6c98beb6da59cafe8d913d /drivers
parente17be2b2a95b43fe0d5878adf330701bb7a77115 (diff)
uwb: add basic radio manager
The UWB radio manager coordinates the use of the radio between the PALs that may be using it. PALs request use of the radio with uwb_radio_start() and the radio manager will start beaconing if its not already doing so. When the last PAL has called uwb_radio_stop() beaconing will be stopped. In the future, the radio manager will have a more sophisticated channel selection algorithm, probably following the Channel Selection Policy from the WiMedia Alliance when it is finalized. For now, channel 9 (BG1, TFC1) is selected. The user may override the channel selected by the radio manager and may force the radio to stop beaconing. The WUSB Host Controller PAL makes use of this and there are two new debug PAL commands that can be used for testing. Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/hwa-hc.c1
-rw-r--r--drivers/usb/host/whci/hcd.c2
-rw-r--r--drivers/usb/wusbcore/devconnect.c5
-rw-r--r--drivers/usb/wusbcore/mmc.c75
-rw-r--r--drivers/usb/wusbcore/pal.c16
-rw-r--r--drivers/usb/wusbcore/wusbhc.h8
-rw-r--r--drivers/uwb/Makefile1
-rw-r--r--drivers/uwb/beacon.c26
-rw-r--r--drivers/uwb/drp.c24
-rw-r--r--drivers/uwb/lc-rc.c11
-rw-r--r--drivers/uwb/pal.c20
-rw-r--r--drivers/uwb/radio.c202
-rw-r--r--drivers/uwb/reset.c6
-rw-r--r--drivers/uwb/rsv.c4
-rw-r--r--drivers/uwb/uwb-debug.c26
-rw-r--r--drivers/uwb/uwb-internal.h5
-rw-r--r--drivers/uwb/wlp/wlp-lc.c5
17 files changed, 294 insertions, 143 deletions
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 2827353e97e1..2a4d36fa70b0 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -221,7 +221,6 @@ static void hwahc_op_stop(struct usb_hcd *usb_hcd)
221 221
222 d_fnstart(4, dev, "(hwahc %p)\n", hwahc); 222 d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
223 mutex_lock(&wusbhc->mutex); 223 mutex_lock(&wusbhc->mutex);
224 wusbhc_stop(wusbhc);
225 wusb_cluster_id_put(wusbhc->cluster_id); 224 wusb_cluster_id_put(wusbhc->cluster_id);
226 mutex_unlock(&wusbhc->mutex); 225 mutex_unlock(&wusbhc->mutex);
227 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); 226 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
index de1e07271b81..f599f89d3be1 100644
--- a/drivers/usb/host/whci/hcd.c
+++ b/drivers/usb/host/whci/hcd.c
@@ -91,8 +91,6 @@ static void whc_stop(struct usb_hcd *usb_hcd)
91 91
92 mutex_lock(&wusbhc->mutex); 92 mutex_lock(&wusbhc->mutex);
93 93
94 wusbhc_stop(wusbhc);
95
96 /* stop HC */ 94 /* stop HC */
97 le_writel(0, whc->base + WUSBINTR); 95 le_writel(0, whc->base + WUSBINTR);
98 whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); 96 whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
index c01c7a80744c..08a1ec903867 100644
--- a/drivers/usb/wusbcore/devconnect.c
+++ b/drivers/usb/wusbcore/devconnect.c
@@ -1124,8 +1124,7 @@ void wusbhc_devconnect_destroy(struct wusbhc *wusbhc)
1124 * FIXME: This also enables the keep alives but this is not necessary 1124 * FIXME: This also enables the keep alives but this is not necessary
1125 * until there are connected and authenticated devices. 1125 * until there are connected and authenticated devices.
1126 */ 1126 */
1127int wusbhc_devconnect_start(struct wusbhc *wusbhc, 1127int wusbhc_devconnect_start(struct wusbhc *wusbhc)
1128 const struct wusb_ckhdid *chid)
1129{ 1128{
1130 struct device *dev = wusbhc->dev; 1129 struct device *dev = wusbhc->dev;
1131 struct wuie_host_info *hi; 1130 struct wuie_host_info *hi;
@@ -1138,7 +1137,7 @@ int wusbhc_devconnect_start(struct wusbhc *wusbhc,
1138 hi->hdr.bLength = sizeof(*hi); 1137 hi->hdr.bLength = sizeof(*hi);
1139 hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO; 1138 hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO;
1140 hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL); 1139 hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL);
1141 hi->CHID = *chid; 1140 hi->CHID = wusbhc->chid;
1142 result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr); 1141 result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr);
1143 if (result < 0) { 1142 if (result < 0) {
1144 dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result); 1143 dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result);
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c
index af2aee0fdffa..5463ecebafdf 100644
--- a/drivers/usb/wusbcore/mmc.c
+++ b/drivers/usb/wusbcore/mmc.c
@@ -162,12 +162,11 @@ EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
162/* 162/*
163 * wusbhc_start - start transmitting MMCs and accepting connections 163 * wusbhc_start - start transmitting MMCs and accepting connections
164 * @wusbhc: the HC to start 164 * @wusbhc: the HC to start
165 * @chid: the CHID to use for this host
166 * 165 *
167 * Establishes a cluster reservation, enables device connections, and 166 * Establishes a cluster reservation, enables device connections, and
168 * starts MMCs with appropriate DNTS parameters. 167 * starts MMCs with appropriate DNTS parameters.
169 */ 168 */
170int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) 169int wusbhc_start(struct wusbhc *wusbhc)
171{ 170{
172 int result; 171 int result;
173 struct device *dev = wusbhc->dev; 172 struct device *dev = wusbhc->dev;
@@ -181,7 +180,7 @@ int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
181 goto error_rsv_establish; 180 goto error_rsv_establish;
182 } 181 }
183 182
184 result = wusbhc_devconnect_start(wusbhc, chid); 183 result = wusbhc_devconnect_start(wusbhc);
185 if (result < 0) { 184 if (result < 0) {
186 dev_err(dev, "error enabling device connections: %d\n", result); 185 dev_err(dev, "error enabling device connections: %d\n", result);
187 goto error_devconnect_start; 186 goto error_devconnect_start;
@@ -219,34 +218,6 @@ error_rsv_establish:
219} 218}
220 219
221/* 220/*
222 * Disconnect all from the WUSB Channel
223 *
224 * Send a Host Disconnect IE in the MMC, wait, don't send it any more
225 */
226static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc)
227{
228 int result = -ENOMEM;
229 struct wuie_host_disconnect *host_disconnect_ie;
230 might_sleep();
231 host_disconnect_ie = kmalloc(sizeof(*host_disconnect_ie), GFP_KERNEL);
232 if (host_disconnect_ie == NULL)
233 goto error_alloc;
234 host_disconnect_ie->hdr.bLength = sizeof(*host_disconnect_ie);
235 host_disconnect_ie->hdr.bIEIdentifier = WUIE_ID_HOST_DISCONNECT;
236 result = wusbhc_mmcie_set(wusbhc, 0, 0, &host_disconnect_ie->hdr);
237 if (result < 0)
238 goto error_mmcie_set;
239
240 /* WUSB1.0[8.5.3.1 & 7.5.2] */
241 msleep(100);
242 wusbhc_mmcie_rm(wusbhc, &host_disconnect_ie->hdr);
243error_mmcie_set:
244 kfree(host_disconnect_ie);
245error_alloc:
246 return result;
247}
248
249/*
250 * wusbhc_stop - stop transmitting MMCs 221 * wusbhc_stop - stop transmitting MMCs
251 * @wusbhc: the HC to stop 222 * @wusbhc: the HC to stop
252 * 223 *
@@ -265,29 +236,6 @@ void wusbhc_stop(struct wusbhc *wusbhc)
265EXPORT_SYMBOL_GPL(wusbhc_stop); 236EXPORT_SYMBOL_GPL(wusbhc_stop);
266 237
267/* 238/*
268 * Change the CHID in a WUSB Channel
269 *
270 * If it is just a new CHID, send a Host Disconnect IE and then change
271 * the CHID IE.
272 */
273static int __wusbhc_chid_change(struct wusbhc *wusbhc,
274 const struct wusb_ckhdid *chid)
275{
276 int result = -ENOSYS;
277 struct device *dev = wusbhc->dev;
278 dev_err(dev, "%s() not implemented yet\n", __func__);
279 return result;
280
281 BUG_ON(wusbhc->wuie_host_info == NULL);
282 __wusbhc_host_disconnect_ie(wusbhc);
283 wusbhc->wuie_host_info->CHID = *chid;
284 result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->wuie_host_info->hdr);
285 if (result < 0)
286 dev_err(dev, "Can't update Host Info WUSB IE: %d\n", result);
287 return result;
288}
289
290/*
291 * Set/reset/update a new CHID 239 * Set/reset/update a new CHID
292 * 240 *
293 * Depending on the previous state of the MMCs, start, stop or change 241 * Depending on the previous state of the MMCs, start, stop or change
@@ -302,16 +250,19 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
302 chid = NULL; 250 chid = NULL;
303 251
304 mutex_lock(&wusbhc->mutex); 252 mutex_lock(&wusbhc->mutex);
305 if (wusbhc->active) { 253 if (chid) {
306 if (chid) 254 if (wusbhc->active) {
307 result = __wusbhc_chid_change(wusbhc, chid); 255 mutex_unlock(&wusbhc->mutex);
308 else 256 return -EBUSY;
309 wusbhc_stop(wusbhc); 257 }
310 } else { 258 wusbhc->chid = *chid;
311 if (chid)
312 wusbhc_start(wusbhc, chid);
313 } 259 }
314 mutex_unlock(&wusbhc->mutex); 260 mutex_unlock(&wusbhc->mutex);
261
262 if (chid)
263 result = uwb_radio_start(&wusbhc->pal);
264 else
265 uwb_radio_stop(&wusbhc->pal);
315 return result; 266 return result;
316} 267}
317EXPORT_SYMBOL_GPL(wusbhc_chid_set); 268EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c
index 7cc51e9905cf..d0b172c5ecc7 100644
--- a/drivers/usb/wusbcore/pal.c
+++ b/drivers/usb/wusbcore/pal.c
@@ -18,6 +18,16 @@
18 */ 18 */
19#include "wusbhc.h" 19#include "wusbhc.h"
20 20
21static void wusbhc_channel_changed(struct uwb_pal *pal, int channel)
22{
23 struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal);
24
25 if (channel < 0)
26 wusbhc_stop(wusbhc);
27 else
28 wusbhc_start(wusbhc);
29}
30
21/** 31/**
22 * wusbhc_pal_register - register the WUSB HC as a UWB PAL 32 * wusbhc_pal_register - register the WUSB HC as a UWB PAL
23 * @wusbhc: the WUSB HC 33 * @wusbhc: the WUSB HC
@@ -28,8 +38,10 @@ int wusbhc_pal_register(struct wusbhc *wusbhc)
28 38
29 wusbhc->pal.name = "wusbhc"; 39 wusbhc->pal.name = "wusbhc";
30 wusbhc->pal.device = wusbhc->usb_hcd.self.controller; 40 wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
41 wusbhc->pal.rc = wusbhc->uwb_rc;
42 wusbhc->pal.channel_changed = wusbhc_channel_changed;
31 43
32 return uwb_pal_register(wusbhc->uwb_rc, &wusbhc->pal); 44 return uwb_pal_register(&wusbhc->pal);
33} 45}
34 46
35/** 47/**
@@ -38,5 +50,5 @@ int wusbhc_pal_register(struct wusbhc *wusbhc)
38 */ 50 */
39void wusbhc_pal_unregister(struct wusbhc *wusbhc) 51void wusbhc_pal_unregister(struct wusbhc *wusbhc)
40{ 52{
41 uwb_pal_unregister(wusbhc->uwb_rc, &wusbhc->pal); 53 uwb_pal_unregister(&wusbhc->pal);
42} 54}
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
index 8fef934ad2f3..797c2453a35b 100644
--- a/drivers/usb/wusbcore/wusbhc.h
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -252,7 +252,8 @@ struct wusbhc {
252 struct uwb_pal pal; 252 struct uwb_pal pal;
253 253
254 unsigned trust_timeout; /* in jiffies */ 254 unsigned trust_timeout; /* in jiffies */
255 struct wuie_host_info *wuie_host_info; /* Includes CHID */ 255 struct wusb_ckhdid chid;
256 struct wuie_host_info *wuie_host_info;
256 257
257 struct mutex mutex; /* locks everything else */ 258 struct mutex mutex; /* locks everything else */
258 u16 cluster_id; /* Wireless USB Cluster ID */ 259 u16 cluster_id; /* Wireless USB Cluster ID */
@@ -376,15 +377,14 @@ static inline void wusbhc_put(struct wusbhc *wusbhc)
376 usb_put_hcd(&wusbhc->usb_hcd); 377 usb_put_hcd(&wusbhc->usb_hcd);
377} 378}
378 379
379int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid); 380int wusbhc_start(struct wusbhc *wusbhc);
380void wusbhc_stop(struct wusbhc *wusbhc); 381void wusbhc_stop(struct wusbhc *wusbhc);
381extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *); 382extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *);
382 383
383/* Device connect handling */ 384/* Device connect handling */
384extern int wusbhc_devconnect_create(struct wusbhc *); 385extern int wusbhc_devconnect_create(struct wusbhc *);
385extern void wusbhc_devconnect_destroy(struct wusbhc *); 386extern void wusbhc_devconnect_destroy(struct wusbhc *);
386extern int wusbhc_devconnect_start(struct wusbhc *wusbhc, 387extern int wusbhc_devconnect_start(struct wusbhc *wusbhc);
387 const struct wusb_ckhdid *chid);
388extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc); 388extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc);
389extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr, 389extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr,
390 struct wusb_dn_hdr *dn_hdr, size_t size); 390 struct wusb_dn_hdr *dn_hdr, size_t size);
diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile
index 2b99c3e61671..ce21a95da04a 100644
--- a/drivers/uwb/Makefile
+++ b/drivers/uwb/Makefile
@@ -18,6 +18,7 @@ uwb-objs := \
18 lc-rc.o \ 18 lc-rc.o \
19 neh.o \ 19 neh.o \
20 pal.o \ 20 pal.o \
21 radio.o \
21 reset.o \ 22 reset.o \
22 rsv.o \ 23 rsv.o \
23 scan.o \ 24 scan.o \
diff --git a/drivers/uwb/beacon.c b/drivers/uwb/beacon.c
index d9f2a8acc593..247956098afa 100644
--- a/drivers/uwb/beacon.c
+++ b/drivers/uwb/beacon.c
@@ -119,7 +119,6 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
119 int result; 119 int result;
120 struct device *dev = &rc->uwb_dev.dev; 120 struct device *dev = &rc->uwb_dev.dev;
121 121
122 mutex_lock(&rc->uwb_dev.mutex);
123 if (channel < 0) 122 if (channel < 0)
124 channel = -1; 123 channel = -1;
125 if (channel == -1) 124 if (channel == -1)
@@ -128,7 +127,7 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
128 /* channel >= 0...dah */ 127 /* channel >= 0...dah */
129 result = uwb_rc_start_beacon(rc, bpst_offset, channel); 128 result = uwb_rc_start_beacon(rc, bpst_offset, channel);
130 if (result < 0) 129 if (result < 0)
131 goto out_up; 130 return result;
132 if (le16_to_cpu(rc->ies->wIELength) > 0) { 131 if (le16_to_cpu(rc->ies->wIELength) > 0) {
133 result = uwb_rc_set_ie(rc, rc->ies); 132 result = uwb_rc_set_ie(rc, rc->ies);
134 if (result < 0) { 133 if (result < 0) {
@@ -137,19 +136,14 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
137 result = uwb_rc_stop_beacon(rc); 136 result = uwb_rc_stop_beacon(rc);
138 channel = -1; 137 channel = -1;
139 bpst_offset = 0; 138 bpst_offset = 0;
140 } else 139 }
141 result = 0;
142 } 140 }
143 } 141 }
144 142
145 if (result < 0) 143 if (result >= 0) {
146 goto out_up; 144 rc->beaconing = channel;
147 rc->beaconing = channel; 145 uwb_notify(rc, NULL, uwb_bg_joined(rc) ? UWB_NOTIF_BG_JOIN : UWB_NOTIF_BG_LEAVE);
148 146 }
149 uwb_notify(rc, NULL, uwb_bg_joined(rc) ? UWB_NOTIF_BG_JOIN : UWB_NOTIF_BG_LEAVE);
150
151out_up:
152 mutex_unlock(&rc->uwb_dev.mutex);
153 return result; 147 return result;
154} 148}
155 149
@@ -618,9 +612,6 @@ static ssize_t uwb_rc_beacon_show(struct device *dev,
618 612
619/* 613/*
620 * Start beaconing on the specified channel, or stop beaconing. 614 * Start beaconing on the specified channel, or stop beaconing.
621 *
622 * The BPST offset of when to start searching for a beacon group to
623 * join may be specified.
624 */ 615 */
625static ssize_t uwb_rc_beacon_store(struct device *dev, 616static ssize_t uwb_rc_beacon_store(struct device *dev,
626 struct device_attribute *attr, 617 struct device_attribute *attr,
@@ -629,12 +620,11 @@ static ssize_t uwb_rc_beacon_store(struct device *dev,
629 struct uwb_dev *uwb_dev = to_uwb_dev(dev); 620 struct uwb_dev *uwb_dev = to_uwb_dev(dev);
630 struct uwb_rc *rc = uwb_dev->rc; 621 struct uwb_rc *rc = uwb_dev->rc;
631 int channel; 622 int channel;
632 unsigned bpst_offset = 0;
633 ssize_t result = -EINVAL; 623 ssize_t result = -EINVAL;
634 624
635 result = sscanf(buf, "%d %u\n", &channel, &bpst_offset); 625 result = sscanf(buf, "%d", &channel);
636 if (result >= 1) 626 if (result >= 1)
637 result = uwb_rc_beacon(rc, channel, bpst_offset); 627 result = uwb_radio_force_channel(rc, channel);
638 628
639 return result < 0 ? result : size; 629 return result < 0 ? result : size;
640} 630}
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c
index c0b1e5e2bd08..fe328146adb7 100644
--- a/drivers/uwb/drp.c
+++ b/drivers/uwb/drp.c
@@ -37,14 +37,13 @@
37 * 37 *
38 * A DRP Availability IE is appended. 38 * A DRP Availability IE is appended.
39 * 39 *
40 * rc->uwb_dev.mutex is held 40 * rc->rsvs_mutex is held
41 * 41 *
42 * FIXME We currently ignore the returned value indicating the remaining space 42 * FIXME We currently ignore the returned value indicating the remaining space
43 * in beacon. This could be used to deny reservation requests earlier if 43 * in beacon. This could be used to deny reservation requests earlier if
44 * determined that they would cause the beacon space to be exceeded. 44 * determined that they would cause the beacon space to be exceeded.
45 */ 45 */
46static 46int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
47int uwb_rc_gen_send_drp_ie(struct uwb_rc *rc)
48{ 47{
49 int result; 48 int result;
50 struct device *dev = &rc->uwb_dev.dev; 49 struct device *dev = &rc->uwb_dev.dev;
@@ -102,25 +101,6 @@ error_cmd:
102 kfree(cmd); 101 kfree(cmd);
103error: 102error:
104 return result; 103 return result;
105
106}
107/**
108 * Send all DRP IEs associated with this host
109 *
110 * @returns: >= 0 number of bytes still available in the beacon
111 * < 0 errno code on error.
112 *
113 * As per the protocol we obtain the host controller device lock to access
114 * bandwidth structures.
115 */
116int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
117{
118 int result;
119
120 mutex_lock(&rc->uwb_dev.mutex);
121 result = uwb_rc_gen_send_drp_ie(rc);
122 mutex_unlock(&rc->uwb_dev.mutex);
123 return result;
124} 104}
125 105
126void uwb_drp_handle_timeout(struct uwb_rsv *rsv) 106void uwb_drp_handle_timeout(struct uwb_rsv *rsv)
diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
index f00633d334dd..9cf21e6bb624 100644
--- a/drivers/uwb/lc-rc.c
+++ b/drivers/uwb/lc-rc.c
@@ -189,9 +189,9 @@ static int uwb_rc_setup(struct uwb_rc *rc)
189 int result; 189 int result;
190 struct device *dev = &rc->uwb_dev.dev; 190 struct device *dev = &rc->uwb_dev.dev;
191 191
192 result = uwb_rc_reset(rc); 192 result = uwb_radio_setup(rc);
193 if (result < 0) { 193 if (result < 0) {
194 dev_err(dev, "cannot reset UWB radio: %d\n", result); 194 dev_err(dev, "cannot setup UWB radio: %d\n", result);
195 goto error; 195 goto error;
196 } 196 }
197 result = uwb_rc_mac_addr_setup(rc); 197 result = uwb_rc_mac_addr_setup(rc);
@@ -311,12 +311,7 @@ void uwb_rc_rm(struct uwb_rc *rc)
311 311
312 uwb_dbg_del_rc(rc); 312 uwb_dbg_del_rc(rc);
313 uwb_rsv_remove_all(rc); 313 uwb_rsv_remove_all(rc);
314 uwb_rc_ie_rm(rc, UWB_IDENTIFICATION_IE); 314 uwb_radio_shutdown(rc);
315 if (rc->beaconing >= 0)
316 uwb_rc_beacon(rc, -1, 0);
317 if (rc->scan_type != UWB_SCAN_DISABLED)
318 uwb_rc_scan(rc, rc->scanning, UWB_SCAN_DISABLED, 0);
319 uwb_rc_reset(rc);
320 315
321 rc->stop(rc); 316 rc->stop(rc);
322 317
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 1afb38eacb9a..605765124f5b 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -32,13 +32,13 @@ EXPORT_SYMBOL_GPL(uwb_pal_init);
32 32
33/** 33/**
34 * uwb_pal_register - register a UWB PAL 34 * uwb_pal_register - register a UWB PAL
35 * @rc: the radio controller the PAL will be using
36 * @pal: the PAL 35 * @pal: the PAL
37 * 36 *
38 * The PAL must be initialized with uwb_pal_init(). 37 * The PAL must be initialized with uwb_pal_init().
39 */ 38 */
40int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal) 39int uwb_pal_register(struct uwb_pal *pal)
41{ 40{
41 struct uwb_rc *rc = pal->rc;
42 int ret; 42 int ret;
43 43
44 if (pal->device) { 44 if (pal->device) {
@@ -54,9 +54,9 @@ int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal)
54 } 54 }
55 } 55 }
56 56
57 spin_lock(&rc->pal_lock); 57 mutex_lock(&rc->uwb_dev.mutex);
58 list_add(&pal->node, &rc->pals); 58 list_add(&pal->node, &rc->pals);
59 spin_unlock(&rc->pal_lock); 59 mutex_unlock(&rc->uwb_dev.mutex);
60 60
61 return 0; 61 return 0;
62} 62}
@@ -64,14 +64,17 @@ EXPORT_SYMBOL_GPL(uwb_pal_register);
64 64
65/** 65/**
66 * uwb_pal_register - unregister a UWB PAL 66 * uwb_pal_register - unregister a UWB PAL
67 * @rc: the radio controller the PAL was using
68 * @pal: the PAL 67 * @pal: the PAL
69 */ 68 */
70void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal) 69void uwb_pal_unregister(struct uwb_pal *pal)
71{ 70{
72 spin_lock(&rc->pal_lock); 71 struct uwb_rc *rc = pal->rc;
72
73 uwb_radio_stop(pal);
74
75 mutex_lock(&rc->uwb_dev.mutex);
73 list_del(&pal->node); 76 list_del(&pal->node);
74 spin_unlock(&rc->pal_lock); 77 mutex_unlock(&rc->uwb_dev.mutex);
75 78
76 if (pal->device) { 79 if (pal->device) {
77 sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name); 80 sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
@@ -86,6 +89,5 @@ EXPORT_SYMBOL_GPL(uwb_pal_unregister);
86 */ 89 */
87void uwb_rc_pal_init(struct uwb_rc *rc) 90void uwb_rc_pal_init(struct uwb_rc *rc)
88{ 91{
89 spin_lock_init(&rc->pal_lock);
90 INIT_LIST_HEAD(&rc->pals); 92 INIT_LIST_HEAD(&rc->pals);
91} 93}
diff --git a/drivers/uwb/radio.c b/drivers/uwb/radio.c
new file mode 100644
index 000000000000..f0d55495f5e9
--- /dev/null
+++ b/drivers/uwb/radio.c
@@ -0,0 +1,202 @@
1/*
2 * UWB radio (channel) management.
3 *
4 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include <linux/kernel.h>
19#include <linux/uwb.h>
20
21#include "uwb-internal.h"
22
23
24static int uwb_radio_select_channel(struct uwb_rc *rc)
25{
26 /*
27 * Default to channel 9 (BG1, TFC1) unless the user has
28 * selected a specific channel or there are no active PALs.
29 */
30 if (rc->active_pals == 0)
31 return -1;
32 if (rc->beaconing_forced)
33 return rc->beaconing_forced;
34 return 9;
35}
36
37
38/*
39 * Notify all active PALs that the channel has changed.
40 */
41static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel)
42{
43 struct uwb_pal *pal;
44
45 list_for_each_entry(pal, &rc->pals, node) {
46 if (pal->channel && channel != pal->channel) {
47 pal->channel = channel;
48 if (pal->channel_changed)
49 pal->channel_changed(pal, pal->channel);
50 }
51 }
52}
53
54/*
55 * Change to a new channel and notify any active PALs of the new
56 * channel.
57 *
58 * When stopping the radio, PALs need to be notified first so they can
59 * terminate any active reservations.
60 */
61static int uwb_radio_change_channel(struct uwb_rc *rc, int channel)
62{
63 int ret = 0;
64
65 if (channel == -1)
66 uwb_radio_channel_changed(rc, channel);
67
68 if (channel != rc->beaconing) {
69 if (rc->beaconing != -1 && channel != -1) {
70 /*
71 * FIXME: should signal the channel change
72 * with a Channel Change IE.
73 */
74 ret = uwb_radio_change_channel(rc, -1);
75 if (ret < 0)
76 return ret;
77 }
78 ret = uwb_rc_beacon(rc, channel, 0);
79 }
80
81 if (channel != -1)
82 uwb_radio_channel_changed(rc, rc->beaconing);
83
84 return ret;
85}
86
87/**
88 * uwb_radio_start - request that the radio be started
89 * @pal: the PAL making the request.
90 *
91 * If the radio is not already active, aa suitable channel is selected
92 * and beacons are started.
93 */
94int uwb_radio_start(struct uwb_pal *pal)
95{
96 struct uwb_rc *rc = pal->rc;
97 int ret = 0;
98
99 mutex_lock(&rc->uwb_dev.mutex);
100
101 if (!pal->channel) {
102 pal->channel = -1;
103 rc->active_pals++;
104 ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
105 }
106
107 mutex_unlock(&rc->uwb_dev.mutex);
108 return ret;
109}
110EXPORT_SYMBOL_GPL(uwb_radio_start);
111
112/**
113 * uwb_radio_stop - request tha the radio be stopped.
114 * @pal: the PAL making the request.
115 *
116 * Stops the radio if no other PAL is making use of it.
117 */
118void uwb_radio_stop(struct uwb_pal *pal)
119{
120 struct uwb_rc *rc = pal->rc;
121
122 mutex_lock(&rc->uwb_dev.mutex);
123
124 if (pal->channel) {
125 rc->active_pals--;
126 uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
127 pal->channel = 0;
128 }
129
130 mutex_unlock(&rc->uwb_dev.mutex);
131}
132EXPORT_SYMBOL_GPL(uwb_radio_stop);
133
134/*
135 * uwb_radio_force_channel - force a specific channel to be used
136 * @rc: the radio controller.
137 * @channel: the channel to use; -1 to force the radio to stop; 0 to
138 * use the default channel selection algorithm.
139 */
140int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
141{
142 int ret = 0;
143
144 mutex_lock(&rc->uwb_dev.mutex);
145
146 rc->beaconing_forced = channel;
147 ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
148
149 mutex_unlock(&rc->uwb_dev.mutex);
150 return ret;
151}
152
153/*
154 * uwb_radio_setup - setup the radio manager
155 * @rc: the radio controller.
156 *
157 * The radio controller is reset to ensure it's in a known state
158 * before it's used.
159 */
160int uwb_radio_setup(struct uwb_rc *rc)
161{
162 return uwb_rc_reset(rc);
163}
164
165/*
166 * uwb_radio_reset_state - reset any radio manager state
167 * @rc: the radio controller.
168 *
169 * All internal radio manager state is reset to values corresponding
170 * to a reset radio controller.
171 */
172void uwb_radio_reset_state(struct uwb_rc *rc)
173{
174 struct uwb_pal *pal;
175
176 mutex_lock(&rc->uwb_dev.mutex);
177
178 list_for_each_entry(pal, &rc->pals, node) {
179 if (pal->channel) {
180 pal->channel = -1;
181 if (pal->channel_changed)
182 pal->channel_changed(pal, -1);
183 }
184 }
185
186 rc->beaconing = -1;
187 rc->scanning = -1;
188
189 mutex_unlock(&rc->uwb_dev.mutex);
190}
191
192/*
193 * uwb_radio_shutdown - shutdown the radio manager
194 * @rc: the radio controller.
195 *
196 * The radio controller is reset.
197 */
198void uwb_radio_shutdown(struct uwb_rc *rc)
199{
200 uwb_radio_reset_state(rc);
201 uwb_rc_reset(rc);
202}
diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c
index e39b32099af3..ce8283cc8098 100644
--- a/drivers/uwb/reset.c
+++ b/drivers/uwb/reset.c
@@ -365,11 +365,7 @@ void uwb_rc_pre_reset(struct uwb_rc *rc)
365 rc->stop(rc); 365 rc->stop(rc);
366 uwbd_flush(rc); 366 uwbd_flush(rc);
367 367
368 mutex_lock(&rc->uwb_dev.mutex); 368 uwb_radio_reset_state(rc);
369 rc->beaconing = -1;
370 rc->scanning = -1;
371 mutex_unlock(&rc->uwb_dev.mutex);
372
373 uwb_rsv_remove_all(rc); 369 uwb_rsv_remove_all(rc);
374} 370}
375EXPORT_SYMBOL_GPL(uwb_rc_pre_reset); 371EXPORT_SYMBOL_GPL(uwb_rc_pre_reset);
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index 935d5b536db7..1cd84f927540 100644
--- a/drivers/uwb/rsv.c
+++ b/drivers/uwb/rsv.c
@@ -555,14 +555,14 @@ static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
555 * deny the request. 555 * deny the request.
556 */ 556 */
557 rsv->state = UWB_RSV_STATE_T_DENIED; 557 rsv->state = UWB_RSV_STATE_T_DENIED;
558 spin_lock(&rc->pal_lock); 558 mutex_lock(&rc->uwb_dev.mutex);
559 list_for_each_entry(pal, &rc->pals, node) { 559 list_for_each_entry(pal, &rc->pals, node) {
560 if (pal->new_rsv) 560 if (pal->new_rsv)
561 pal->new_rsv(pal, rsv); 561 pal->new_rsv(pal, rsv);
562 if (rsv->state == UWB_RSV_STATE_T_ACCEPTED) 562 if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
563 break; 563 break;
564 } 564 }
565 spin_unlock(&rc->pal_lock); 565 mutex_unlock(&rc->uwb_dev.mutex);
566 566
567 list_add_tail(&rsv->rc_node, &rc->reservations); 567 list_add_tail(&rsv->rc_node, &rc->reservations);
568 state = rsv->state; 568 state = rsv->state;
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index 217ebaac128d..0e58071a232d 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/drivers/uwb/uwb-debug.c
@@ -192,7 +192,7 @@ static ssize_t command_write(struct file *file, const char __user *buf,
192{ 192{
193 struct uwb_rc *rc = file->private_data; 193 struct uwb_rc *rc = file->private_data;
194 struct uwb_dbg_cmd cmd; 194 struct uwb_dbg_cmd cmd;
195 int ret; 195 int ret = 0;
196 196
197 if (len != sizeof(struct uwb_dbg_cmd)) 197 if (len != sizeof(struct uwb_dbg_cmd))
198 return -EINVAL; 198 return -EINVAL;
@@ -213,6 +213,12 @@ static ssize_t command_write(struct file *file, const char __user *buf,
213 case UWB_DBG_CMD_IE_RM: 213 case UWB_DBG_CMD_IE_RM:
214 ret = cmd_ie_rm(rc, &cmd.ie_rm); 214 ret = cmd_ie_rm(rc, &cmd.ie_rm);
215 break; 215 break;
216 case UWB_DBG_CMD_RADIO_START:
217 ret = uwb_radio_start(&rc->dbg->pal);
218 break;
219 case UWB_DBG_CMD_RADIO_STOP:
220 uwb_radio_stop(&rc->dbg->pal);
221 break;
216 default: 222 default:
217 return -EINVAL; 223 return -EINVAL;
218 } 224 }
@@ -306,6 +312,17 @@ static struct file_operations drp_avail_fops = {
306 .owner = THIS_MODULE, 312 .owner = THIS_MODULE,
307}; 313};
308 314
315static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
316{
317 struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
318 struct device *dev = &pal->rc->uwb_dev.dev;
319
320 if (channel > 0)
321 dev_info(dev, "debug: channel %d started\n", channel);
322 else
323 dev_info(dev, "debug: channel stopped\n");
324}
325
309static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv) 326static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
310{ 327{
311 struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal); 328 struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
@@ -329,8 +346,11 @@ void uwb_dbg_add_rc(struct uwb_rc *rc)
329 INIT_LIST_HEAD(&rc->dbg->rsvs); 346 INIT_LIST_HEAD(&rc->dbg->rsvs);
330 347
331 uwb_pal_init(&rc->dbg->pal); 348 uwb_pal_init(&rc->dbg->pal);
349 rc->dbg->pal.rc = rc;
350 rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
332 rc->dbg->pal.new_rsv = uwb_dbg_new_rsv; 351 rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
333 uwb_pal_register(rc, &rc->dbg->pal); 352 uwb_pal_register(&rc->dbg->pal);
353
334 if (root_dir) { 354 if (root_dir) {
335 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev), 355 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
336 root_dir); 356 root_dir);
@@ -364,7 +384,7 @@ void uwb_dbg_del_rc(struct uwb_rc *rc)
364 uwb_rsv_terminate(rsv); 384 uwb_rsv_terminate(rsv);
365 } 385 }
366 386
367 uwb_pal_unregister(rc, &rc->dbg->pal); 387 uwb_pal_unregister(&rc->dbg->pal);
368 388
369 if (root_dir) { 389 if (root_dir) {
370 debugfs_remove(rc->dbg->drp_avail_f); 390 debugfs_remove(rc->dbg->drp_avail_f);
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
index af95541dabcd..9c0cdb4ded0c 100644
--- a/drivers/uwb/uwb-internal.h
+++ b/drivers/uwb/uwb-internal.h
@@ -238,6 +238,11 @@ struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
238struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, 238struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
239 const struct uwb_mac_addr *macaddr); 239 const struct uwb_mac_addr *macaddr);
240 240
241int uwb_radio_setup(struct uwb_rc *rc);
242void uwb_radio_reset_state(struct uwb_rc *rc);
243void uwb_radio_shutdown(struct uwb_rc *rc);
244int uwb_radio_force_channel(struct uwb_rc *rc, int channel);
245
241/* -- UWB Sysfs representation */ 246/* -- UWB Sysfs representation */
242extern struct class uwb_rc_class; 247extern struct class uwb_rc_class;
243extern struct device_attribute dev_attr_mac_address; 248extern struct device_attribute dev_attr_mac_address;
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c
index 0799402e73fb..7e5eb49b03b8 100644
--- a/drivers/uwb/wlp/wlp-lc.c
+++ b/drivers/uwb/wlp/wlp-lc.c
@@ -543,7 +543,8 @@ int wlp_setup(struct wlp *wlp, struct uwb_rc *rc)
543 uwb_notifs_register(rc, &wlp->uwb_notifs_handler); 543 uwb_notifs_register(rc, &wlp->uwb_notifs_handler);
544 544
545 uwb_pal_init(&wlp->pal); 545 uwb_pal_init(&wlp->pal);
546 result = uwb_pal_register(rc, &wlp->pal); 546 wlp->pal.rc = rc;
547 result = uwb_pal_register(&wlp->pal);
547 if (result < 0) 548 if (result < 0)
548 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); 549 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
549 550
@@ -557,7 +558,7 @@ void wlp_remove(struct wlp *wlp)
557 struct device *dev = &wlp->rc->uwb_dev.dev; 558 struct device *dev = &wlp->rc->uwb_dev.dev;
558 d_fnstart(6, dev, "wlp %p\n", wlp); 559 d_fnstart(6, dev, "wlp %p\n", wlp);
559 wlp_neighbors_release(wlp); 560 wlp_neighbors_release(wlp);
560 uwb_pal_unregister(wlp->rc, &wlp->pal); 561 uwb_pal_unregister(&wlp->pal);
561 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); 562 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
562 wlp_eda_release(&wlp->eda); 563 wlp_eda_release(&wlp->eda);
563 mutex_lock(&wlp->mutex); 564 mutex_lock(&wlp->mutex);