+static int usb_manipulate_feature(const struct usb_ctrlrequest *ctrl, bool __unused clear)
+{
+ unsigned int feature;
+
+ if ((ctrl->bRequestType & USB_DIR_MASK) != USB_DIR_OUT)
+ return -1;
+
+ if (usb_configured() == false)
+ return -1;
+
+ feature = le16_to_cpu(ctrl->wValue);
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE: {
+#ifdef CONFIG_CARL9170FW_WOL
+ if (feature & USB_DEVICE_REMOTE_WAKEUP) {
+ if (clear)
+ usb_disable_remote_wakeup();
+ else
+ usb_enable_remote_wakeup();
+ }
+#endif /* CONFIG_CARL9170FW_WOL */
+
+ if (clear)
+ fw.usb.device_feature &= ~feature;
+ else
+ fw.usb.device_feature |= feature;
+
+
+ break;
+ }
+
+ case USB_RECIP_ENDPOINT: {
+ unsigned int ep, dir;
+
+ ep = le16_to_cpu(ctrl->wIndex) & 0xf;
+ dir = le16_to_cpu(ctrl->wIndex) & USB_DIR_MASK;
+ if (ep == 0) {
+ /* According to the spec, EP cannot be stopped this way. */
+ return -1;
+ } else {
+ unsigned int addr;
+
+ if (dir == USB_DIR_IN)
+ addr = AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH;
+ else
+ addr = AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH;
+
+ addr += (ep << 1);
+
+ if (clear)
+ andb(addr, ~AR9170_USB_EP_OUT_STALL);
+ else
+ orb(addr, AR9170_USB_EP_OUT_STALL);
+ }
+ break;
+ }
+
+ case USB_RECIP_INTERFACE:
+ /*
+ * the current USB Specification Revision 2
+ * specifies no interface features.
+ */
+
+ default:
+ return -1;
+ }
+
+ return 1;
+}
+