carl9170 firmware: implement endpoint halt req/clear and get endpoint status
authorChristian Lamparter <chunkeey@googlemail.com>
Wed, 23 Jan 2013 18:10:58 +0000 (19:10 +0100)
committerChristian Lamparter <chunkeey@googlemail.com>
Mon, 18 Feb 2013 00:27:30 +0000 (01:27 +0100)
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
carlfw/include/usb.h
carlfw/usb/usb.c
include/shared/hw.h

index cea1d4da90e00ef5eec51edb6f1dad42cc59e670..fb258bf16bd37be843d3542f26fa771c921e76b4 100644 (file)
@@ -141,6 +141,12 @@ static inline __inline void usb_clear_input_ep_toggle(unsigned int ep)
             ~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),
@@ -159,6 +165,12 @@ static inline __inline void usb_set_output_ep_toggle(unsigned int ep)
            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);
index 74b8f8c4dcc6baac78b888bf7bfee0fbe79a43ab..0c66b8275b636e91d0a0c94e4070c32777ed6e68 100644 (file)
@@ -175,6 +175,7 @@ static void usb_reset_eps(void)
        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);
        }
 
        /*
@@ -184,6 +185,7 @@ static void usb_reset_eps(void)
        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 */
@@ -337,7 +339,30 @@ static int usb_get_status(const struct usb_ctrlrequest *ctrl)
                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;
@@ -571,7 +596,8 @@ static int usb_get_interface(const struct usb_ctrlrequest *ctrl)
 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)
@@ -579,19 +605,61 @@ static int usb_manipulate_feature(const struct usb_ctrlrequest *ctrl, bool __unu
 
        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;
 }
@@ -645,7 +713,7 @@ static int usb_standard_command(const struct usb_ctrlrequest *ctrl __unused)
 
        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:
index 0db874abde500750f7365ed6a9c254b297d03025..139ded8dc6a402d1efe179cb40108452d9ecd22b 100644 (file)
 #define        AR9170_USB_REG_EP10_MAP                 (AR9170_USB_REG_BASE + 0x039)
 
 #define        AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH      (AR9170_USB_REG_BASE + 0x03f)
+#define                AR9170_USB_EP_IN_STALL                  0x8
 #define                AR9170_USB_EP_IN_TOGGLE                 0x10
 
 #define        AR9170_USB_REG_EP_IN_MAX_SIZE_LOW       (AR9170_USB_REG_BASE + 0x03e)
 
 #define        AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH     (AR9170_USB_REG_BASE + 0x05f)
+#define                AR9170_USB_EP_OUT_STALL                 0x8
 #define                AR9170_USB_EP_OUT_TOGGLE                0x10
 
 #define        AR9170_USB_REG_EP_OUT_MAX_SIZE_LOW      (AR9170_USB_REG_BASE + 0x05e)