~AR9170_USB_EP_IN_TOGGLE);
}
+static inline __inline void usb_clear_input_ep_stall(unsigned int ep)
+{
+ andl(AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH + (ep << 1),
+ ~AR9170_USB_EP_IN_STALL);
+}
+
static inline __inline void usb_set_input_ep_toggle(unsigned int ep)
{
orl(AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH + (ep << 1),
AR9170_USB_EP_OUT_TOGGLE);
}
+static inline __inline void usb_clear_output_ep_stall(unsigned int ep)
+{
+ andl(AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH + (ep << 1),
+ ~AR9170_USB_EP_OUT_STALL);
+}
+
static inline void usb_structure_check(void)
{
BUILD_BUG_ON(sizeof(struct usb_config_descriptor) != USB_DT_CONFIG_SIZE);
for (i = 1; i < __AR9170_USB_NUM_MAX_EP; i++) {
usb_set_input_ep_toggle(i);
usb_clear_input_ep_toggle(i);
+ usb_clear_input_ep_stall(i);
}
/*
for (i = 1; i < __AR9170_USB_NUM_MAX_EP; i++) {
usb_set_output_ep_toggle(i);
usb_clear_output_ep_toggle(i);
+ usb_clear_output_ep_stall(i);
}
}
#endif /* CONFIG_CARL9170FW_USB_MODESWITCH */
status = cpu_to_le16(0);
break;
- case USB_RECIP_ENDPOINT:
+ case USB_RECIP_ENDPOINT: {
+ unsigned int ep = le16_to_cpu(ctrl->wIndex) & 0xf;
+ unsigned int dir = le16_to_cpu(ctrl->wIndex) & USB_DIR_MASK;
+
+ if (ep == 0) {
+ status = !!(getb(AR9170_USB_REG_CX_CONFIG_STATUS) & BIT(2));
+ } 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);
+
+ /*
+ * AR9170_USB_EP_OUT_STALL == AR9170_USB_EP_IN_STALL
+ * so it doesn't matter which one we use
+ */
+ status = !!(getb(addr) & AR9170_USB_EP_OUT_STALL);
+ }
+ break;
+ }
case USB_RECIP_OTHER:
default:
break;
static int usb_manipulate_feature(const struct usb_ctrlrequest *ctrl, bool __unused clear)
{
unsigned int feature;
- if (USB_CHECK_REQTYPE(ctrl, USB_RECIP_DEVICE, USB_DIR_OUT))
+
+ if ((ctrl->bRequestType & USB_DIR_MASK) != USB_DIR_OUT)
return -1;
if (usb_configured() == false)
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 (feature & USB_DEVICE_REMOTE_WAKEUP) {
+ if (clear)
+ usb_disable_remote_wakeup();
+ else
+ usb_enable_remote_wakeup();
+ }
+#endif /* CONFIG_CARL9170FW_WOL */
+
if (clear)
- usb_disable_remote_wakeup();
+ fw.usb.device_feature &= ~feature;
else
- usb_enable_remote_wakeup();
- }
-#endif /* CONFIG_CARL9170FW_WOL */
+ fw.usb.device_feature |= feature;
- 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;
}
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
- usb_manipulate_feature(ctrl, ctrl->bRequest == USB_REQ_CLEAR_FEATURE);
+ status = usb_manipulate_feature(ctrl, ctrl->bRequest == USB_REQ_CLEAR_FEATURE);
break;
case USB_REQ_SET_ADDRESS: