From: Christian Lamparter Date: Wed, 23 Jan 2013 18:10:58 +0000 (+0100) Subject: carl9170 firmware: implement endpoint halt req/clear and get endpoint status X-Git-Tag: 1.9.8~13 X-Git-Url: https://jxself.org/git/?p=carl9170fw.git;a=commitdiff_plain;h=aad02e753490f33725d407b63b31e76c58f01caa carl9170 firmware: implement endpoint halt req/clear and get endpoint status Signed-off-by: Christian Lamparter --- diff --git a/carlfw/include/usb.h b/carlfw/include/usb.h index cea1d4d..fb258bf 100644 --- a/carlfw/include/usb.h +++ b/carlfw/include/usb.h @@ -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); diff --git a/carlfw/usb/usb.c b/carlfw/usb/usb.c index 74b8f8c..0c66b82 100644 --- a/carlfw/usb/usb.c +++ b/carlfw/usb/usb.c @@ -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: diff --git a/include/shared/hw.h b/include/shared/hw.h index 0db874a..139ded8 100644 --- a/include/shared/hw.h +++ b/include/shared/hw.h @@ -589,11 +589,13 @@ #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)