uwb: add symlinks in sysfs between radio controllers and PALs

Add a facility for PALs to have symlinks to their radio controller
(and vice-versa) and make WUSB host controllers use this.

Signed-off-by: David Vrabel <david.vrabel@csr.com>
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c
index cc126b4..7cc51e9 100644
--- a/drivers/usb/wusbcore/pal.c
+++ b/drivers/usb/wusbcore/pal.c
@@ -26,6 +26,9 @@
 {
 	uwb_pal_init(&wusbhc->pal);
 
+	wusbhc->pal.name   = "wusbhc";
+	wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
+
 	return uwb_pal_register(wusbhc->uwb_rc, &wusbhc->pal);
 }
 
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index 1149b1e..07c63a3 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -192,13 +192,8 @@
 	result = wusbhc_sec_create(wusbhc);
 	if (result < 0)
 		goto error_sec_create;
-	result = wusbhc_pal_register(wusbhc);
-	if (result < 0)
-		goto error_pal_register;
 	return 0;
 
-error_pal_register:
-	wusbhc_sec_destroy(wusbhc);
 error_sec_create:
 	wusbhc_rh_destroy(wusbhc);
 error_rh_create:
@@ -235,7 +230,14 @@
 		dev_err(dev, "Cannot register WUSBHC attributes: %d\n", result);
 		goto error_create_attr_group;
 	}
-	/* Yep, I plan to add stuff here... */
+
+	result = wusbhc_pal_register(wusbhc);
+	if (result < 0)
+		goto error_pal_register;
+	return 0;
+
+error_pal_register:
+	sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
 error_create_attr_group:
 	return result;
 }
@@ -243,13 +245,13 @@
 
 void wusbhc_b_destroy(struct wusbhc *wusbhc)
 {
+	wusbhc_pal_unregister(wusbhc);
 	sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
 }
 EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
 
 void wusbhc_destroy(struct wusbhc *wusbhc)
 {
-	wusbhc_pal_unregister(wusbhc);
 	wusbhc_sec_destroy(wusbhc);
 	wusbhc_rh_destroy(wusbhc);
 	wusbhc_devconnect_destroy(wusbhc);
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 5508993..1afb38e 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -39,6 +39,21 @@
  */
 int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal)
 {
+	int ret;
+
+	if (pal->device) {
+		ret = sysfs_create_link(&pal->device->kobj,
+					&rc->uwb_dev.dev.kobj, "uwb_rc");
+		if (ret < 0)
+			return ret;
+		ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
+					&pal->device->kobj, pal->name);
+		if (ret < 0) {
+			sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+			return ret;
+		}
+	}
+
 	spin_lock(&rc->pal_lock);
 	list_add(&pal->node, &rc->pals);
 	spin_unlock(&rc->pal_lock);
@@ -57,6 +72,11 @@
 	spin_lock(&rc->pal_lock);
 	list_del(&pal->node);
 	spin_unlock(&rc->pal_lock);
+
+	if (pal->device) {
+		sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+		sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+	}
 }
 EXPORT_SYMBOL_GPL(uwb_pal_unregister);
 
diff --git a/include/linux/uwb.h b/include/linux/uwb.h
index 0cd3593..f9ccbd9 100644
--- a/include/linux/uwb.h
+++ b/include/linux/uwb.h
@@ -361,6 +361,9 @@
 
 /**
  * struct uwb_pal - a UWB PAL
+ * @name:    descriptive name for this PAL (wushc, wlp, etc.).
+ * @device:  a device for the PAL.  Used to link the PAL and the radio
+ *           controller in sysfs.
  * @new_rsv: called when a peer requests a reservation (may be NULL if
  *           the PAL cannot accept reservation requests).
  *
@@ -379,7 +382,8 @@
  */
 struct uwb_pal {
 	struct list_head node;
-
+	const char *name;
+	struct device *device;
 	void (*new_rsv)(struct uwb_rsv *rsv);
 };