X-Git-Url: https://jxself.org/git/?p=carl9170fw.git;a=blobdiff_plain;f=carlfw%2Fusb%2Fusb.c;h=aedf30d1404830bb989e9ba8caeb4a459aee5fc1;hp=49852fb70611a318d4410cf66d1e3c9855c688f8;hb=f99b6fd51bf8429eaad357ac9c7149a92f719628;hpb=e72388a0aa23da8bc8e24a0cbe9d523c5a9ce294 diff --git a/carlfw/usb/usb.c b/carlfw/usb/usb.c index 49852fb..aedf30d 100644 --- a/carlfw/usb/usb.c +++ b/carlfw/usb/usb.c @@ -6,7 +6,7 @@ * Copyright (c) 2000-2005 ZyDAS Technology Corporation * Copyright (c) 2007-2009 Atheros Communications, Inc. * Copyright 2009 Johannes Berg - * Copyright 2009 Christian Lamparter + * Copyright 2009-2011 Christian Lamparter * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * with this program; If not, see . */ #include "carl9170.h" #include "usb.h" @@ -40,7 +39,11 @@ static struct ar9170_usb_config usb_config_highspeed = { .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE, + .bmAttributes = USB_CONFIG_ATT_ONE | +#ifdef CONFIG_CARL9170FW_WOL + USB_CONFIG_ATT_WAKEUP | +#endif /* CONFIG_CARL9170FW_WOL */ + 0, .bMaxPower = 0xfa, /* 500 mA */ }, @@ -103,7 +106,11 @@ static struct ar9170_usb_config usb_config_fullspeed = { .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE, + .bmAttributes = USB_CONFIG_ATT_ONE | +#ifdef CONFIG_CARL9170FW_WOL + USB_CONFIG_ATT_WAKEUP | +#endif /* CONFIG_CARL9170FW_WOL */ + 0, .bMaxPower = 0xfa, /* 500 mA */ }, @@ -151,15 +158,14 @@ static struct ar9170_usb_config usb_config_fullspeed = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT | AR9170_USB_EP_CMD, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(64), .bInterval = 1, }, }, }; -#ifdef CONFIG_CARL9170FW_USB_MODESWITCH -static void usb_reset_eps(void) +void usb_reset_eps(void) { unsigned int i; @@ -167,6 +173,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); } /* @@ -176,14 +183,13 @@ 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 */ - -#ifdef CONFIG_CARL9170FW_USB_INIT_FIRMWARE static void usb_pta_init(void) { + unsigned int usb_dma_ctrl = 0; /* Set PTA mode to USB */ andl(AR9170_PTA_REG_DMA_MODE_CTRL, ~AR9170_PTA_DMA_MODE_CTRL_DISABLE_USB); @@ -197,44 +203,34 @@ static void usb_pta_init(void) fw.usb.cfg_desc = &usb_config_highspeed; /* 512 Byte DMA transfers */ - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_HIGH_SPEED); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_HIGH_SPEED; } else { fw.usb.cfg_desc = &usb_config_fullspeed; fw.usb.os_cfg_desc = &usb_config_highspeed; } #ifdef CONFIG_CARL9170FW_USB_UP_STREAM - /* Enable upload stream mode */ - andl(AR9170_USB_REG_DMA_CTL, ~AR9170_DMA_CTL_UP_PACKET_MODE); - - /* reset maximum transfer size */ - andl(AR9170_USB_REG_DMA_CTL, ~(AR9170_DMA_CTL_UP_STREAM_MASK)); - # if (CONFIG_CARL9170FW_RX_FRAME_LEN == 4096) - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_UP_STREAM_4K); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_UP_STREAM_4K; # elif (CONFIG_CARL9170FW_RX_FRAME_LEN == 8192) - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_UP_STREAM_8K); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_UP_STREAM_8K; # elif (CONFIG_CARL9170FW_RX_FRAME_LEN == 16384) - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_UP_STREAM_16K); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_UP_STREAM_16K; # elif (CONFIG_CARL9170FW_RX_FRAME_LEN == 32768) - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_UP_STREAM_32K); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_UP_STREAM_32K; # else # error "Invalid AR9170_RX_FRAME_LEN setting" # endif #else /* CONFIG_CARL9170FW_USB_UP_STREAM */ - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_UP_PACKET_MODE); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_UP_PACKET_MODE; #endif /* CONFIG_CARL9170FW_USB_UP_STREAM */ #ifdef CONFIG_CARL9170FW_USB_DOWN_STREAM /* Enable down stream mode */ - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_DOWN_STREAM); + usb_dma_ctrl |= AR9170_USB_DMA_CTL_DOWN_STREAM; #endif /* CONFIG_CARL9170FW_USB_DOWN_STREAM */ - /* Enable up stream and down stream */ - orl(AR9170_USB_REG_DMA_CTL, AR9170_DMA_CTL_ENABLE_TO_DEVICE | - AR9170_DMA_CTL_ENABLE_FROM_DEVICE); - #ifdef CONFIG_CARL9170FW_USB_UP_STREAM /* Set the up stream mode maximum aggregate number */ set(AR9170_USB_REG_MAX_AGG_UPLOAD, 4); @@ -246,14 +242,16 @@ static void usb_pta_init(void) set(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); #endif /* CONFIG_CARL9170FW_USB_UP_STREAM */ + /* Enable up stream and down stream */ + usb_dma_ctrl |= AR9170_USB_DMA_CTL_ENABLE_TO_DEVICE | + AR9170_USB_DMA_CTL_ENABLE_FROM_DEVICE; + + set(AR9170_USB_REG_DMA_CTL, usb_dma_ctrl); } -#endif /* CONFIG_CARL9170FW_USB_INIT_FIRMWARE */ void usb_init(void) { -#ifdef CONFIG_CARL9170FW_USB_INIT_FIRMWARE usb_pta_init(); -#endif /* CONFIG_CARL9170FW_USB_INIT_FIRMWARE */ fw.usb.config = 1; /* @@ -262,7 +260,13 @@ void usb_init(void) * * fw.usb.interface_setting = 0; * fw.usb.alternate_interface_setting = 0; + * fw.usb.device_feature = 0; */ + +#ifdef CONFIG_CARL9170FW_WOL + fw.usb.device_feature |= USB_DEVICE_REMOTE_WAKEUP; + usb_enable_remote_wakeup(); +#endif /* CONFIG_CARL9170FW_WOL */ } #define GET_ARRAY(a, o) ((uint32_t *) (((unsigned long) data) + offset)) @@ -315,7 +319,7 @@ static int usb_ep0tx_data(const void *data, const unsigned int len) #ifdef CONFIG_CARL9170FW_USB_STANDARD_CMDS static int usb_get_status(const struct usb_ctrlrequest *ctrl) { - __le16 status = cpu_to_le16(0); + __le16 status = cpu_to_le16(fw.usb.device_feature); if ((ctrl->bRequestType & USB_DIR_MASK) != USB_DIR_IN) return -1; @@ -331,7 +335,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; @@ -472,7 +499,7 @@ static int usb_get_configuration(const struct usb_ctrlrequest *ctrl) if (USB_CHECK_REQTYPE(ctrl, USB_RECIP_DEVICE, USB_DIR_IN)) return -1; - return usb_ep0tx_data(&fw.usb.config, 1); + return usb_ep0tx_data(&fw.usb.config, fw.usb.config); } static int usb_set_configuration(const struct usb_ctrlrequest *ctrl) @@ -488,10 +515,11 @@ static int usb_set_configuration(const struct usb_ctrlrequest *ctrl) /* Disable Device */ andb(AR9170_USB_REG_DEVICE_ADDRESS, (uint8_t) ~(AR9170_USB_DEVICE_ADDRESS_CONFIGURE)); -#ifdef CONFIG_CARL9170FW_USB_MODESWITCH + /* fall through */ case 1: fw.usb.config = config; +#ifdef CONFIG_CARL9170FW_USB_MODESWITCH if (usb_detect_highspeed()) { /* High Speed Configuration */ usb_init_highspeed_fifo_cfg(); @@ -499,25 +527,20 @@ static int usb_set_configuration(const struct usb_ctrlrequest *ctrl) /* Full Speed Configuration */ usb_init_fullspeed_fifo_cfg(); } - break; + /* usb_pta_init() ? */ +#endif /* CONFIG_CARL9170FW_USB_MODESWITCH */ - default: - return -1; - } - /* usb_pta_init() ? */ + usb_reset_eps(); + orb(AR9170_USB_REG_DEVICE_ADDRESS, + (AR9170_USB_DEVICE_ADDRESS_CONFIGURE)); - usb_reset_eps(); - orb(AR9170_USB_REG_DEVICE_ADDRESS, - (AR9170_USB_DEVICE_ADDRESS_CONFIGURE)); + usb_enable_global_int(); + usb_trigger_out(); + return 1; - usb_enable_global_int(); - usb_trigger_out(); - return 1; -#else default: return -1; } -#endif /* CONFIG_CARL9170FW_USB_MODESWITCH */ } static int usb_set_address(const struct usb_ctrlrequest *ctrl) @@ -562,6 +585,77 @@ static int usb_get_interface(const struct usb_ctrlrequest *ctrl) return usb_ep0tx_data(&fw.usb.alternate_interface_setting, 1); } +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; +} + #ifdef CONFIG_CARL9170FW_USB_MODESWITCH static int usb_set_interface(const struct usb_ctrlrequest *ctrl) { @@ -610,9 +704,8 @@ static int usb_standard_command(const struct usb_ctrlrequest *ctrl __unused) break; case USB_REQ_CLEAR_FEATURE: - break; - case USB_REQ_SET_FEATURE: + status = usb_manipulate_feature(ctrl, ctrl->bRequest == USB_REQ_CLEAR_FEATURE); break; case USB_REQ_SET_ADDRESS: @@ -700,8 +793,10 @@ void usb_ep0setup(void) if (status < 0) fw.usb.ep0_action |= CARL9170_EP0_STALL; +#ifdef CONFIG_CARL9170FW_USB_STANDARD_CMDS if (status > 0) fw.usb.ep0_action |= CARL9170_EP0_TRIGGER; +#endif /* CONFIG_CARL9170FW_USB_STANDARD_CMDS */ } void usb_ep0rx(void)