提交 f549953c 编写于 作者: L Linus Torvalds

Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (115 commits)
  EHCI: fix direction handling for interrupt data toggles
  USB: serial: add IDs for WinChipHead USB->RS232 adapter
  USB: OHCI: fix another regression for NVIDIA controllers
  usb: gadget: m66592-udc: add pullup function
  usb: gadget: m66592-udc: add function for external controller
  usb: gadget: r8a66597-udc: add pullup function
  usb: renesas_usbhs: support multi driver
  usb: renesas_usbhs: inaccessible pipe is not an error
  usb: renesas_usbhs: care buff alignment when dma handler
  USB: PL2303: correctly handle baudrates above 115200
  usb: r8a66597-hcd: fixup USB_PORT_STAT_C_SUSPEND shift
  usb: renesas_usbhs: compile/config are rescued
  usb: renesas_usbhs: fixup comment-out
  usb: update email address in ohci-sh and r8a66597-hcd
  usb: r8a66597-hcd: add function for external controller
  EHCI: only power off port if over-current is active
  USB: mon: Allow to use usbmon without debugfs
  USB: EHCI: go back to using the system clock for QH unlinks
  ehci: add pci quirk for Ordissimo and RM Slate 100 too
  ehci: refactor pci quirk to use standard dmi_check_system method
  ...

Fix up trivial conflicts in Documentation/feature-removal-schedule.txt
...@@ -10,3 +10,26 @@ KernelVersion: 2.6.35 ...@@ -10,3 +10,26 @@ KernelVersion: 2.6.35
Contact: masa-korg@dsn.okisemi.com Contact: masa-korg@dsn.okisemi.com
Description: Write/read Option ROM data. Description: Write/read Option ROM data.
What: /sys/module/ehci_hcd/drivers/.../uframe_periodic_max
Date: July 2011
KernelVersion: 3.1
Contact: Kirill Smelkov <kirr@mns.spb.ru>
Description: Maximum time allowed for periodic transfers per microframe (μs)
[ USB 2.0 sets maximum allowed time for periodic transfers per
microframe to be 80%, that is 100 microseconds out of 125
microseconds (full microframe).
However there are cases, when 80% max isochronous bandwidth is
too limiting. For example two video streams could require 110
microseconds of isochronous bandwidth per microframe to work
together. ]
Through this setting it is possible to raise the limit so that
the host controller would allow allocating more than 100
microseconds of periodic bandwidth per microframe.
Beware, non-standard modes are usually not thoroughly tested by
hardware designers, and the hardware can malfunction when this
setting differ from default 100.
...@@ -569,3 +569,10 @@ Why: Just opening a V4L device should not change the state of the hardware ...@@ -569,3 +569,10 @@ Why: Just opening a V4L device should not change the state of the hardware
Who: Hans Verkuil <hans.verkuil@cisco.com> Who: Hans Verkuil <hans.verkuil@cisco.com>
---------------------------- ----------------------------
What: g_file_storage driver
When: 3.8
Why: This driver has been superseded by g_mass_storage.
Who: Alan Stern <stern@rowland.harvard.edu>
----------------------------
...@@ -2545,6 +2545,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -2545,6 +2545,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
unknown_nmi_panic unknown_nmi_panic
[X86] Cause panic on unknown NMI. [X86] Cause panic on unknown NMI.
usbcore.authorized_default=
[USB] Default USB device authorization:
(default -1 = authorized except for wireless USB,
0 = not authorized, 1 = authorized)
usbcore.autosuspend= usbcore.autosuspend=
[USB] The autosuspend time delay (in seconds) used [USB] The autosuspend time delay (in seconds) used
for newly-detected USB devices (default 2). This for newly-detected USB devices (default 2). This
......
...@@ -210,3 +210,5 @@ TBD: Interrupt and ISO transfer performance issues. Those periodic ...@@ -210,3 +210,5 @@ TBD: Interrupt and ISO transfer performance issues. Those periodic
transfers are fully scheduled, so the main issue is likely to be how transfers are fully scheduled, so the main issue is likely to be how
to trigger "high bandwidth" modes. to trigger "high bandwidth" modes.
TBD: More than standard 80% periodic bandwidth allocation is possible
through sysfs uframe_periodic_max parameter. Describe that.
...@@ -97,7 +97,7 @@ Send and receive HID reports ...@@ -97,7 +97,7 @@ Send and receive HID reports
HID gadget. HID gadget.
Another interesting example is the caps lock test. Type Another interesting example is the caps lock test. Type
-caps-lock and hit return. A report is then sent by the --caps-lock and hit return. A report is then sent by the
gadget and you should receive the host answer, corresponding gadget and you should receive the host answer, corresponding
to the caps lock LED status. to the caps lock LED status.
......
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
#include <plat/omap_device.h> #include <plat/omap_device.h>
#include "mux.h" #include "mux.h"
#if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
static struct musb_hdrc_config musb_config = { static struct musb_hdrc_config musb_config = {
.multipoint = 1, .multipoint = 1,
.dyn_fifo = 1, .dyn_fifo = 1,
...@@ -175,11 +173,3 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) ...@@ -175,11 +173,3 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
if (cpu_is_omap44xx()) if (cpu_is_omap44xx())
omap4430_phy_init(dev); omap4430_phy_init(dev);
} }
#else
void __init usb_musb_init(struct omap_musb_board_data *board_data)
{
if (cpu_is_omap44xx())
omap4430_phy_init(NULL);
}
#endif /* CONFIG_USB_MUSB_SOC */
...@@ -116,14 +116,14 @@ struct uea_cmvs_v1 { ...@@ -116,14 +116,14 @@ struct uea_cmvs_v1 {
u32 address; u32 address;
u16 offset; u16 offset;
u32 data; u32 data;
} __attribute__ ((packed)); } __packed;
struct uea_cmvs_v2 { struct uea_cmvs_v2 {
u32 group; u32 group;
u32 address; u32 address;
u32 offset; u32 offset;
u32 data; u32 data;
} __attribute__ ((packed)); } __packed;
/* information about currently processed cmv */ /* information about currently processed cmv */
struct cmv_dsc_e1 { struct cmv_dsc_e1 {
...@@ -352,7 +352,7 @@ struct block_index { ...@@ -352,7 +352,7 @@ struct block_index {
__le32 PageAddress; __le32 PageAddress;
__le16 dummy1; __le16 dummy1;
__le16 PageNumber; __le16 PageNumber;
} __attribute__ ((packed)); } __packed;
#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) #define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) #define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
...@@ -367,7 +367,7 @@ struct l1_code { ...@@ -367,7 +367,7 @@ struct l1_code {
u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
u8 code[0]; u8 code[0];
} __attribute__ ((packed)); } __packed;
/* structures describing a block within a DSP page */ /* structures describing a block within a DSP page */
struct block_info_e1 { struct block_info_e1 {
...@@ -377,7 +377,7 @@ struct block_info_e1 { ...@@ -377,7 +377,7 @@ struct block_info_e1 {
__le16 wOvlOffset; __le16 wOvlOffset;
__le16 wOvl; /* overlay */ __le16 wOvl; /* overlay */
__le16 wLast; __le16 wLast;
} __attribute__ ((packed)); } __packed;
#define E1_BLOCK_INFO_SIZE 12 #define E1_BLOCK_INFO_SIZE 12
struct block_info_e4 { struct block_info_e4 {
...@@ -387,7 +387,7 @@ struct block_info_e4 { ...@@ -387,7 +387,7 @@ struct block_info_e4 {
__be32 dwSize; __be32 dwSize;
__be32 dwAddress; __be32 dwAddress;
__be16 wReserved; __be16 wReserved;
} __attribute__ ((packed)); } __packed;
#define E4_BLOCK_INFO_SIZE 14 #define E4_BLOCK_INFO_SIZE 14
#define UEA_BIHDR 0xabcd #define UEA_BIHDR 0xabcd
...@@ -467,7 +467,7 @@ struct cmv_e1 { ...@@ -467,7 +467,7 @@ struct cmv_e1 {
__le32 dwSymbolicAddress; __le32 dwSymbolicAddress;
__le16 wOffsetAddress; __le16 wOffsetAddress;
__le32 dwData; __le32 dwData;
} __attribute__ ((packed)); } __packed;
struct cmv_e4 { struct cmv_e4 {
__be16 wGroup; __be16 wGroup;
...@@ -475,17 +475,17 @@ struct cmv_e4 { ...@@ -475,17 +475,17 @@ struct cmv_e4 {
__be16 wOffset; __be16 wOffset;
__be16 wAddress; __be16 wAddress;
__be32 dwData[6]; __be32 dwData[6];
} __attribute__ ((packed)); } __packed;
/* structures representing swap information */ /* structures representing swap information */
struct swap_info_e1 { struct swap_info_e1 {
__u8 bSwapPageNo; __u8 bSwapPageNo;
__u8 bOvl; /* overlay */ __u8 bOvl; /* overlay */
} __attribute__ ((packed)); } __packed;
struct swap_info_e4 { struct swap_info_e4 {
__u8 bSwapPageNo; __u8 bSwapPageNo;
} __attribute__ ((packed)); } __packed;
/* structures representing interrupt data */ /* structures representing interrupt data */
#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo #define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
...@@ -499,23 +499,23 @@ union intr_data_e1 { ...@@ -499,23 +499,23 @@ union intr_data_e1 {
struct { struct {
struct swap_info_e1 swapinfo; struct swap_info_e1 swapinfo;
__le16 wDataSize; __le16 wDataSize;
} __attribute__ ((packed)) s1; } __packed s1;
struct { struct {
struct cmv_e1 cmv; struct cmv_e1 cmv;
__le16 wDataSize; __le16 wDataSize;
} __attribute__ ((packed)) s2; } __packed s2;
} __attribute__ ((packed)); } __packed;
union intr_data_e4 { union intr_data_e4 {
struct { struct {
struct swap_info_e4 swapinfo; struct swap_info_e4 swapinfo;
__le16 wDataSize; __le16 wDataSize;
} __attribute__ ((packed)) s1; } __packed s1;
struct { struct {
struct cmv_e4 cmv; struct cmv_e4 cmv;
__le16 wDataSize; __le16 wDataSize;
} __attribute__ ((packed)) s2; } __packed s2;
} __attribute__ ((packed)); } __packed;
struct intr_pkt { struct intr_pkt {
__u8 bType; __u8 bType;
...@@ -528,15 +528,15 @@ struct intr_pkt { ...@@ -528,15 +528,15 @@ struct intr_pkt {
union intr_data_e1 e1; union intr_data_e1 e1;
union intr_data_e4 e4; union intr_data_e4 e4;
} u; } u;
} __attribute__ ((packed)); } __packed;
#define E1_INTR_PKT_SIZE 28 #define E1_INTR_PKT_SIZE 28
#define E4_INTR_PKT_SIZE 64 #define E4_INTR_PKT_SIZE 64
static struct usb_driver uea_driver; static struct usb_driver uea_driver;
static DEFINE_MUTEX(uea_mutex); static DEFINE_MUTEX(uea_mutex);
static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", static const char * const chip_name[] = {
"Eagle IV"}; "ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
static int modem_index; static int modem_index;
static unsigned int debug; static unsigned int debug;
......
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/ratelimit.h>
#ifdef VERBOSE_DEBUG #ifdef VERBOSE_DEBUG
static int usbatm_print_packet(const unsigned char *data, int len); static int usbatm_print_packet(const unsigned char *data, int len);
...@@ -668,8 +669,7 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -668,8 +669,7 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
/* racy disconnection check - fine */ /* racy disconnection check - fine */
if (!instance || instance->disconnected) { if (!instance || instance->disconnected) {
#ifdef DEBUG #ifdef DEBUG
if (printk_ratelimit()) printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
#endif #endif
err = -ENODEV; err = -ENODEV;
goto fail; goto fail;
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#undef DEBUG #undef DEBUG
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/ratelimit.h>
/* /*
* Version Information * Version Information
...@@ -348,8 +349,7 @@ static int usblp_check_status(struct usblp *usblp, int err) ...@@ -348,8 +349,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
mutex_lock(&usblp->mut); mutex_lock(&usblp->mut);
if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
mutex_unlock(&usblp->mut); mutex_unlock(&usblp->mut);
if (printk_ratelimit()) printk_ratelimited(KERN_ERR
printk(KERN_ERR
"usblp%d: error %d reading printer status\n", "usblp%d: error %d reading printer status\n",
usblp->minor, error); usblp->minor, error);
return 0; return 0;
...@@ -653,8 +653,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -653,8 +653,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case LPGETSTATUS: case LPGETSTATUS:
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) { if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
if (printk_ratelimit()) printk_ratelimited(KERN_ERR "usblp%d:"
printk(KERN_ERR "usblp%d:"
"failed reading printer status (%d)\n", "failed reading printer status (%d)\n",
usblp->minor, retval); usblp->minor, retval);
retval = -EIO; retval = -EIO;
......
...@@ -337,6 +337,17 @@ static const u8 ss_rh_config_descriptor[] = { ...@@ -337,6 +337,17 @@ static const u8 ss_rh_config_descriptor[] = {
0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */ 0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
}; };
/* authorized_default behaviour:
* -1 is authorized for all devices except wireless (old behaviour)
* 0 is unauthorized for all devices
* 1 is authorized for all devices
*/
static int authorized_default = -1;
module_param(authorized_default, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(authorized_default,
"Default USB device authorization: 0 is not authorized, 1 is "
"authorized, -1 is authorized except for wireless USB (default, "
"old behaviour");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/** /**
...@@ -2371,7 +2382,11 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -2371,7 +2382,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc); dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
/* Keep old behaviour if authorized_default is not in [0, 1]. */
if (authorized_default < 0 || authorized_default > 1)
hcd->authorized_default = hcd->wireless? 0 : 1; hcd->authorized_default = hcd->wireless? 0 : 1;
else
hcd->authorized_default = authorized_default;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* HC is in reset state, but accessible. Now do the one-time init, /* HC is in reset state, but accessible. Now do the one-time init,
......
...@@ -96,9 +96,6 @@ config USB_GADGET_VBUS_DRAW ...@@ -96,9 +96,6 @@ config USB_GADGET_VBUS_DRAW
This value will be used except for system-specific gadget This value will be used except for system-specific gadget
drivers that have more specific information. drivers that have more specific information.
config USB_GADGET_SELECTED
boolean
# #
# USB Peripheral Controller Support # USB Peripheral Controller Support
# #
...@@ -122,10 +119,9 @@ choice ...@@ -122,10 +119,9 @@ choice
# Integrated controllers # Integrated controllers
# #
config USB_GADGET_AT91 config USB_AT91
boolean "Atmel AT91 USB Device Port" tristate "Atmel AT91 USB Device Port"
depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45 depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
select USB_GADGET_SELECTED
help help
Many Atmel AT91 processors (such as the AT91RM2000) have a Many Atmel AT91 processors (such as the AT91RM2000) have a
full speed USB Device Port with support for five configurable full speed USB Device Port with support for five configurable
...@@ -135,27 +131,16 @@ config USB_GADGET_AT91 ...@@ -135,27 +131,16 @@ config USB_GADGET_AT91
dynamically linked module called "at91_udc" and force all dynamically linked module called "at91_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_AT91 config USB_ATMEL_USBA
tristate tristate "Atmel USBA"
depends on USB_GADGET_AT91
default USB_GADGET
config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA"
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help help
USBA is the integrated high-speed USB Device controller on USBA is the integrated high-speed USB Device controller on
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
config USB_ATMEL_USBA config USB_FSL_USB2
tristate tristate "Freescale Highspeed USB DR Peripheral Controller"
depends on USB_GADGET_ATMEL_USBA
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC depends on FSL_SOC || ARCH_MXC
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
select USB_FSL_MPH_DR_OF if OF select USB_FSL_MPH_DR_OF if OF
...@@ -170,26 +155,15 @@ config USB_GADGET_FSL_USB2 ...@@ -170,26 +155,15 @@ config USB_GADGET_FSL_USB2
dynamically linked module called "fsl_usb2_udc" and force dynamically linked module called "fsl_usb2_udc" and force
all gadget drivers to also be dynamically linked. all gadget drivers to also be dynamically linked.
config USB_FSL_USB2 config USB_FUSB300
tristate tristate "Faraday FUSB300 USB Peripheral Controller"
depends on USB_GADGET_FSL_USB2 depends on !PHYS_ADDR_T_64BIT
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_FUSB300
boolean "Faraday FUSB300 USB Peripheral Controller"
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
Faraday usb device controller FUSB300 driver Faraday usb device controller FUSB300 driver
config USB_FUSB300 config USB_OMAP
tristate tristate "OMAP USB Device Controller"
depends on USB_GADGET_FUSB300
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP depends on ARCH_OMAP
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
select USB_OTG_UTILS if ARCH_OMAP select USB_OTG_UTILS if ARCH_OMAP
...@@ -204,14 +178,8 @@ config USB_GADGET_OMAP ...@@ -204,14 +178,8 @@ config USB_GADGET_OMAP
dynamically linked module called "omap_udc" and force all dynamically linked module called "omap_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_OMAP config USB_PXA25X
tristate tristate "PXA 25x or IXP 4xx"
depends on USB_GADGET_OMAP
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_PXA25X
boolean "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
select USB_OTG_UTILS select USB_OTG_UTILS
help help
...@@ -226,24 +194,18 @@ config USB_GADGET_PXA25X ...@@ -226,24 +194,18 @@ config USB_GADGET_PXA25X
dynamically linked module called "pxa25x_udc" and force all dynamically linked module called "pxa25x_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_PXA25X
tristate
depends on USB_GADGET_PXA25X
default USB_GADGET
select USB_GADGET_SELECTED
# if there's only one gadget driver, using only two bulk endpoints, # if there's only one gadget driver, using only two bulk endpoints,
# don't waste memory for the other endpoints # don't waste memory for the other endpoints
config USB_PXA25X_SMALL config USB_PXA25X_SMALL
depends on USB_GADGET_PXA25X depends on USB_PXA25X
bool bool
default n if USB_ETH_RNDIS default n if USB_ETH_RNDIS
default y if USB_ZERO default y if USB_ZERO
default y if USB_ETH default y if USB_ETH
default y if USB_G_SERIAL default y if USB_G_SERIAL
config USB_GADGET_R8A66597 config USB_R8A66597
boolean "Renesas R8A66597 USB Peripheral Controller" tristate "Renesas R8A66597 USB Peripheral Controller"
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
R8A66597 is a discrete USB host and peripheral controller chip that R8A66597 is a discrete USB host and peripheral controller chip that
...@@ -254,32 +216,22 @@ config USB_GADGET_R8A66597 ...@@ -254,32 +216,22 @@ config USB_GADGET_R8A66597
dynamically linked module called "r8a66597_udc" and force all dynamically linked module called "r8a66597_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_R8A66597 config USB_RENESAS_USBHS_UDC
tristate tristate 'Renesas USBHS controller'
depends on USB_GADGET_R8A66597 depends on SUPERH || ARCH_SHMOBILE
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_RENESAS_USBHS
boolean "Renesas USBHS"
depends on USB_RENESAS_USBHS depends on USB_RENESAS_USBHS
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
Renesas USBHS is a discrete USB host and peripheral controller Renesas USBHS is a discrete USB host and peripheral controller chip
chip that supports both full and high speed USB 2.0 data transfers. that supports both full and high speed USB 2.0 data transfers.
platform is able to configure endpoint (pipe) style It has nine or more configurable endpoints, and endpoint zero.
Say "y" to enable the gadget specific portion of the USBHS driver.
config USB_RENESAS_USBHS_UDC Say "y" to link the driver statically, or "m" to build a
tristate dynamically linked module called "renesas_usbhs" and force all
depends on USB_GADGET_RENESAS_USBHS gadget drivers to also be dynamically linked.
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_PXA27X config USB_PXA27X
boolean "PXA 27x" tristate "PXA 27x"
depends on ARCH_PXA && (PXA27x || PXA3xx) depends on ARCH_PXA && (PXA27x || PXA3xx)
select USB_OTG_UTILS select USB_OTG_UTILS
help help
...@@ -293,14 +245,8 @@ config USB_GADGET_PXA27X ...@@ -293,14 +245,8 @@ config USB_GADGET_PXA27X
dynamically linked module called "pxa27x_udc" and force all dynamically linked module called "pxa27x_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_PXA27X config USB_S3C_HSOTG
tristate tristate "S3C HS/OtG USB Device controller"
depends on USB_GADGET_PXA27X
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_S3C_HSOTG
boolean "S3C HS/OtG USB Device controller"
depends on S3C_DEV_USB_HSOTG depends on S3C_DEV_USB_HSOTG
select USB_GADGET_S3C_HSOTG_PIO select USB_GADGET_S3C_HSOTG_PIO
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
...@@ -308,14 +254,8 @@ config USB_GADGET_S3C_HSOTG ...@@ -308,14 +254,8 @@ config USB_GADGET_S3C_HSOTG
The Samsung S3C64XX USB2.0 high-speed gadget controller The Samsung S3C64XX USB2.0 high-speed gadget controller
integrated into the S3C64XX series SoC. integrated into the S3C64XX series SoC.
config USB_S3C_HSOTG config USB_IMX
tristate tristate "Freescale IMX USB Peripheral Controller"
depends on USB_GADGET_S3C_HSOTG
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_IMX
boolean "Freescale IMX USB Peripheral Controller"
depends on ARCH_MX1 depends on ARCH_MX1
help help
Freescale's IMX series include an integrated full speed Freescale's IMX series include an integrated full speed
...@@ -329,14 +269,8 @@ config USB_GADGET_IMX ...@@ -329,14 +269,8 @@ config USB_GADGET_IMX
dynamically linked module called "imx_udc" and force all dynamically linked module called "imx_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_IMX config USB_S3C2410
tristate tristate "S3C2410 USB Device Controller"
depends on USB_GADGET_IMX
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_S3C2410
boolean "S3C2410 USB Device Controller"
depends on ARCH_S3C2410 depends on ARCH_S3C2410
help help
Samsung's S3C2410 is an ARM-4 processor with an integrated Samsung's S3C2410 is an ARM-4 processor with an integrated
...@@ -346,18 +280,12 @@ config USB_GADGET_S3C2410 ...@@ -346,18 +280,12 @@ config USB_GADGET_S3C2410
This driver has been tested on the S3C2410, S3C2412, and This driver has been tested on the S3C2410, S3C2412, and
S3C2440 processors. S3C2440 processors.
config USB_S3C2410
tristate
depends on USB_GADGET_S3C2410
default USB_GADGET
select USB_GADGET_SELECTED
config USB_S3C2410_DEBUG config USB_S3C2410_DEBUG
boolean "S3C2410 udc debug messages" boolean "S3C2410 udc debug messages"
depends on USB_GADGET_S3C2410 depends on USB_S3C2410
config USB_GADGET_S3C_HSUDC config USB_S3C_HSUDC
boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller" tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
depends on ARCH_S3C2410 depends on ARCH_S3C2410
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
...@@ -367,41 +295,29 @@ config USB_GADGET_S3C_HSUDC ...@@ -367,41 +295,29 @@ config USB_GADGET_S3C_HSUDC
This driver has been tested on S3C2416 and S3C2450 processors. This driver has been tested on S3C2416 and S3C2450 processors.
config USB_S3C_HSUDC config USB_PXA_U2O
tristate tristate "PXA9xx Processor USB2.0 controller"
depends on USB_GADGET_S3C_HSUDC depends on ARCH_MMP
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_PXA_U2O
boolean "PXA9xx Processor USB2.0 controller"
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
PXA9xx Processor series include a high speed USB2.0 device PXA9xx Processor series include a high speed USB2.0 device
controller, which support high speed and full speed USB peripheral. controller, which support high speed and full speed USB peripheral.
config USB_PXA_U2O
tristate
depends on USB_GADGET_PXA_U2O
default USB_GADGET
select USB_GADGET_SELECTED
# #
# Controllers available in both integrated and discrete versions # Controllers available in both integrated and discrete versions
# #
# musb builds in ../musb along with host support # musb builds in ../musb along with host support
config USB_GADGET_MUSB_HDRC config USB_GADGET_MUSB_HDRC
boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)" tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG) depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
select USB_GADGET_SELECTED
help help
This OTG-capable silicon IP is used in dual designs including This OTG-capable silicon IP is used in dual designs including
the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
config USB_GADGET_M66592 config USB_M66592
boolean "Renesas M66592 USB Peripheral Controller" tristate "Renesas M66592 USB Peripheral Controller"
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
M66592 is a discrete USB peripheral controller chip that M66592 is a discrete USB peripheral controller chip that
...@@ -412,18 +328,12 @@ config USB_GADGET_M66592 ...@@ -412,18 +328,12 @@ config USB_GADGET_M66592
dynamically linked module called "m66592_udc" and force all dynamically linked module called "m66592_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_M66592
tristate
depends on USB_GADGET_M66592
default USB_GADGET
select USB_GADGET_SELECTED
# #
# Controllers available only in discrete form (and all PCI controllers) # Controllers available only in discrete form (and all PCI controllers)
# #
config USB_GADGET_AMD5536UDC config USB_AMD5536UDC
boolean "AMD5536 UDC" tristate "AMD5536 UDC"
depends on PCI depends on PCI
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
...@@ -437,14 +347,8 @@ config USB_GADGET_AMD5536UDC ...@@ -437,14 +347,8 @@ config USB_GADGET_AMD5536UDC
dynamically linked module called "amd5536udc" and force all dynamically linked module called "amd5536udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_AMD5536UDC config USB_FSL_QE
tristate tristate "Freescale QE/CPM USB Device Controller"
depends on USB_GADGET_AMD5536UDC
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_FSL_QE
boolean "Freescale QE/CPM USB Device Controller"
depends on FSL_SOC && (QUICC_ENGINE || CPM) depends on FSL_SOC && (QUICC_ENGINE || CPM)
help help
Some of Freescale PowerPC processors have a Full Speed Some of Freescale PowerPC processors have a Full Speed
...@@ -456,14 +360,8 @@ config USB_GADGET_FSL_QE ...@@ -456,14 +360,8 @@ config USB_GADGET_FSL_QE
Set CONFIG_USB_GADGET to "m" to build this driver as a Set CONFIG_USB_GADGET to "m" to build this driver as a
dynamically linked module called "fsl_qe_udc". dynamically linked module called "fsl_qe_udc".
config USB_FSL_QE config USB_CI13XXX_PCI
tristate tristate "MIPS USB CI13xxx PCI UDC"
depends on USB_GADGET_FSL_QE
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_CI13XXX_PCI
boolean "MIPS USB CI13xxx PCI UDC"
depends on PCI depends on PCI
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
...@@ -474,14 +372,31 @@ config USB_GADGET_CI13XXX_PCI ...@@ -474,14 +372,31 @@ config USB_GADGET_CI13XXX_PCI
dynamically linked module called "ci13xxx_udc" and force all dynamically linked module called "ci13xxx_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_CI13XXX_PCI config USB_NET2272
tristate tristate "PLX NET2272"
depends on USB_GADGET_CI13XXX_PCI select USB_GADGET_DUALSPEED
default USB_GADGET help
select USB_GADGET_SELECTED PLX NET2272 is a USB peripheral controller which supports
both full and high speed USB 2.0 data transfers.
config USB_GADGET_NET2280 It has three configurable endpoints, as well as endpoint zero
boolean "NetChip 228x" (for control transfer).
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "net2272" and force all
gadget drivers to also be dynamically linked.
config USB_NET2272_DMA
boolean "Support external DMA controller"
depends on USB_NET2272
help
The NET2272 part can optionally support an external DMA
controller, but your board has to have support in the
driver itself.
If unsure, say "N" here. The driver works fine in PIO mode.
config USB_NET2280
tristate "NetChip 228x"
depends on PCI depends on PCI
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
...@@ -496,14 +411,8 @@ config USB_GADGET_NET2280 ...@@ -496,14 +411,8 @@ config USB_GADGET_NET2280
dynamically linked module called "net2280" and force all dynamically linked module called "net2280" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_NET2280 config USB_GOKU
tristate tristate "Toshiba TC86C001 'Goku-S'"
depends on USB_GADGET_NET2280
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI depends on PCI
help help
The Toshiba TC86C001 is a PCI device which includes controllers The Toshiba TC86C001 is a PCI device which includes controllers
...@@ -516,15 +425,10 @@ config USB_GADGET_GOKU ...@@ -516,15 +425,10 @@ config USB_GADGET_GOKU
dynamically linked module called "goku_udc" and to force all dynamically linked module called "goku_udc" and to force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_GOKU config USB_LANGWELL
tristate tristate "Intel Langwell USB Device Controller"
depends on USB_GADGET_GOKU
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_LANGWELL
boolean "Intel Langwell USB Device Controller"
depends on PCI depends on PCI
depends on !PHYS_ADDR_T_64BIT
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
Intel Langwell USB Device Controller is a High-Speed USB Intel Langwell USB Device Controller is a High-Speed USB
...@@ -537,14 +441,8 @@ config USB_GADGET_LANGWELL ...@@ -537,14 +441,8 @@ config USB_GADGET_LANGWELL
dynamically linked module called "langwell_udc" and force all dynamically linked module called "langwell_udc" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_LANGWELL config USB_EG20T
tristate tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
depends on USB_GADGET_LANGWELL
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_EG20T
boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
depends on PCI depends on PCI
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
...@@ -565,14 +463,8 @@ config USB_GADGET_EG20T ...@@ -565,14 +463,8 @@ config USB_GADGET_EG20T
ML7213 is companion chip for Intel Atom E6xx series. ML7213 is companion chip for Intel Atom E6xx series.
ML7213 is completely compatible for Intel EG20T PCH. ML7213 is completely compatible for Intel EG20T PCH.
config USB_EG20T config USB_CI13XXX_MSM
tristate tristate "MIPS USB CI13xxx for MSM"
depends on USB_GADGET_EG20T
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_CI13XXX_MSM
boolean "MIPS USB CI13xxx for MSM"
depends on ARCH_MSM depends on ARCH_MSM
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
select USB_MSM_OTG select USB_MSM_OTG
...@@ -588,20 +480,15 @@ config USB_GADGET_CI13XXX_MSM ...@@ -588,20 +480,15 @@ config USB_GADGET_CI13XXX_MSM
dynamically linked module called "ci13xxx_msm" and force all dynamically linked module called "ci13xxx_msm" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_CI13XXX_MSM
tristate
depends on USB_GADGET_CI13XXX_MSM
default USB_GADGET
select USB_GADGET_SELECTED
# #
# LAST -- dummy/emulated controller # LAST -- dummy/emulated controller
# #
config USB_GADGET_DUMMY_HCD config USB_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)" tristate "Dummy HCD (DEVELOPMENT)"
depends on USB=y || (USB=m && USB_GADGET=m) depends on USB=y || (USB=m && USB_GADGET=m)
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
help help
This host controller driver emulates USB, looping all data transfer This host controller driver emulates USB, looping all data transfer
requests back to a USB "gadget driver" in the same host. The host requests back to a USB "gadget driver" in the same host. The host
...@@ -621,12 +508,6 @@ config USB_GADGET_DUMMY_HCD ...@@ -621,12 +508,6 @@ config USB_GADGET_DUMMY_HCD
dynamically linked module called "dummy_hcd" and force all dynamically linked module called "dummy_hcd" and force all
gadget drivers to also be dynamically linked. gadget drivers to also be dynamically linked.
config USB_DUMMY_HCD
tristate
depends on USB_GADGET_DUMMY_HCD
default USB_GADGET
select USB_GADGET_SELECTED
# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears
# first and will be selected by default. # first and will be selected by default.
...@@ -637,12 +518,18 @@ config USB_GADGET_DUALSPEED ...@@ -637,12 +518,18 @@ config USB_GADGET_DUALSPEED
bool bool
depends on USB_GADGET depends on USB_GADGET
# Selected by UDC drivers that support super-speed opperation
config USB_GADGET_SUPERSPEED
bool
depends on USB_GADGET
depends on USB_GADGET_DUALSPEED
# #
# USB Gadget Drivers # USB Gadget Drivers
# #
choice choice
tristate "USB Gadget Drivers" tristate "USB Gadget Drivers"
depends on USB_GADGET && USB_GADGET_SELECTED depends on USB_GADGET
default USB_ETH default USB_ETH
help help
A Linux "Gadget Driver" talks to the USB Peripheral Controller A Linux "Gadget Driver" talks to the USB Peripheral Controller
...@@ -848,7 +735,7 @@ config USB_FUNCTIONFS_GENERIC ...@@ -848,7 +735,7 @@ config USB_FUNCTIONFS_GENERIC
no Ethernet interface. no Ethernet interface.
config USB_FILE_STORAGE config USB_FILE_STORAGE
tristate "File-backed Storage Gadget" tristate "File-backed Storage Gadget (DEPRECATED)"
depends on BLOCK depends on BLOCK
help help
The File-backed Storage Gadget acts as a USB Mass Storage The File-backed Storage Gadget acts as a USB Mass Storage
...@@ -859,6 +746,9 @@ config USB_FILE_STORAGE ...@@ -859,6 +746,9 @@ config USB_FILE_STORAGE
Say "y" to link the driver statically, or "m" to build a Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_file_storage". dynamically linked module called "g_file_storage".
NOTE: This driver is deprecated. Its replacement is the
Mass Storage Gadget.
config USB_FILE_STORAGE_TEST config USB_FILE_STORAGE_TEST
bool "File-backed Storage Gadget testing version" bool "File-backed Storage Gadget testing version"
depends on USB_FILE_STORAGE depends on USB_FILE_STORAGE
...@@ -878,14 +768,11 @@ config USB_MASS_STORAGE ...@@ -878,14 +768,11 @@ config USB_MASS_STORAGE
device (in much the same way as the "loop" device driver), device (in much the same way as the "loop" device driver),
specified as a module parameter or sysfs option. specified as a module parameter or sysfs option.
This is heavily based on File-backed Storage Gadget and in most This driver is an updated replacement for the deprecated
cases you will want to use FSG instead. This gadget is mostly File-backed Storage Gadget (g_file_storage).
here to test the functionality of the Mass Storage Function
which may be used with composite framework.
Say "y" to link the driver statically, or "m" to build Say "y" to link the driver statically, or "m" to build
a dynamically linked module called "g_mass_storage". If unsure, a dynamically linked module called "g_mass_storage".
consider File-backed Storage Gadget.
config USB_G_SERIAL config USB_G_SERIAL
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
......
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
# #
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
......
...@@ -1438,10 +1438,15 @@ static int udc_wakeup(struct usb_gadget *gadget) ...@@ -1438,10 +1438,15 @@ static int udc_wakeup(struct usb_gadget *gadget)
return 0; return 0;
} }
static int amd5536_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *));
static int amd5536_stop(struct usb_gadget_driver *driver);
/* gadget operations */ /* gadget operations */
static const struct usb_gadget_ops udc_ops = { static const struct usb_gadget_ops udc_ops = {
.wakeup = udc_wakeup, .wakeup = udc_wakeup,
.get_frame = udc_get_frame, .get_frame = udc_get_frame,
.start = amd5536_start,
.stop = amd5536_stop,
}; };
/* Setups endpoint parameters, adds endpoints to linked list */ /* Setups endpoint parameters, adds endpoints to linked list */
...@@ -1955,7 +1960,7 @@ static int setup_ep0(struct udc *dev) ...@@ -1955,7 +1960,7 @@ static int setup_ep0(struct udc *dev)
} }
/* Called by gadget driver to register itself */ /* Called by gadget driver to register itself */
int usb_gadget_probe_driver(struct usb_gadget_driver *driver, static int amd5536_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *)) int (*bind)(struct usb_gadget *))
{ {
struct udc *dev = udc; struct udc *dev = udc;
...@@ -2002,7 +2007,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, ...@@ -2002,7 +2007,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
return 0; return 0;
} }
EXPORT_SYMBOL(usb_gadget_probe_driver);
/* shutdown requests and disconnect from gadget */ /* shutdown requests and disconnect from gadget */
static void static void
...@@ -2027,7 +2031,7 @@ __acquires(dev->lock) ...@@ -2027,7 +2031,7 @@ __acquires(dev->lock)
} }
/* Called by gadget driver to unregister itself */ /* Called by gadget driver to unregister itself */
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) static int amd5536_stop(struct usb_gadget_driver *driver)
{ {
struct udc *dev = udc; struct udc *dev = udc;
unsigned long flags; unsigned long flags;
...@@ -2057,8 +2061,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ...@@ -2057,8 +2061,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
return 0; return 0;
} }
EXPORT_SYMBOL(usb_gadget_unregister_driver);
/* Clear pending NAK bits */ /* Clear pending NAK bits */
static void udc_process_cnak_queue(struct udc *dev) static void udc_process_cnak_queue(struct udc *dev)
...@@ -3134,6 +3136,7 @@ static void udc_pci_remove(struct pci_dev *pdev) ...@@ -3134,6 +3136,7 @@ static void udc_pci_remove(struct pci_dev *pdev)
dev = pci_get_drvdata(pdev); dev = pci_get_drvdata(pdev);
usb_del_gadget_udc(&udc->gadget);
/* gadget driver must not be registered */ /* gadget driver must not be registered */
BUG_ON(dev->driver != NULL); BUG_ON(dev->driver != NULL);
...@@ -3382,8 +3385,13 @@ static int udc_probe(struct udc *dev) ...@@ -3382,8 +3385,13 @@ static int udc_probe(struct udc *dev)
"driver version: %s(for Geode5536 B1)\n", tmp); "driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev; udc = dev;
retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
if (retval)
goto finished;
retval = device_register(&dev->gadget.dev); retval = device_register(&dev->gadget.dev);
if (retval) { if (retval) {
usb_del_gadget_udc(&dev->gadget);
put_device(&dev->gadget.dev); put_device(&dev->gadget.dev);
goto finished; goto finished;
} }
......
...@@ -985,12 +985,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) ...@@ -985,12 +985,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
return 0; return 0;
} }
static int at91_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *));
static int at91_stop(struct usb_gadget_driver *driver);
static const struct usb_gadget_ops at91_udc_ops = { static const struct usb_gadget_ops at91_udc_ops = {
.get_frame = at91_get_frame, .get_frame = at91_get_frame,
.wakeup = at91_wakeup, .wakeup = at91_wakeup,
.set_selfpowered = at91_set_selfpowered, .set_selfpowered = at91_set_selfpowered,
.vbus_session = at91_vbus_session, .vbus_session = at91_vbus_session,
.pullup = at91_pullup, .pullup = at91_pullup,
.start = at91_start,
.stop = at91_stop,
/* /*
* VBUS-powered devices may also also want to support bigger * VBUS-powered devices may also also want to support bigger
...@@ -1628,7 +1634,7 @@ static void at91_vbus_timer(unsigned long data) ...@@ -1628,7 +1634,7 @@ static void at91_vbus_timer(unsigned long data)
schedule_work(&udc->vbus_timer_work); schedule_work(&udc->vbus_timer_work);
} }
int usb_gadget_probe_driver(struct usb_gadget_driver *driver, static int at91_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *)) int (*bind)(struct usb_gadget *))
{ {
struct at91_udc *udc = &controller; struct at91_udc *udc = &controller;
...@@ -1672,9 +1678,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, ...@@ -1672,9 +1678,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
DBG("bound to %s\n", driver->driver.name); DBG("bound to %s\n", driver->driver.name);
return 0; return 0;
} }
EXPORT_SYMBOL(usb_gadget_probe_driver);
int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) static int at91_stop(struct usb_gadget_driver *driver)
{ {
struct at91_udc *udc = &controller; struct at91_udc *udc = &controller;
unsigned long flags; unsigned long flags;
...@@ -1696,7 +1701,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) ...@@ -1696,7 +1701,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
DBG("unbound from %s\n", driver->driver.name); DBG("unbound from %s\n", driver->driver.name);
return 0; return 0;
} }
EXPORT_SYMBOL (usb_gadget_unregister_driver);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1854,13 +1858,18 @@ static int __init at91udc_probe(struct platform_device *pdev) ...@@ -1854,13 +1858,18 @@ static int __init at91udc_probe(struct platform_device *pdev)
DBG("no VBUS detection, assuming always-on\n"); DBG("no VBUS detection, assuming always-on\n");
udc->vbus = 1; udc->vbus = 1;
} }
retval = usb_add_gadget_udc(dev, &udc->gadget);
if (retval)
goto fail4;
dev_set_drvdata(dev, udc); dev_set_drvdata(dev, udc);
device_init_wakeup(dev, 1); device_init_wakeup(dev, 1);
create_debug_file(udc); create_debug_file(udc);
INFO("%s version %s\n", driver_name, DRIVER_VERSION); INFO("%s version %s\n", driver_name, DRIVER_VERSION);
return 0; return 0;
fail4:
if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled)
free_irq(udc->board.vbus_pin, udc);
fail3: fail3:
if (udc->board.vbus_pin > 0) if (udc->board.vbus_pin > 0)
gpio_free(udc->board.vbus_pin); gpio_free(udc->board.vbus_pin);
...@@ -1887,6 +1896,7 @@ static int __exit at91udc_remove(struct platform_device *pdev) ...@@ -1887,6 +1896,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
DBG("remove\n"); DBG("remove\n");
usb_del_gadget_udc(&udc->gadget);
if (udc->driver) if (udc->driver)
return -EBUSY; return -EBUSY;
......
...@@ -1007,10 +1007,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) ...@@ -1007,10 +1007,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
return 0; return 0;
} }
static int atmel_usba_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *));
static int atmel_usba_stop(struct usb_gadget_driver *driver);
static const struct usb_gadget_ops usba_udc_ops = { static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame, .get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup, .wakeup = usba_udc_wakeup,
.set_selfpowered = usba_udc_set_selfpowered, .set_selfpowered = usba_udc_set_selfpowered,
.start = atmel_usba_start,
.stop = atmel_usba_stop,
}; };
static struct usb_endpoint_descriptor usba_ep0_desc = { static struct usb_endpoint_descriptor usba_ep0_desc = {
...@@ -1789,7 +1795,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid) ...@@ -1789,7 +1795,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int usb_gadget_probe_driver(struct usb_gadget_driver *driver, static int atmel_usba_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *)) int (*bind)(struct usb_gadget *))
{ {
struct usba_udc *udc = &the_udc; struct usba_udc *udc = &the_udc;
...@@ -1842,9 +1848,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, ...@@ -1842,9 +1848,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
udc->gadget.dev.driver = NULL; udc->gadget.dev.driver = NULL;
return ret; return ret;
} }
EXPORT_SYMBOL(usb_gadget_probe_driver);
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) static int atmel_usba_stop(struct usb_gadget_driver *driver)
{ {
struct usba_udc *udc = &the_udc; struct usba_udc *udc = &the_udc;
unsigned long flags; unsigned long flags;
...@@ -1880,7 +1885,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ...@@ -1880,7 +1885,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
return 0; return 0;
} }
EXPORT_SYMBOL(usb_gadget_unregister_driver);
static int __init usba_udc_probe(struct platform_device *pdev) static int __init usba_udc_probe(struct platform_device *pdev)
{ {
...@@ -2021,12 +2025,24 @@ static int __init usba_udc_probe(struct platform_device *pdev) ...@@ -2021,12 +2025,24 @@ static int __init usba_udc_probe(struct platform_device *pdev)
} }
} }
ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (ret)
goto err_add_udc;
usba_init_debugfs(udc); usba_init_debugfs(udc);
for (i = 1; i < pdata->num_ep; i++) for (i = 1; i < pdata->num_ep; i++)
usba_ep_init_debugfs(udc, &usba_ep[i]); usba_ep_init_debugfs(udc, &usba_ep[i]);
return 0; return 0;
err_add_udc:
if (gpio_is_valid(pdata->vbus_pin)) {
free_irq(gpio_to_irq(udc->vbus_pin), udc);
gpio_free(udc->vbus_pin);
}
device_unregister(&udc->gadget.dev);
err_device_add: err_device_add:
free_irq(irq, udc); free_irq(irq, udc);
err_request_irq: err_request_irq:
...@@ -2053,6 +2069,8 @@ static int __exit usba_udc_remove(struct platform_device *pdev) ...@@ -2053,6 +2069,8 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
udc = platform_get_drvdata(pdev); udc = platform_get_drvdata(pdev);
usb_del_gadget_udc(&udc->gadget);
for (i = 1; i < pdata->num_ep; i++) for (i = 1; i < pdata->num_ep; i++)
usba_ep_cleanup_debugfs(&usba_ep[i]); usba_ep_cleanup_debugfs(&usba_ep[i]);
usba_cleanup_debugfs(udc); usba_cleanup_debugfs(udc);
......
...@@ -165,6 +165,7 @@ static struct usb_composite_driver audio_driver = { ...@@ -165,6 +165,7 @@ static struct usb_composite_driver audio_driver = {
.name = "g_audio", .name = "g_audio",
.dev = &device_desc, .dev = &device_desc,
.strings = audio_strings, .strings = audio_strings,
.max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(audio_unbind), .unbind = __exit_p(audio_unbind),
}; };
......
...@@ -244,6 +244,7 @@ static struct usb_composite_driver cdc_driver = { ...@@ -244,6 +244,7 @@ static struct usb_composite_driver cdc_driver = {
.name = "g_cdc", .name = "g_cdc",
.dev = &device_desc, .dev = &device_desc,
.strings = dev_strings, .strings = dev_strings,
.max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(cdc_unbind), .unbind = __exit_p(cdc_unbind),
}; };
......
...@@ -126,6 +126,7 @@ static struct platform_driver ci13xxx_msm_driver = { ...@@ -126,6 +126,7 @@ static struct platform_driver ci13xxx_msm_driver = {
.probe = ci13xxx_msm_probe, .probe = ci13xxx_msm_probe,
.driver = { .name = "msm_hsusb", }, .driver = { .name = "msm_hsusb", },
}; };
MODULE_ALIAS("platform:msm_hsusb");
static int __init ci13xxx_msm_init(void) static int __init ci13xxx_msm_init(void)
{ {
......
...@@ -857,7 +857,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra) ...@@ -857,7 +857,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra)
stamp = stamp * 1000000 + tval.tv_usec; stamp = stamp * 1000000 + tval.tv_usec;
scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
"%04X\t %02X %-7.7s %4i \t%s\n", "%04X\t? %02X %-7.7s %4i ?\t%s\n",
stamp, addr, name, status, extra); stamp, addr, name, status, extra);
dbg_inc(&dbg_data.idx); dbg_inc(&dbg_data.idx);
...@@ -865,7 +865,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra) ...@@ -865,7 +865,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra)
write_unlock_irqrestore(&dbg_data.lck, flags); write_unlock_irqrestore(&dbg_data.lck, flags);
if (dbg_data.tty != 0) if (dbg_data.tty != 0)
pr_notice("%04X\t %02X %-7.7s %4i \t%s\n", pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
stamp, addr, name, status, extra); stamp, addr, name, status, extra);
} }
...@@ -1025,15 +1025,15 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr, ...@@ -1025,15 +1025,15 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
isr_statistics.test); isr_statistics.test);
n += scnprintf(buf + n, PAGE_SIZE - n, " ui = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
isr_statistics.ui); isr_statistics.ui);
n += scnprintf(buf + n, PAGE_SIZE - n, " uei = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
isr_statistics.uei); isr_statistics.uei);
n += scnprintf(buf + n, PAGE_SIZE - n, " pci = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
isr_statistics.pci); isr_statistics.pci);
n += scnprintf(buf + n, PAGE_SIZE - n, " uri = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
isr_statistics.uri); isr_statistics.uri);
n += scnprintf(buf + n, PAGE_SIZE - n, " sli = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
isr_statistics.sli); isr_statistics.sli);
n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
isr_statistics.none); isr_statistics.none);
...@@ -1214,12 +1214,13 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); ...@@ -1214,12 +1214,13 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
* *
* Check "device.h" for details * Check "device.h" for details
*/ */
#define DUMP_ENTRIES 512
static ssize_t show_registers(struct device *dev, static ssize_t show_registers(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags; unsigned long flags;
u32 dump[512]; u32 *dump;
unsigned i, k, n = 0; unsigned i, k, n = 0;
dbg_trace("[%s] %p\n", __func__, buf); dbg_trace("[%s] %p\n", __func__, buf);
...@@ -1228,8 +1229,14 @@ static ssize_t show_registers(struct device *dev, ...@@ -1228,8 +1229,14 @@ static ssize_t show_registers(struct device *dev,
return 0; return 0;
} }
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
if (!dump) {
dev_err(dev, "%s: out of memory\n", __func__);
return 0;
}
spin_lock_irqsave(udc->lock, flags); spin_lock_irqsave(udc->lock, flags);
k = hw_register_read(dump, sizeof(dump)/sizeof(u32)); k = hw_register_read(dump, DUMP_ENTRIES);
spin_unlock_irqrestore(udc->lock, flags); spin_unlock_irqrestore(udc->lock, flags);
for (i = 0; i < k; i++) { for (i = 0; i < k; i++) {
...@@ -1237,6 +1244,7 @@ static ssize_t show_registers(struct device *dev, ...@@ -1237,6 +1244,7 @@ static ssize_t show_registers(struct device *dev,
"reg[0x%04X] = 0x%08X\n", "reg[0x%04X] = 0x%08X\n",
i * (unsigned)sizeof(u32), dump[i]); i * (unsigned)sizeof(u32), dump[i]);
} }
kfree(dump);
return n; return n;
} }
...@@ -2515,6 +2523,9 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) ...@@ -2515,6 +2523,9 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
return -ENOTSUPP; return -ENOTSUPP;
} }
static int ci13xxx_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *));
static int ci13xxx_stop(struct usb_gadget_driver *driver);
/** /**
* Device operations part of the API to the USB controller hardware, * Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o) * which don't involve endpoints (or i/o)
...@@ -2524,17 +2535,19 @@ static const struct usb_gadget_ops usb_gadget_ops = { ...@@ -2524,17 +2535,19 @@ static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci13xxx_vbus_session, .vbus_session = ci13xxx_vbus_session,
.wakeup = ci13xxx_wakeup, .wakeup = ci13xxx_wakeup,
.vbus_draw = ci13xxx_vbus_draw, .vbus_draw = ci13xxx_vbus_draw,
.start = ci13xxx_start,
.stop = ci13xxx_stop,
}; };
/** /**
* usb_gadget_probe_driver: register a gadget driver * ci13xxx_start: register a gadget driver
* @driver: the driver being registered * @driver: the driver being registered
* @bind: the driver's bind callback * @bind: the driver's bind callback
* *
* Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details. * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
* Interrupts are enabled here. * Interrupts are enabled here.
*/ */
int usb_gadget_probe_driver(struct usb_gadget_driver *driver, static int ci13xxx_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *)) int (*bind)(struct usb_gadget *))
{ {
struct ci13xxx *udc = _udc; struct ci13xxx *udc = _udc;
...@@ -2615,10 +2628,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, ...@@ -2615,10 +2628,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
if (retval) if (retval)
goto done; goto done;
spin_unlock_irqrestore(udc->lock, flags); spin_unlock_irqrestore(udc->lock, flags);
retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc); udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
retval = usb_ep_enable(&udc->ep0out.ep);
if (retval) if (retval)
return retval; return retval;
retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
retval = usb_ep_enable(&udc->ep0in.ep);
if (retval) if (retval)
return retval; return retval;
spin_lock_irqsave(udc->lock, flags); spin_lock_irqsave(udc->lock, flags);
...@@ -2657,14 +2673,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, ...@@ -2657,14 +2673,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
spin_unlock_irqrestore(udc->lock, flags); spin_unlock_irqrestore(udc->lock, flags);
return retval; return retval;
} }
EXPORT_SYMBOL(usb_gadget_probe_driver);
/** /**
* usb_gadget_unregister_driver: unregister a gadget driver * ci13xxx_stop: unregister a gadget driver
* *
* Check usb_gadget_unregister_driver() at "usb_gadget.h" for details * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
*/ */
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) static int ci13xxx_stop(struct usb_gadget_driver *driver)
{ {
struct ci13xxx *udc = _udc; struct ci13xxx *udc = _udc;
unsigned long i, flags; unsigned long i, flags;
...@@ -2726,7 +2741,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ...@@ -2726,7 +2741,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
return 0; return 0;
} }
EXPORT_SYMBOL(usb_gadget_unregister_driver);
/****************************************************************************** /******************************************************************************
* BUS block * BUS block
...@@ -2901,12 +2915,23 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, ...@@ -2901,12 +2915,23 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
if (retval) if (retval)
goto remove_dbg; goto remove_dbg;
} }
retval = usb_add_gadget_udc(dev, &udc->gadget);
if (retval)
goto remove_trans;
pm_runtime_no_callbacks(&udc->gadget.dev); pm_runtime_no_callbacks(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev); pm_runtime_enable(&udc->gadget.dev);
_udc = udc; _udc = udc;
return retval; return retval;
remove_trans:
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget);
otg_put_transceiver(udc->transceiver);
}
err("error = %i", retval); err("error = %i", retval);
remove_dbg: remove_dbg:
#ifdef CONFIG_USB_GADGET_DEBUG_FILES #ifdef CONFIG_USB_GADGET_DEBUG_FILES
...@@ -2936,6 +2961,7 @@ static void udc_remove(void) ...@@ -2936,6 +2961,7 @@ static void udc_remove(void)
err("EINVAL"); err("EINVAL");
return; return;
} }
usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) { if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget); otg_set_peripheral(udc->transceiver, &udc->gadget);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include <asm/unaligned.h>
/* /*
* The code in this file is utility code, used to build a gadget driver * The code in this file is utility code, used to build a gadget driver
...@@ -74,6 +74,130 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); ...@@ -74,6 +74,130 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
static char composite_manufacturer[50]; static char composite_manufacturer[50];
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/**
* next_ep_desc() - advance to the next EP descriptor
* @t: currect pointer within descriptor array
*
* Return: next EP descriptor or NULL
*
* Iterate over @t until either EP descriptor found or
* NULL (that indicates end of list) encountered
*/
static struct usb_descriptor_header**
next_ep_desc(struct usb_descriptor_header **t)
{
for (; *t; t++) {
if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
return t;
}
return NULL;
}
/*
* for_each_ep_desc()- iterate over endpoint descriptors in the
* descriptors list
* @start: pointer within descriptor array.
* @ep_desc: endpoint descriptor to use as the loop cursor
*/
#define for_each_ep_desc(start, ep_desc) \
for (ep_desc = next_ep_desc(start); \
ep_desc; ep_desc = next_ep_desc(ep_desc+1))
/**
* config_ep_by_speed() - configures the given endpoint
* according to gadget speed.
* @g: pointer to the gadget
* @f: usb function
* @_ep: the endpoint to configure
*
* Return: error code, 0 on success
*
* This function chooses the right descriptors for a given
* endpoint according to gadget speed and saves it in the
* endpoint desc field. If the endpoint already has a descriptor
* assigned to it - overwrites it with currently corresponding
* descriptor. The endpoint maxpacket field is updated according
* to the chosen descriptor.
* Note: the supplied function should hold all the descriptors
* for supported speeds
*/
int config_ep_by_speed(struct usb_gadget *g,
struct usb_function *f,
struct usb_ep *_ep)
{
struct usb_endpoint_descriptor *chosen_desc = NULL;
struct usb_descriptor_header **speed_desc = NULL;
struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
int want_comp_desc = 0;
struct usb_descriptor_header **d_spd; /* cursor for speed desc */
if (!g || !f || !_ep)
return -EIO;
/* select desired speed */
switch (g->speed) {
case USB_SPEED_SUPER:
if (gadget_is_superspeed(g)) {
speed_desc = f->ss_descriptors;
want_comp_desc = 1;
break;
}
/* else: Fall trough */
case USB_SPEED_HIGH:
if (gadget_is_dualspeed(g)) {
speed_desc = f->hs_descriptors;
break;
}
/* else: fall through */
default:
speed_desc = f->descriptors;
}
/* find descriptors */
for_each_ep_desc(speed_desc, d_spd) {
chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
if (chosen_desc->bEndpointAddress == _ep->address)
goto ep_found;
}
return -EIO;
ep_found:
/* commit results */
_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
_ep->desc = chosen_desc;
_ep->comp_desc = NULL;
_ep->maxburst = 0;
_ep->mult = 0;
if (!want_comp_desc)
return 0;
/*
* Companion descriptor should follow EP descriptor
* USB 3.0 spec, #9.6.7
*/
comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
if (!comp_desc ||
(comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
return -EIO;
_ep->comp_desc = comp_desc;
if (g->speed == USB_SPEED_SUPER) {
switch (usb_endpoint_type(_ep->desc)) {
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
_ep->maxburst = comp_desc->bMaxBurst;
break;
case USB_ENDPOINT_XFER_ISOC:
/* mult: bits 1:0 of bmAttributes */
_ep->mult = comp_desc->bmAttributes & 0x3;
break;
default:
/* Do nothing for control endpoints */
break;
}
}
return 0;
}
/** /**
* usb_add_function() - add a function to a configuration * usb_add_function() - add a function to a configuration
...@@ -123,6 +247,8 @@ int usb_add_function(struct usb_configuration *config, ...@@ -123,6 +247,8 @@ int usb_add_function(struct usb_configuration *config,
config->fullspeed = true; config->fullspeed = true;
if (!config->highspeed && function->hs_descriptors) if (!config->highspeed && function->hs_descriptors)
config->highspeed = true; config->highspeed = true;
if (!config->superspeed && function->ss_descriptors)
config->superspeed = true;
done: done:
if (value) if (value)
...@@ -266,10 +392,17 @@ static int config_buf(struct usb_configuration *config, ...@@ -266,10 +392,17 @@ static int config_buf(struct usb_configuration *config,
list_for_each_entry(f, &config->functions, list) { list_for_each_entry(f, &config->functions, list) {
struct usb_descriptor_header **descriptors; struct usb_descriptor_header **descriptors;
if (speed == USB_SPEED_HIGH) switch (speed) {
case USB_SPEED_SUPER:
descriptors = f->ss_descriptors;
break;
case USB_SPEED_HIGH:
descriptors = f->hs_descriptors; descriptors = f->hs_descriptors;
else break;
default:
descriptors = f->descriptors; descriptors = f->descriptors;
}
if (!descriptors) if (!descriptors)
continue; continue;
status = usb_descriptor_fillbuf(next, len, status = usb_descriptor_fillbuf(next, len,
...@@ -292,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) ...@@ -292,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
u8 type = w_value >> 8; u8 type = w_value >> 8;
enum usb_device_speed speed = USB_SPEED_UNKNOWN; enum usb_device_speed speed = USB_SPEED_UNKNOWN;
if (gadget_is_dualspeed(gadget)) { if (gadget->speed == USB_SPEED_SUPER)
speed = gadget->speed;
else if (gadget_is_dualspeed(gadget)) {
int hs = 0; int hs = 0;
if (gadget->speed == USB_SPEED_HIGH) if (gadget->speed == USB_SPEED_HIGH)
hs = 1; hs = 1;
if (type == USB_DT_OTHER_SPEED_CONFIG) if (type == USB_DT_OTHER_SPEED_CONFIG)
...@@ -308,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) ...@@ -308,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
w_value &= 0xff; w_value &= 0xff;
list_for_each_entry(c, &cdev->configs, list) { list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */ /* ignore configs that won't work at this speed */
if (speed == USB_SPEED_HIGH) { switch (speed) {
case USB_SPEED_SUPER:
if (!c->superspeed)
continue;
break;
case USB_SPEED_HIGH:
if (!c->highspeed) if (!c->highspeed)
continue; continue;
} else { break;
default:
if (!c->fullspeed) if (!c->fullspeed)
continue; continue;
} }
if (w_value == 0) if (w_value == 0)
return config_buf(c, speed, cdev->req->buf, type); return config_buf(c, speed, cdev->req->buf, type);
w_value--; w_value--;
...@@ -328,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) ...@@ -328,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
struct usb_configuration *c; struct usb_configuration *c;
unsigned count = 0; unsigned count = 0;
int hs = 0; int hs = 0;
int ss = 0;
if (gadget_is_dualspeed(gadget)) { if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH) if (gadget->speed == USB_SPEED_HIGH)
hs = 1; hs = 1;
if (gadget->speed == USB_SPEED_SUPER)
ss = 1;
if (type == USB_DT_DEVICE_QUALIFIER) if (type == USB_DT_DEVICE_QUALIFIER)
hs = !hs; hs = !hs;
} }
list_for_each_entry(c, &cdev->configs, list) { list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */ /* ignore configs that won't work at this speed */
if (hs) { if (ss) {
if (!c->superspeed)
continue;
} else if (hs) {
if (!c->highspeed) if (!c->highspeed)
continue; continue;
} else { } else {
...@@ -349,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) ...@@ -349,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
return count; return count;
} }
/**
* bos_desc() - prepares the BOS descriptor.
* @cdev: pointer to usb_composite device to generate the bos
* descriptor for
*
* This function generates the BOS (Binary Device Object)
* descriptor and its device capabilities descriptors. The BOS
* descriptor should be supported by a SuperSpeed device.
*/
static int bos_desc(struct usb_composite_dev *cdev)
{
struct usb_ext_cap_descriptor *usb_ext;
struct usb_ss_cap_descriptor *ss_cap;
struct usb_dcd_config_params dcd_config_params;
struct usb_bos_descriptor *bos = cdev->req->buf;
bos->bLength = USB_DT_BOS_SIZE;
bos->bDescriptorType = USB_DT_BOS;
bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
bos->bNumDeviceCaps = 0;
/*
* A SuperSpeed device shall include the USB2.0 extension descriptor
* and shall support LPM when operating in USB2.0 HS mode.
*/
usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++;
le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
/*
* The Superspeed USB Capability descriptor shall be implemented by all
* SuperSpeed devices.
*/
ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++;
le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
ss_cap->bmAttributes = 0; /* LTM is not supported yet */
ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
USB_FULL_SPEED_OPERATION |
USB_HIGH_SPEED_OPERATION |
USB_5GBPS_OPERATION);
ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
/* Get Controller configuration */
if (cdev->gadget->ops->get_config_params)
cdev->gadget->ops->get_config_params(&dcd_config_params);
else {
dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT;
dcd_config_params.bU2DevExitLat =
cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT);
}
ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
return le16_to_cpu(bos->wTotalLength);
}
static void device_qual(struct usb_composite_dev *cdev) static void device_qual(struct usb_composite_dev *cdev)
{ {
struct usb_qualifier_descriptor *qual = cdev->req->buf; struct usb_qualifier_descriptor *qual = cdev->req->buf;
...@@ -361,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev) ...@@ -361,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev)
qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
/* ASSUME same EP0 fifo size at both speeds */ /* ASSUME same EP0 fifo size at both speeds */
qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0; qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
qual->bRESERVED = 0; qual->bRESERVED = 0;
} }
...@@ -392,28 +604,46 @@ static int set_config(struct usb_composite_dev *cdev, ...@@ -392,28 +604,46 @@ static int set_config(struct usb_composite_dev *cdev,
unsigned power = gadget_is_otg(gadget) ? 8 : 100; unsigned power = gadget_is_otg(gadget) ? 8 : 100;
int tmp; int tmp;
if (cdev->config)
reset_config(cdev);
if (number) { if (number) {
list_for_each_entry(c, &cdev->configs, list) { list_for_each_entry(c, &cdev->configs, list) {
if (c->bConfigurationValue == number) { if (c->bConfigurationValue == number) {
/*
* We disable the FDs of the previous
* configuration only if the new configuration
* is a valid one
*/
if (cdev->config)
reset_config(cdev);
result = 0; result = 0;
break; break;
} }
} }
if (result < 0) if (result < 0)
goto done; goto done;
} else } else { /* Zero configuration value - need to reset the config */
if (cdev->config)
reset_config(cdev);
result = 0; result = 0;
}
INFO(cdev, "%s speed config #%d: %s\n", INFO(cdev, "%s speed config #%d: %s\n",
({ char *speed; ({ char *speed;
switch (gadget->speed) { switch (gadget->speed) {
case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_LOW:
case USB_SPEED_FULL: speed = "full"; break; speed = "low";
case USB_SPEED_HIGH: speed = "high"; break; break;
default: speed = "?"; break; case USB_SPEED_FULL:
speed = "full";
break;
case USB_SPEED_HIGH:
speed = "high";
break;
case USB_SPEED_SUPER:
speed = "super";
break;
default:
speed = "?";
break;
} ; speed; }), number, c ? c->label : "unconfigured"); } ; speed; }), number, c ? c->label : "unconfigured");
if (!c) if (!c)
...@@ -435,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev, ...@@ -435,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev,
* function's setup callback instead of the current * function's setup callback instead of the current
* configuration's setup callback. * configuration's setup callback.
*/ */
if (gadget->speed == USB_SPEED_HIGH) switch (gadget->speed) {
case USB_SPEED_SUPER:
descriptors = f->ss_descriptors;
break;
case USB_SPEED_HIGH:
descriptors = f->hs_descriptors; descriptors = f->hs_descriptors;
else break;
default:
descriptors = f->descriptors; descriptors = f->descriptors;
}
for (; *descriptors; ++descriptors) { for (; *descriptors; ++descriptors) {
struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep;
...@@ -531,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev, ...@@ -531,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
} else { } else {
unsigned i; unsigned i;
DBG(cdev, "cfg %d/%p speeds:%s%s\n", DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
config->bConfigurationValue, config, config->bConfigurationValue, config,
config->superspeed ? " super" : "",
config->highspeed ? " high" : "", config->highspeed ? " high" : "",
config->fullspeed config->fullspeed
? (gadget_is_dualspeed(cdev->gadget) ? (gadget_is_dualspeed(cdev->gadget)
...@@ -811,6 +1048,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -811,6 +1048,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_request *req = cdev->req; struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP; int value = -EOPNOTSUPP;
int status = 0;
u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_index = le16_to_cpu(ctrl->wIndex);
u8 intf = w_index & 0xFF; u8 intf = w_index & 0xFF;
u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_value = le16_to_cpu(ctrl->wValue);
...@@ -838,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -838,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_DT_DEVICE: case USB_DT_DEVICE:
cdev->desc.bNumConfigurations = cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE); count_configs(cdev, USB_DT_DEVICE);
cdev->desc.bMaxPacketSize0 =
cdev->gadget->ep0->maxpacket;
if (gadget_is_superspeed(gadget)) {
if (gadget->speed >= USB_SPEED_SUPER)
cdev->desc.bcdUSB = cpu_to_le16(0x0300);
else
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
}
value = min(w_length, (u16) sizeof cdev->desc); value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value); memcpy(req->buf, &cdev->desc, value);
break; break;
case USB_DT_DEVICE_QUALIFIER: case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget)) if (!gadget_is_dualspeed(gadget) ||
gadget->speed >= USB_SPEED_SUPER)
break; break;
device_qual(cdev); device_qual(cdev);
value = min_t(int, w_length, value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor)); sizeof(struct usb_qualifier_descriptor));
break; break;
case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget_is_dualspeed(gadget)) if (!gadget_is_dualspeed(gadget) ||
gadget->speed >= USB_SPEED_SUPER)
break; break;
/* FALLTHROUGH */ /* FALLTHROUGH */
case USB_DT_CONFIG: case USB_DT_CONFIG:
...@@ -863,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -863,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (value >= 0) if (value >= 0)
value = min(w_length, (u16) value); value = min(w_length, (u16) value);
break; break;
case USB_DT_BOS:
if (gadget_is_superspeed(gadget)) {
value = bos_desc(cdev);
value = min(w_length, (u16) value);
}
break;
} }
break; break;
...@@ -930,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -930,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
*((u8 *)req->buf) = value; *((u8 *)req->buf) = value;
value = min(w_length, (u16) 1); value = min(w_length, (u16) 1);
break; break;
/*
* USB 3.0 additions:
* Function driver should handle get_status request. If such cb
* wasn't supplied we respond with default value = 0
* Note: function driver should supply such cb only for the first
* interface of the function
*/
case USB_REQ_GET_STATUS:
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
goto unknown;
value = 2; /* This is the length of the get_status reply */
put_unaligned_le16(0, req->buf);
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
status = f->get_status ? f->get_status(f) : 0;
if (status < 0)
break;
put_unaligned_le16(status & 0x0000ffff, req->buf);
break;
/*
* Function drivers should handle SetFeature/ClearFeature
* (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
* only for the first interface of the function
*/
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
goto unknown;
switch (w_value) {
case USB_INTRF_FUNC_SUSPEND:
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
value = 0;
if (f->func_suspend)
value = f->func_suspend(f, w_index >> 8);
if (value < 0) {
ERROR(cdev,
"func_suspend() returned error %d\n",
value);
value = 0;
}
break;
}
break;
default: default:
unknown: unknown:
VDBG(cdev, VDBG(cdev,
...@@ -1140,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget) ...@@ -1140,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget)
goto fail; goto fail;
cdev->desc = *composite->dev; cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
/* standardized runtime overrides for device ID data */ /* standardized runtime overrides for device ID data */
if (idVendor) if (idVendor)
...@@ -1247,7 +1556,11 @@ composite_resume(struct usb_gadget *gadget) ...@@ -1247,7 +1556,11 @@ composite_resume(struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_gadget_driver composite_driver = { static struct usb_gadget_driver composite_driver = {
#ifdef CONFIG_USB_GADGET_SUPERSPEED
.speed = USB_SPEED_SUPER,
#else
.speed = USB_SPEED_HIGH, .speed = USB_SPEED_HIGH,
#endif
.unbind = composite_unbind, .unbind = composite_unbind,
...@@ -1293,6 +1606,8 @@ int usb_composite_probe(struct usb_composite_driver *driver, ...@@ -1293,6 +1606,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,
driver->iProduct = driver->name; driver->iProduct = driver->name;
composite_driver.function = (char *) driver->name; composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name; composite_driver.driver.name = driver->name;
composite_driver.speed = min((u8)composite_driver.speed,
(u8)driver->max_speed);
composite = driver; composite = driver;
composite_gadget_bind = bind; composite_gadget_bind = bind;
......
...@@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src) ...@@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
return ret; return ret;
} }
/**
* usb_find_endpoint - find a copy of an endpoint descriptor
* @src: original vector of descriptors
* @copy: copy of @src
* @match: endpoint descriptor found in @src
*
* This returns the copy of the @match descriptor made for @copy. Its
* intended use is to help remembering the endpoint descriptor to use
* when enabling a given endpoint.
*/
struct usb_endpoint_descriptor *
usb_find_endpoint(
struct usb_descriptor_header **src,
struct usb_descriptor_header **copy,
struct usb_endpoint_descriptor *match
)
{
while (*src) {
if (*src == (void *) match)
return (void *)*copy;
src++;
copy++;
}
return NULL;
}
...@@ -173,7 +173,9 @@ static int dbgp_enable_ep_req(struct usb_ep *ep) ...@@ -173,7 +173,9 @@ static int dbgp_enable_ep_req(struct usb_ep *ep)
static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc) static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
{ {
int err = usb_ep_enable(ep, desc); int err;
ep->desc = desc;
err = usb_ep_enable(ep);
ep->driver_data = dbgp.gadget; ep->driver_data = dbgp.gadget;
return err; return err;
} }
...@@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) ...@@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
dbgp.serial->in = dbgp.i_ep; dbgp.serial->in = dbgp.i_ep;
dbgp.serial->out = dbgp.o_ep; dbgp.serial->out = dbgp.o_ep;
dbgp.serial->in_desc = &i_desc; dbgp.serial->in->desc = &i_desc;
dbgp.serial->out_desc = &o_desc; dbgp.serial->out->desc = &o_desc;
if (gserial_setup(gadget, 1) < 0) { if (gserial_setup(gadget, 1) < 0) {
stp = 3; stp = 3;
...@@ -312,7 +314,6 @@ static int __init dbgp_bind(struct usb_gadget *gadget) ...@@ -312,7 +314,6 @@ static int __init dbgp_bind(struct usb_gadget *gadget)
dbgp.req->length = DBGP_REQ_EP0_LEN; dbgp.req->length = DBGP_REQ_EP0_LEN;
gadget->ep0->driver_data = gadget; gadget->ep0->driver_data = gadget;
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
#ifdef CONFIG_USB_G_DBGP_SERIAL #ifdef CONFIG_USB_G_DBGP_SERIAL
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL); dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
...@@ -363,6 +364,7 @@ static int dbgp_setup(struct usb_gadget *gadget, ...@@ -363,6 +364,7 @@ static int dbgp_setup(struct usb_gadget *gadget,
dev_dbg(&dbgp.gadget->dev, "setup: desc device\n"); dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
len = sizeof device_desc; len = sizeof device_desc;
data = &device_desc; data = &device_desc;
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
break; break;
case USB_DT_DEBUG: case USB_DT_DEBUG:
dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n"); dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
......
此差异已折叠。
...@@ -63,13 +63,16 @@ static int ...@@ -63,13 +63,16 @@ static int
ep_matches ( ep_matches (
struct usb_gadget *gadget, struct usb_gadget *gadget,
struct usb_ep *ep, struct usb_ep *ep,
struct usb_endpoint_descriptor *desc struct usb_endpoint_descriptor *desc,
struct usb_ss_ep_comp_descriptor *ep_comp
) )
{ {
u8 type; u8 type;
const char *tmp; const char *tmp;
u16 max; u16 max;
int num_req_streams = 0;
/* endpoint already claimed? */ /* endpoint already claimed? */
if (NULL != ep->driver_data) if (NULL != ep->driver_data)
return 0; return 0;
...@@ -128,6 +131,22 @@ ep_matches ( ...@@ -128,6 +131,22 @@ ep_matches (
} }
} }
/*
* Get the number of required streams from the EP companion
* descriptor and see if the EP matches it
*/
if (usb_endpoint_xfer_bulk(desc)) {
if (ep_comp) {
num_req_streams = ep_comp->bmAttributes & 0x1f;
if (num_req_streams > ep->max_streams)
return 0;
/* Update the ep_comp descriptor if needed */
if (num_req_streams != ep->max_streams)
ep_comp->bmAttributes = ep->max_streams;
}
}
/* /*
* If the protocol driver hasn't yet decided on wMaxPacketSize * If the protocol driver hasn't yet decided on wMaxPacketSize
* and wants to know the maximum possible, provide the info. * and wants to know the maximum possible, provide the info.
...@@ -142,13 +161,13 @@ ep_matches ( ...@@ -142,13 +161,13 @@ ep_matches (
max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
switch (type) { switch (type) {
case USB_ENDPOINT_XFER_INT: case USB_ENDPOINT_XFER_INT:
/* INT: limit 64 bytes full speed, 1024 high speed */ /* INT: limit 64 bytes full speed, 1024 high/super speed */
if (!gadget->is_dualspeed && max > 64) if (!gadget->is_dualspeed && max > 64)
return 0; return 0;
/* FALLTHROUGH */ /* FALLTHROUGH */
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
/* ISO: limit 1023 bytes full speed, 1024 high speed */ /* ISO: limit 1023 bytes full speed, 1024 high/super speed */
if (ep->maxpacket < max) if (ep->maxpacket < max)
return 0; return 0;
if (!gadget->is_dualspeed && max > 1023) if (!gadget->is_dualspeed && max > 1023)
...@@ -183,7 +202,7 @@ ep_matches ( ...@@ -183,7 +202,7 @@ ep_matches (
} }
/* report (variable) full speed bulk maxpacket */ /* report (variable) full speed bulk maxpacket */
if (USB_ENDPOINT_XFER_BULK == type) { if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
int size = ep->maxpacket; int size = ep->maxpacket;
/* min() doesn't work on bitfields with gcc-3.5 */ /* min() doesn't work on bitfields with gcc-3.5 */
...@@ -191,6 +210,7 @@ ep_matches ( ...@@ -191,6 +210,7 @@ ep_matches (
size = 64; size = 64;
desc->wMaxPacketSize = cpu_to_le16(size); desc->wMaxPacketSize = cpu_to_le16(size);
} }
ep->address = desc->bEndpointAddress;
return 1; return 1;
} }
...@@ -207,38 +227,53 @@ find_ep (struct usb_gadget *gadget, const char *name) ...@@ -207,38 +227,53 @@ find_ep (struct usb_gadget *gadget, const char *name)
} }
/** /**
* usb_ep_autoconfig - choose an endpoint matching the descriptor * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
* descriptor and ep companion descriptor
* @gadget: The device to which the endpoint must belong. * @gadget: The device to which the endpoint must belong.
* @desc: Endpoint descriptor, with endpoint direction and transfer mode * @desc: Endpoint descriptor, with endpoint direction and transfer mode
* initialized. For periodic transfers, the maximum packet * initialized. For periodic transfers, the maximum packet
* size must also be initialized. This is modified on success. * size must also be initialized. This is modified on
* success.
* @ep_comp: Endpoint companion descriptor, with the required
* number of streams. Will be modified when the chosen EP
* supports a different number of streams.
* *
* By choosing an endpoint to use with the specified descriptor, this * This routine replaces the usb_ep_autoconfig when needed
* routine simplifies writing gadget drivers that work with multiple * superspeed enhancments. If such enhancemnets are required,
* USB device controllers. The endpoint would be passed later to * the FD should call usb_ep_autoconfig_ss directly and provide
* usb_ep_enable(), along with some descriptor. * the additional ep_comp parameter.
*
* By choosing an endpoint to use with the specified descriptor,
* this routine simplifies writing gadget drivers that work with
* multiple USB device controllers. The endpoint would be
* passed later to usb_ep_enable(), along with some descriptor.
* *
* That second descriptor won't always be the same as the first one. * That second descriptor won't always be the same as the first one.
* For example, isochronous endpoints can be autoconfigured for high * For example, isochronous endpoints can be autoconfigured for high
* bandwidth, and then used in several lower bandwidth altsettings. * bandwidth, and then used in several lower bandwidth altsettings.
* Also, high and full speed descriptors will be different. * Also, high and full speed descriptors will be different.
* *
* Be sure to examine and test the results of autoconfiguration on your * Be sure to examine and test the results of autoconfiguration
* hardware. This code may not make the best choices about how to use the * on your hardware. This code may not make the best choices
* USB controller, and it can't know all the restrictions that may apply. * about how to use the USB controller, and it can't know all
* Some combinations of driver and hardware won't be able to autoconfigure. * the restrictions that may apply. Some combinations of driver
* and hardware won't be able to autoconfigure.
* *
* On success, this returns an un-claimed usb_ep, and modifies the endpoint * On success, this returns an un-claimed usb_ep, and modifies the endpoint
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
* is initialized as if the endpoint were used at full speed. To prevent * is initialized as if the endpoint were used at full speed and
* the endpoint from being returned by a later autoconfig call, claim it * the bmAttribute field in the ep companion descriptor is
* by assigning ep->driver_data to some non-null value. * updated with the assigned number of streams if it is
* different from the original value. To prevent the endpoint
* from being returned by a later autoconfig call, claim it by
* assigning ep->driver_data to some non-null value.
* *
* On failure, this returns a null endpoint descriptor. * On failure, this returns a null endpoint descriptor.
*/ */
struct usb_ep *usb_ep_autoconfig ( struct usb_ep *usb_ep_autoconfig_ss(
struct usb_gadget *gadget, struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc struct usb_endpoint_descriptor *desc,
struct usb_ss_ep_comp_descriptor *ep_comp
) )
{ {
struct usb_ep *ep; struct usb_ep *ep;
...@@ -252,23 +287,24 @@ struct usb_ep *usb_ep_autoconfig ( ...@@ -252,23 +287,24 @@ struct usb_ep *usb_ep_autoconfig (
if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
/* ep-e, ep-f are PIO with only 64 byte fifos */ /* ep-e, ep-f are PIO with only 64 byte fifos */
ep = find_ep (gadget, "ep-e"); ep = find_ep (gadget, "ep-e");
if (ep && ep_matches (gadget, ep, desc)) if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep; return ep;
ep = find_ep (gadget, "ep-f"); ep = find_ep (gadget, "ep-f");
if (ep && ep_matches (gadget, ep, desc)) if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep; return ep;
} else if (gadget_is_goku (gadget)) { } else if (gadget_is_goku (gadget)) {
if (USB_ENDPOINT_XFER_INT == type) { if (USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough */ /* single buffering is enough */
ep = find_ep (gadget, "ep3-bulk"); ep = find_ep(gadget, "ep3-bulk");
if (ep && ep_matches (gadget, ep, desc)) if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep; return ep;
} else if (USB_ENDPOINT_XFER_BULK == type } else if (USB_ENDPOINT_XFER_BULK == type
&& (USB_DIR_IN & desc->bEndpointAddress)) { && (USB_DIR_IN & desc->bEndpointAddress)) {
/* DMA may be available */ /* DMA may be available */
ep = find_ep (gadget, "ep2-bulk"); ep = find_ep(gadget, "ep2-bulk");
if (ep && ep_matches (gadget, ep, desc)) if (ep && ep_matches(gadget, ep, desc,
ep_comp))
return ep; return ep;
} }
...@@ -287,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig ( ...@@ -287,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig (
ep = find_ep(gadget, "ep2out"); ep = find_ep(gadget, "ep2out");
} else } else
ep = NULL; ep = NULL;
if (ep && ep_matches (gadget, ep, desc)) if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep; return ep;
#endif #endif
} }
/* Second, look at endpoints until an unclaimed one looks usable */ /* Second, look at endpoints until an unclaimed one looks usable */
list_for_each_entry (ep, &gadget->ep_list, ep_list) { list_for_each_entry (ep, &gadget->ep_list, ep_list) {
if (ep_matches (gadget, ep, desc)) if (ep_matches(gadget, ep, desc, ep_comp))
return ep; return ep;
} }
...@@ -302,6 +338,46 @@ struct usb_ep *usb_ep_autoconfig ( ...@@ -302,6 +338,46 @@ struct usb_ep *usb_ep_autoconfig (
return NULL; return NULL;
} }
/**
* usb_ep_autoconfig() - choose an endpoint matching the
* descriptor
* @gadget: The device to which the endpoint must belong.
* @desc: Endpoint descriptor, with endpoint direction and transfer mode
* initialized. For periodic transfers, the maximum packet
* size must also be initialized. This is modified on success.
*
* By choosing an endpoint to use with the specified descriptor, this
* routine simplifies writing gadget drivers that work with multiple
* USB device controllers. The endpoint would be passed later to
* usb_ep_enable(), along with some descriptor.
*
* That second descriptor won't always be the same as the first one.
* For example, isochronous endpoints can be autoconfigured for high
* bandwidth, and then used in several lower bandwidth altsettings.
* Also, high and full speed descriptors will be different.
*
* Be sure to examine and test the results of autoconfiguration on your
* hardware. This code may not make the best choices about how to use the
* USB controller, and it can't know all the restrictions that may apply.
* Some combinations of driver and hardware won't be able to autoconfigure.
*
* On success, this returns an un-claimed usb_ep, and modifies the endpoint
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
* is initialized as if the endpoint were used at full speed. To prevent
* the endpoint from being returned by a later autoconfig call, claim it
* by assigning ep->driver_data to some non-null value.
*
* On failure, this returns a null endpoint descriptor.
*/
struct usb_ep *usb_ep_autoconfig(
struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc
)
{
return usb_ep_autoconfig_ss(gadget, desc, NULL);
}
/** /**
* usb_ep_autoconfig_reset - reset endpoint autoconfig state * usb_ep_autoconfig_reset - reset endpoint autoconfig state
* @gadget: device for which autoconfig state will be reset * @gadget: device for which autoconfig state will be reset
......
...@@ -401,6 +401,7 @@ static struct usb_composite_driver eth_driver = { ...@@ -401,6 +401,7 @@ static struct usb_composite_driver eth_driver = {
.name = "g_ether", .name = "g_ether",
.dev = &device_desc, .dev = &device_desc,
.strings = dev_strings, .strings = dev_strings,
.max_speed = USB_SPEED_SUPER,
.unbind = __exit_p(eth_unbind), .unbind = __exit_p(eth_unbind),
}; };
......
...@@ -39,12 +39,6 @@ ...@@ -39,12 +39,6 @@
* descriptors (roughly equivalent to CDC Unions) may sometimes help. * descriptors (roughly equivalent to CDC Unions) may sometimes help.
*/ */
struct acm_ep_descs {
struct usb_endpoint_descriptor *in;
struct usb_endpoint_descriptor *out;
struct usb_endpoint_descriptor *notify;
};
struct f_acm { struct f_acm {
struct gserial port; struct gserial port;
u8 ctrl_id, data_id; u8 ctrl_id, data_id;
...@@ -58,11 +52,7 @@ struct f_acm { ...@@ -58,11 +52,7 @@ struct f_acm {
*/ */
spinlock_t lock; spinlock_t lock;
struct acm_ep_descs fs;
struct acm_ep_descs hs;
struct usb_ep *notify; struct usb_ep *notify;
struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req; struct usb_request *notify_req;
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
...@@ -405,23 +395,27 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -405,23 +395,27 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
usb_ep_disable(acm->notify); usb_ep_disable(acm->notify);
} else { } else {
VDBG(cdev, "init acm ctrl interface %d\n", intf); VDBG(cdev, "init acm ctrl interface %d\n", intf);
acm->notify_desc = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f, acm->notify))
acm->hs.notify, return -EINVAL;
acm->fs.notify);
} }
usb_ep_enable(acm->notify, acm->notify_desc); usb_ep_enable(acm->notify);
acm->notify->driver_data = acm; acm->notify->driver_data = acm;
} else if (intf == acm->data_id) { } else if (intf == acm->data_id) {
if (acm->port.in->driver_data) { if (acm->port.in->driver_data) {
DBG(cdev, "reset acm ttyGS%d\n", acm->port_num); DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
gserial_disconnect(&acm->port); gserial_disconnect(&acm->port);
} else { }
if (!acm->port.in->desc || !acm->port.out->desc) {
DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
acm->port.in_desc = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f,
acm->hs.in, acm->fs.in); acm->port.in) ||
acm->port.out_desc = ep_choose(cdev->gadget, config_ep_by_speed(cdev->gadget, f,
acm->hs.out, acm->fs.out); acm->port.out)) {
acm->port.in->desc = NULL;
acm->port.out->desc = NULL;
return -EINVAL;
}
} }
gserial_connect(&acm->port, acm->port_num); gserial_connect(&acm->port, acm->port_num);
...@@ -629,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -629,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
acm->notify_req->complete = acm_cdc_notify_complete; acm->notify_req->complete = acm_cdc_notify_complete;
acm->notify_req->context = acm; acm->notify_req->context = acm;
/* copy descriptors, and track endpoint copies */ /* copy descriptors */
f->descriptors = usb_copy_descriptors(acm_fs_function); f->descriptors = usb_copy_descriptors(acm_fs_function);
if (!f->descriptors) if (!f->descriptors)
goto fail; goto fail;
acm->fs.in = usb_find_endpoint(acm_fs_function,
f->descriptors, &acm_fs_in_desc);
acm->fs.out = usb_find_endpoint(acm_fs_function,
f->descriptors, &acm_fs_out_desc);
acm->fs.notify = usb_find_endpoint(acm_fs_function,
f->descriptors, &acm_fs_notify_desc);
/* support all relevant hardware speeds... we expect that when /* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
* both speeds * both speeds
...@@ -653,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -653,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
acm_hs_notify_desc.bEndpointAddress = acm_hs_notify_desc.bEndpointAddress =
acm_fs_notify_desc.bEndpointAddress; acm_fs_notify_desc.bEndpointAddress;
/* copy descriptors, and track endpoint copies */ /* copy descriptors */
f->hs_descriptors = usb_copy_descriptors(acm_hs_function); f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
acm->hs.in = usb_find_endpoint(acm_hs_function,
f->hs_descriptors, &acm_hs_in_desc);
acm->hs.out = usb_find_endpoint(acm_hs_function,
f->hs_descriptors, &acm_hs_out_desc);
acm->hs.notify = usb_find_endpoint(acm_hs_function,
f->hs_descriptors, &acm_hs_notify_desc);
} }
DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
......
...@@ -279,7 +279,6 @@ struct f_audio { ...@@ -279,7 +279,6 @@ struct f_audio {
/* endpoints handle full and/or high speeds */ /* endpoints handle full and/or high speeds */
struct usb_ep *out_ep; struct usb_ep *out_ep;
struct usb_endpoint_descriptor *out_desc;
spinlock_t lock; spinlock_t lock;
struct f_audio_buf *copy_buf; struct f_audio_buf *copy_buf;
...@@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (intf == 1) { if (intf == 1) {
if (alt == 1) { if (alt == 1) {
usb_ep_enable(out_ep, audio->out_desc); usb_ep_enable(out_ep);
out_ep->driver_data = audio; out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
if (IS_ERR(audio->copy_buf)) if (IS_ERR(audio->copy_buf))
...@@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep) if (!ep)
goto fail; goto fail;
audio->out_ep = ep; audio->out_ep = ep;
audio->out_ep->desc = &as_out_ep_desc;
ep->driver_data = cdev; /* claim */ ep->driver_data = cdev; /* claim */
status = -ENOMEM; status = -ENOMEM;
...@@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c) ...@@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c)
audio->card.func.set_alt = f_audio_set_alt; audio->card.func.set_alt = f_audio_set_alt;
audio->card.func.setup = f_audio_setup; audio->card.func.setup = f_audio_setup;
audio->card.func.disable = f_audio_disable; audio->card.func.disable = f_audio_disable;
audio->out_desc = &as_out_ep_desc;
control_selector_init(audio); control_selector_init(audio);
......
...@@ -46,11 +46,6 @@ ...@@ -46,11 +46,6 @@
* and also means that a get_alt() method is required. * and also means that a get_alt() method is required.
*/ */
struct ecm_ep_descs {
struct usb_endpoint_descriptor *in;
struct usb_endpoint_descriptor *out;
struct usb_endpoint_descriptor *notify;
};
enum ecm_notify_state { enum ecm_notify_state {
ECM_NOTIFY_NONE, /* don't notify */ ECM_NOTIFY_NONE, /* don't notify */
...@@ -64,11 +59,7 @@ struct f_ecm { ...@@ -64,11 +59,7 @@ struct f_ecm {
char ethaddr[14]; char ethaddr[14];
struct ecm_ep_descs fs;
struct ecm_ep_descs hs;
struct usb_ep *notify; struct usb_ep *notify;
struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req; struct usb_request *notify_req;
u8 notify_state; u8 notify_state;
bool is_open; bool is_open;
...@@ -86,7 +77,9 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f) ...@@ -86,7 +77,9 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)
/* peak (theoretical) bulk transfer rate in bits-per-second */ /* peak (theoretical) bulk transfer rate in bits-per-second */
static inline unsigned ecm_bitrate(struct usb_gadget *g) static inline unsigned ecm_bitrate(struct usb_gadget *g)
{ {
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
return 13 * 1024 * 8 * 1000 * 8;
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return 13 * 512 * 8 * 1000 * 8; return 13 * 512 * 8 * 1000 * 8;
else else
return 19 * 64 * 1 * 1000 * 8; return 19 * 64 * 1 * 1000 * 8;
...@@ -219,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = { ...@@ -219,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = {
(struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc, (struct usb_descriptor_header *) &ecm_union_desc,
(struct usb_descriptor_header *) &ecm_desc, (struct usb_descriptor_header *) &ecm_desc,
/* NOTE: status endpoint might need to be removed */ /* NOTE: status endpoint might need to be removed */
(struct usb_descriptor_header *) &fs_ecm_notify_desc, (struct usb_descriptor_header *) &fs_ecm_notify_desc,
/* data interface, altsettings 0 and 1 */ /* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_nop_intf,
(struct usb_descriptor_header *) &ecm_data_intf, (struct usb_descriptor_header *) &ecm_data_intf,
...@@ -240,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = { ...@@ -240,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
}; };
static struct usb_endpoint_descriptor hs_ecm_in_desc = { static struct usb_endpoint_descriptor hs_ecm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
...@@ -264,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = { ...@@ -264,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
(struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc, (struct usb_descriptor_header *) &ecm_union_desc,
(struct usb_descriptor_header *) &ecm_desc, (struct usb_descriptor_header *) &ecm_desc,
/* NOTE: status endpoint might need to be removed */ /* NOTE: status endpoint might need to be removed */
(struct usb_descriptor_header *) &hs_ecm_notify_desc, (struct usb_descriptor_header *) &hs_ecm_notify_desc,
/* data interface, altsettings 0 and 1 */ /* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_nop_intf,
(struct usb_descriptor_header *) &ecm_data_intf, (struct usb_descriptor_header *) &ecm_data_intf,
...@@ -274,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = { ...@@ -274,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
NULL, NULL,
}; };
/* super speed support: */
static struct usb_endpoint_descriptor ss_ecm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
};
static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = {
.bLength = sizeof ss_ecm_intr_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* the following 3 values can be tweaked if necessary */
/* .bMaxBurst = 0, */
/* .bmAttributes = 0, */
.wBytesPerInterval = cpu_to_le16(ECM_STATUS_BYTECOUNT),
};
static struct usb_endpoint_descriptor ss_ecm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_endpoint_descriptor ss_ecm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = {
.bLength = sizeof ss_ecm_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* the following 2 values can be tweaked if necessary */
/* .bMaxBurst = 0, */
/* .bmAttributes = 0, */
};
static struct usb_descriptor_header *ecm_ss_function[] = {
/* CDC ECM control descriptors */
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
(struct usb_descriptor_header *) &ecm_desc,
/* NOTE: status endpoint might need to be removed */
(struct usb_descriptor_header *) &ss_ecm_notify_desc,
(struct usb_descriptor_header *) &ss_ecm_intr_comp_desc,
/* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &ecm_data_nop_intf,
(struct usb_descriptor_header *) &ecm_data_intf,
(struct usb_descriptor_header *) &ss_ecm_in_desc,
(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
(struct usb_descriptor_header *) &ss_ecm_out_desc,
(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
NULL,
};
/* string descriptors: */ /* string descriptors: */
static struct usb_string ecm_string_defs[] = { static struct usb_string ecm_string_defs[] = {
...@@ -464,13 +532,13 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -464,13 +532,13 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (ecm->notify->driver_data) { if (ecm->notify->driver_data) {
VDBG(cdev, "reset ecm control %d\n", intf); VDBG(cdev, "reset ecm control %d\n", intf);
usb_ep_disable(ecm->notify); usb_ep_disable(ecm->notify);
} else { }
if (!(ecm->notify->desc)) {
VDBG(cdev, "init ecm ctrl %d\n", intf); VDBG(cdev, "init ecm ctrl %d\n", intf);
ecm->notify_desc = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
ecm->hs.notify, goto fail;
ecm->fs.notify);
} }
usb_ep_enable(ecm->notify, ecm->notify_desc); usb_ep_enable(ecm->notify);
ecm->notify->driver_data = ecm; ecm->notify->driver_data = ecm;
/* Data interface has two altsettings, 0 and 1 */ /* Data interface has two altsettings, 0 and 1 */
...@@ -483,12 +551,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -483,12 +551,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
gether_disconnect(&ecm->port); gether_disconnect(&ecm->port);
} }
if (!ecm->port.in) { if (!ecm->port.in_ep->desc ||
!ecm->port.out_ep->desc) {
DBG(cdev, "init ecm\n"); DBG(cdev, "init ecm\n");
ecm->port.in = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f,
ecm->hs.in, ecm->fs.in); ecm->port.in_ep) ||
ecm->port.out = ep_choose(cdev->gadget, config_ep_by_speed(cdev->gadget, f,
ecm->hs.out, ecm->fs.out); ecm->port.out_ep)) {
ecm->port.in_ep->desc = NULL;
ecm->port.out_ep->desc = NULL;
goto fail;
}
} }
/* CDC Ethernet only sends data in non-default altsettings. /* CDC Ethernet only sends data in non-default altsettings.
...@@ -549,7 +622,7 @@ static void ecm_disable(struct usb_function *f) ...@@ -549,7 +622,7 @@ static void ecm_disable(struct usb_function *f)
if (ecm->notify->driver_data) { if (ecm->notify->driver_data) {
usb_ep_disable(ecm->notify); usb_ep_disable(ecm->notify);
ecm->notify->driver_data = NULL; ecm->notify->driver_data = NULL;
ecm->notify_desc = NULL; ecm->notify->desc = NULL;
} }
} }
...@@ -665,13 +738,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -665,13 +738,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
if (!f->descriptors) if (!f->descriptors)
goto fail; goto fail;
ecm->fs.in = usb_find_endpoint(ecm_fs_function,
f->descriptors, &fs_ecm_in_desc);
ecm->fs.out = usb_find_endpoint(ecm_fs_function,
f->descriptors, &fs_ecm_out_desc);
ecm->fs.notify = usb_find_endpoint(ecm_fs_function,
f->descriptors, &fs_ecm_notify_desc);
/* support all relevant hardware speeds... we expect that when /* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
* both speeds * both speeds
...@@ -688,13 +754,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -688,13 +754,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = usb_copy_descriptors(ecm_hs_function); f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
if (!f->hs_descriptors) if (!f->hs_descriptors)
goto fail; goto fail;
}
if (gadget_is_superspeed(c->cdev->gadget)) {
ss_ecm_in_desc.bEndpointAddress =
fs_ecm_in_desc.bEndpointAddress;
ss_ecm_out_desc.bEndpointAddress =
fs_ecm_out_desc.bEndpointAddress;
ss_ecm_notify_desc.bEndpointAddress =
fs_ecm_notify_desc.bEndpointAddress;
ecm->hs.in = usb_find_endpoint(ecm_hs_function, /* copy descriptors, and track endpoint copies */
f->hs_descriptors, &hs_ecm_in_desc); f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
ecm->hs.out = usb_find_endpoint(ecm_hs_function, if (!f->ss_descriptors)
f->hs_descriptors, &hs_ecm_out_desc); goto fail;
ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
f->hs_descriptors, &hs_ecm_notify_desc);
} }
/* NOTE: all that is done without knowing or caring about /* NOTE: all that is done without knowing or caring about
...@@ -706,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -706,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
ecm->port.close = ecm_close; ecm->port.close = ecm_close;
DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->port.in_ep->name, ecm->port.out_ep->name,
ecm->notify->name); ecm->notify->name);
...@@ -714,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -714,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
fail: fail:
if (f->descriptors) if (f->descriptors)
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);
if (f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors);
if (ecm->notify_req) { if (ecm->notify_req) {
kfree(ecm->notify_req->buf); kfree(ecm->notify_req->buf);
...@@ -723,9 +799,9 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -723,9 +799,9 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
/* we might as well release our claims on endpoints */ /* we might as well release our claims on endpoints */
if (ecm->notify) if (ecm->notify)
ecm->notify->driver_data = NULL; ecm->notify->driver_data = NULL;
if (ecm->port.out) if (ecm->port.out_ep->desc)
ecm->port.out_ep->driver_data = NULL; ecm->port.out_ep->driver_data = NULL;
if (ecm->port.in) if (ecm->port.in_ep->desc)
ecm->port.in_ep->driver_data = NULL; ecm->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
...@@ -740,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f) ...@@ -740,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
DBG(c->cdev, "ecm unbind\n"); DBG(c->cdev, "ecm unbind\n");
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);
......
...@@ -35,17 +35,9 @@ ...@@ -35,17 +35,9 @@
* Ethernet link. * Ethernet link.
*/ */
struct eem_ep_descs {
struct usb_endpoint_descriptor *in;
struct usb_endpoint_descriptor *out;
};
struct f_eem { struct f_eem {
struct gether port; struct gether port;
u8 ctrl_id; u8 ctrl_id;
struct eem_ep_descs fs;
struct eem_ep_descs hs;
}; };
static inline struct f_eem *func_to_eem(struct usb_function *f) static inline struct f_eem *func_to_eem(struct usb_function *f)
...@@ -123,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = { ...@@ -123,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {
NULL, NULL,
}; };
/* super speed support: */
static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = {
.bLength = sizeof eem_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* the following 2 values can be tweaked if necessary */
/* .bMaxBurst = 0, */
/* .bmAttributes = 0, */
};
static struct usb_descriptor_header *eem_ss_function[] __initdata = {
/* CDC EEM control descriptors */
(struct usb_descriptor_header *) &eem_intf,
(struct usb_descriptor_header *) &eem_ss_in_desc,
(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
(struct usb_descriptor_header *) &eem_ss_out_desc,
(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
NULL,
};
/* string descriptors: */ /* string descriptors: */
static struct usb_string eem_string_defs[] = { static struct usb_string eem_string_defs[] = {
...@@ -176,12 +207,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -176,12 +207,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
gether_disconnect(&eem->port); gether_disconnect(&eem->port);
} }
if (!eem->port.in) { if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
DBG(cdev, "init eem\n"); DBG(cdev, "init eem\n");
eem->port.in = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f,
eem->hs.in, eem->fs.in); eem->port.in_ep) ||
eem->port.out = ep_choose(cdev->gadget, config_ep_by_speed(cdev->gadget, f,
eem->hs.out, eem->fs.out); eem->port.out_ep)) {
eem->port.in_ep->desc = NULL;
eem->port.out_ep->desc = NULL;
goto fail;
}
} }
/* zlps should not occur because zero-length EEM packets /* zlps should not occur because zero-length EEM packets
...@@ -253,11 +288,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -253,11 +288,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
if (!f->descriptors) if (!f->descriptors)
goto fail; goto fail;
eem->fs.in = usb_find_endpoint(eem_fs_function,
f->descriptors, &eem_fs_in_desc);
eem->fs.out = usb_find_endpoint(eem_fs_function,
f->descriptors, &eem_fs_out_desc);
/* support all relevant hardware speeds... we expect that when /* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
* both speeds * both speeds
...@@ -272,14 +302,22 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -272,14 +302,22 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = usb_copy_descriptors(eem_hs_function); f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
if (!f->hs_descriptors) if (!f->hs_descriptors)
goto fail; goto fail;
}
eem->hs.in = usb_find_endpoint(eem_hs_function, if (gadget_is_superspeed(c->cdev->gadget)) {
f->hs_descriptors, &eem_hs_in_desc); eem_ss_in_desc.bEndpointAddress =
eem->hs.out = usb_find_endpoint(eem_hs_function, eem_fs_in_desc.bEndpointAddress;
f->hs_descriptors, &eem_hs_out_desc); eem_ss_out_desc.bEndpointAddress =
eem_fs_out_desc.bEndpointAddress;
/* copy descriptors, and track endpoint copies */
f->ss_descriptors = usb_copy_descriptors(eem_ss_function);
if (!f->ss_descriptors)
goto fail;
} }
DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
eem->port.in_ep->name, eem->port.out_ep->name); eem->port.in_ep->name, eem->port.out_ep->name);
return 0; return 0;
...@@ -287,11 +325,13 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -287,11 +325,13 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
fail: fail:
if (f->descriptors) if (f->descriptors)
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);
if (f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors);
/* we might as well release our claims on endpoints */ /* we might as well release our claims on endpoints */
if (eem->port.out) if (eem->port.out_ep->desc)
eem->port.out_ep->driver_data = NULL; eem->port.out_ep->driver_data = NULL;
if (eem->port.in) if (eem->port.in_ep->desc)
eem->port.in_ep->driver_data = NULL; eem->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
...@@ -306,6 +346,8 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f) ...@@ -306,6 +346,8 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
DBG(c->cdev, "eem unbind\n"); DBG(c->cdev, "eem unbind\n");
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);
......
...@@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func) ...@@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func)
ds = ep->descs[ep->descs[1] ? 1 : 0]; ds = ep->descs[ep->descs[1] ? 1 : 0];
ep->ep->driver_data = ep; ep->ep->driver_data = ep;
ret = usb_ep_enable(ep->ep, ds); ep->ep->desc = ds;
ret = usb_ep_enable(ep->ep);
if (likely(!ret)) { if (likely(!ret)) {
epfile->ep = ep; epfile->ep = ep;
epfile->in = usb_endpoint_dir_in(ds); epfile->in = usb_endpoint_dir_in(ds);
......
...@@ -59,8 +59,6 @@ struct f_hidg { ...@@ -59,8 +59,6 @@ struct f_hidg {
struct cdev cdev; struct cdev cdev;
struct usb_function func; struct usb_function func;
struct usb_ep *in_ep; struct usb_ep *in_ep;
struct usb_endpoint_descriptor *fs_in_ep_desc;
struct usb_endpoint_descriptor *hs_in_ep_desc;
}; };
static inline struct f_hidg *func_to_hidg(struct usb_function *f) static inline struct f_hidg *func_to_hidg(struct usb_function *f)
...@@ -416,7 +414,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -416,7 +414,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{ {
struct usb_composite_dev *cdev = f->config->cdev; struct usb_composite_dev *cdev = f->config->cdev;
struct f_hidg *hidg = func_to_hidg(f); struct f_hidg *hidg = func_to_hidg(f);
const struct usb_endpoint_descriptor *ep_desc;
int status = 0; int status = 0;
VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
...@@ -426,9 +423,13 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -426,9 +423,13 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (hidg->in_ep->driver_data != NULL) if (hidg->in_ep->driver_data != NULL)
usb_ep_disable(hidg->in_ep); usb_ep_disable(hidg->in_ep);
ep_desc = ep_choose(f->config->cdev->gadget, status = config_ep_by_speed(f->config->cdev->gadget, f,
hidg->hs_in_ep_desc, hidg->fs_in_ep_desc); hidg->in_ep);
status = usb_ep_enable(hidg->in_ep, ep_desc); if (status) {
ERROR(cdev, "config_ep_by_speed FAILED!\n");
goto fail;
}
status = usb_ep_enable(hidg->in_ep);
if (status < 0) { if (status < 0) {
ERROR(cdev, "Enable endpoint FAILED!\n"); ERROR(cdev, "Enable endpoint FAILED!\n");
goto fail; goto fail;
...@@ -498,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -498,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (!f->descriptors) if (!f->descriptors)
goto fail; goto fail;
hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
f->descriptors,
&hidg_fs_in_ep_desc);
if (gadget_is_dualspeed(c->cdev->gadget)) { if (gadget_is_dualspeed(c->cdev->gadget)) {
hidg_hs_in_ep_desc.bEndpointAddress = hidg_hs_in_ep_desc.bEndpointAddress =
hidg_fs_in_ep_desc.bEndpointAddress; hidg_fs_in_ep_desc.bEndpointAddress;
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors); f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
if (!f->hs_descriptors) if (!f->hs_descriptors)
goto fail; goto fail;
hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
f->hs_descriptors,
&hidg_hs_in_ep_desc);
} else {
hidg->hs_in_ep_desc = NULL;
} }
mutex_init(&hidg->lock); mutex_init(&hidg->lock);
......
...@@ -118,6 +118,49 @@ static struct usb_descriptor_header *hs_loopback_descs[] = { ...@@ -118,6 +118,49 @@ static struct usb_descriptor_header *hs_loopback_descs[] = {
NULL, NULL,
}; };
/* super speed support: */
static struct usb_endpoint_descriptor ss_loop_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
.bLength = USB_DT_SS_EP_COMP_SIZE,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
};
static struct usb_endpoint_descriptor ss_loop_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
.bLength = USB_DT_SS_EP_COMP_SIZE,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
};
static struct usb_descriptor_header *ss_loopback_descs[] = {
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &ss_loop_source_desc,
(struct usb_descriptor_header *) &ss_loop_source_comp_desc,
(struct usb_descriptor_header *) &ss_loop_sink_desc,
(struct usb_descriptor_header *) &ss_loop_sink_comp_desc,
NULL,
};
/* function-specific strings: */ /* function-specific strings: */
static struct usb_string strings_loopback[] = { static struct usb_string strings_loopback[] = {
...@@ -175,8 +218,18 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -175,8 +218,18 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = hs_loopback_descs; f->hs_descriptors = hs_loopback_descs;
} }
/* support super speed hardware */
if (gadget_is_superspeed(c->cdev->gadget)) {
ss_loop_source_desc.bEndpointAddress =
fs_loop_source_desc.bEndpointAddress;
ss_loop_sink_desc.bEndpointAddress =
fs_loop_sink_desc.bEndpointAddress;
f->ss_descriptors = ss_loopback_descs;
}
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", (gadget_is_superspeed(c->cdev->gadget) ? "super" :
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
f->name, loop->in_ep->name, loop->out_ep->name); f->name, loop->in_ep->name, loop->out_ep->name);
return 0; return 0;
} }
...@@ -250,26 +303,27 @@ static int ...@@ -250,26 +303,27 @@ static int
enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
{ {
int result = 0; int result = 0;
const struct usb_endpoint_descriptor *src, *sink;
struct usb_ep *ep; struct usb_ep *ep;
struct usb_request *req; struct usb_request *req;
unsigned i; unsigned i;
src = ep_choose(cdev->gadget,
&hs_loop_source_desc, &fs_loop_source_desc);
sink = ep_choose(cdev->gadget,
&hs_loop_sink_desc, &fs_loop_sink_desc);
/* one endpoint writes data back IN to the host */ /* one endpoint writes data back IN to the host */
ep = loop->in_ep; ep = loop->in_ep;
result = usb_ep_enable(ep, src); result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
return result;
result = usb_ep_enable(ep);
if (result < 0) if (result < 0)
return result; return result;
ep->driver_data = loop; ep->driver_data = loop;
/* one endpoint just reads OUT packets */ /* one endpoint just reads OUT packets */
ep = loop->out_ep; ep = loop->out_ep;
result = usb_ep_enable(ep, sink); result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
goto fail0;
result = usb_ep_enable(ep);
if (result < 0) { if (result < 0) {
fail0: fail0:
ep = loop->in_ep; ep = loop->in_ep;
......
...@@ -2324,18 +2324,6 @@ static int get_next_command(struct fsg_common *common) ...@@ -2324,18 +2324,6 @@ static int get_next_command(struct fsg_common *common)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
const struct usb_endpoint_descriptor *d)
{
int rc;
ep->driver_data = common;
rc = usb_ep_enable(ep, d);
if (rc)
ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
return rc;
}
static int alloc_request(struct fsg_common *common, struct usb_ep *ep, static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
struct usb_request **preq) struct usb_request **preq)
{ {
...@@ -2349,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep, ...@@ -2349,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
/* Reset interface setting and re-init endpoint state (toggle etc). */ /* Reset interface setting and re-init endpoint state (toggle etc). */
static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
{ {
const struct usb_endpoint_descriptor *d;
struct fsg_dev *fsg; struct fsg_dev *fsg;
int i, rc = 0; int i, rc = 0;
...@@ -2396,20 +2383,26 @@ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) ...@@ -2396,20 +2383,26 @@ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
fsg = common->fsg; fsg = common->fsg;
/* Enable the endpoints */ /* Enable the endpoints */
d = fsg_ep_desc(common->gadget, rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); if (rc)
rc = enable_endpoint(common, fsg->bulk_in, d); goto reset;
rc = usb_ep_enable(fsg->bulk_in);
if (rc) if (rc)
goto reset; goto reset;
fsg->bulk_in->driver_data = common;
fsg->bulk_in_enabled = 1; fsg->bulk_in_enabled = 1;
d = fsg_ep_desc(common->gadget, rc = config_ep_by_speed(common->gadget, &(fsg->function),
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); fsg->bulk_out);
rc = enable_endpoint(common, fsg->bulk_out, d); if (rc)
goto reset;
rc = usb_ep_enable(fsg->bulk_out);
if (rc) if (rc)
goto reset; goto reset;
fsg->bulk_out->driver_data = common;
fsg->bulk_out_enabled = 1; fsg->bulk_out_enabled = 1;
common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); common->bulk_out_maxpacket =
le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
/* Allocate the requests */ /* Allocate the requests */
......
...@@ -48,12 +48,6 @@ ...@@ -48,12 +48,6 @@
#define NCM_NDP_HDR_CRC 0x01000000 #define NCM_NDP_HDR_CRC 0x01000000
#define NCM_NDP_HDR_NOCRC 0x00000000 #define NCM_NDP_HDR_NOCRC 0x00000000
struct ncm_ep_descs {
struct usb_endpoint_descriptor *in;
struct usb_endpoint_descriptor *out;
struct usb_endpoint_descriptor *notify;
};
enum ncm_notify_state { enum ncm_notify_state {
NCM_NOTIFY_NONE, /* don't notify */ NCM_NOTIFY_NONE, /* don't notify */
NCM_NOTIFY_CONNECT, /* issue CONNECT next */ NCM_NOTIFY_CONNECT, /* issue CONNECT next */
...@@ -66,11 +60,7 @@ struct f_ncm { ...@@ -66,11 +60,7 @@ struct f_ncm {
char ethaddr[14]; char ethaddr[14];
struct ncm_ep_descs fs;
struct ncm_ep_descs hs;
struct usb_ep *notify; struct usb_ep *notify;
struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req; struct usb_request *notify_req;
u8 notify_state; u8 notify_state;
bool is_open; bool is_open;
...@@ -802,13 +792,14 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -802,13 +792,14 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (ncm->notify->driver_data) { if (ncm->notify->driver_data) {
DBG(cdev, "reset ncm control %d\n", intf); DBG(cdev, "reset ncm control %d\n", intf);
usb_ep_disable(ncm->notify); usb_ep_disable(ncm->notify);
} else { }
if (!(ncm->notify->desc)) {
DBG(cdev, "init ncm ctrl %d\n", intf); DBG(cdev, "init ncm ctrl %d\n", intf);
ncm->notify_desc = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
ncm->hs.notify, goto fail;
ncm->fs.notify);
} }
usb_ep_enable(ncm->notify, ncm->notify_desc); usb_ep_enable(ncm->notify);
ncm->notify->driver_data = ncm; ncm->notify->driver_data = ncm;
/* Data interface has two altsettings, 0 and 1 */ /* Data interface has two altsettings, 0 and 1 */
...@@ -829,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -829,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt == 1) { if (alt == 1) {
struct net_device *net; struct net_device *net;
if (!ncm->port.in) { if (!ncm->port.in_ep->desc ||
!ncm->port.out_ep->desc) {
DBG(cdev, "init ncm\n"); DBG(cdev, "init ncm\n");
ncm->port.in = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f,
ncm->hs.in, ncm->port.in_ep) ||
ncm->fs.in); config_ep_by_speed(cdev->gadget, f,
ncm->port.out = ep_choose(cdev->gadget, ncm->port.out_ep)) {
ncm->hs.out, ncm->port.in_ep->desc = NULL;
ncm->fs.out); ncm->port.out_ep->desc = NULL;
goto fail;
}
} }
/* TODO */ /* TODO */
...@@ -1111,7 +1105,7 @@ static void ncm_disable(struct usb_function *f) ...@@ -1111,7 +1105,7 @@ static void ncm_disable(struct usb_function *f)
if (ncm->notify->driver_data) { if (ncm->notify->driver_data) {
usb_ep_disable(ncm->notify); usb_ep_disable(ncm->notify);
ncm->notify->driver_data = NULL; ncm->notify->driver_data = NULL;
ncm->notify_desc = NULL; ncm->notify->desc = NULL;
} }
} }
...@@ -1228,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -1228,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
if (!f->descriptors) if (!f->descriptors)
goto fail; goto fail;
ncm->fs.in = usb_find_endpoint(ncm_fs_function,
f->descriptors, &fs_ncm_in_desc);
ncm->fs.out = usb_find_endpoint(ncm_fs_function,
f->descriptors, &fs_ncm_out_desc);
ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
f->descriptors, &fs_ncm_notify_desc);
/* /*
* support all relevant hardware speeds... we expect that when * support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
...@@ -1252,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -1252,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = usb_copy_descriptors(ncm_hs_function); f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
if (!f->hs_descriptors) if (!f->hs_descriptors)
goto fail; goto fail;
ncm->hs.in = usb_find_endpoint(ncm_hs_function,
f->hs_descriptors, &hs_ncm_in_desc);
ncm->hs.out = usb_find_endpoint(ncm_hs_function,
f->hs_descriptors, &hs_ncm_out_desc);
ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
f->hs_descriptors, &hs_ncm_notify_desc);
} }
/* /*
...@@ -1288,9 +1268,9 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -1288,9 +1268,9 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
/* we might as well release our claims on endpoints */ /* we might as well release our claims on endpoints */
if (ncm->notify) if (ncm->notify)
ncm->notify->driver_data = NULL; ncm->notify->driver_data = NULL;
if (ncm->port.out) if (ncm->port.out_ep->desc)
ncm->port.out_ep->driver_data = NULL; ncm->port.out_ep->driver_data = NULL;
if (ncm->port.in) if (ncm->port.in_ep->desc)
ncm->port.in_ep->driver_data = NULL; ncm->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
......
...@@ -39,20 +39,12 @@ ...@@ -39,20 +39,12 @@
* ready to handle the commands. * ready to handle the commands.
*/ */
struct obex_ep_descs {
struct usb_endpoint_descriptor *obex_in;
struct usb_endpoint_descriptor *obex_out;
};
struct f_obex { struct f_obex {
struct gserial port; struct gserial port;
u8 ctrl_id; u8 ctrl_id;
u8 data_id; u8 data_id;
u8 port_num; u8 port_num;
u8 can_activate; u8 can_activate;
struct obex_ep_descs fs;
struct obex_ep_descs hs;
}; };
static inline struct f_obex *func_to_obex(struct usb_function *f) static inline struct f_obex *func_to_obex(struct usb_function *f)
...@@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
gserial_disconnect(&obex->port); gserial_disconnect(&obex->port);
} }
if (!obex->port.in_desc) { if (!obex->port.in->desc || !obex->port.out->desc) {
DBG(cdev, "init obex ttyGS%d\n", obex->port_num); DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
obex->port.in_desc = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f,
obex->hs.obex_in, obex->fs.obex_in); obex->port.in) ||
obex->port.out_desc = ep_choose(cdev->gadget, config_ep_by_speed(cdev->gadget, f,
obex->hs.obex_out, obex->fs.obex_out); obex->port.out)) {
obex->port.out->desc = NULL;
obex->port.in->desc = NULL;
goto fail;
}
} }
if (alt == 1) { if (alt == 1) {
...@@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors, and track endpoint copies */ /* copy descriptors, and track endpoint copies */
f->descriptors = usb_copy_descriptors(fs_function); f->descriptors = usb_copy_descriptors(fs_function);
obex->fs.obex_in = usb_find_endpoint(fs_function,
f->descriptors, &obex_fs_ep_in_desc);
obex->fs.obex_out = usb_find_endpoint(fs_function,
f->descriptors, &obex_fs_ep_out_desc);
/* support all relevant hardware speeds... we expect that when /* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
* both speeds * both speeds
...@@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors, and track endpoint copies */ /* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(hs_function); f->hs_descriptors = usb_copy_descriptors(hs_function);
obex->hs.obex_in = usb_find_endpoint(hs_function,
f->hs_descriptors, &obex_hs_ep_in_desc);
obex->hs.obex_out = usb_find_endpoint(hs_function,
f->hs_descriptors, &obex_hs_ep_out_desc);
} }
/* Avoid letting this gadget enumerate until the userspace /* Avoid letting this gadget enumerate until the userspace
......
...@@ -428,17 +428,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -428,17 +428,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
spin_lock(&port->lock); spin_lock(&port->lock);
__pn_reset(f); __pn_reset(f);
if (alt == 1) { if (alt == 1) {
struct usb_endpoint_descriptor *out, *in;
int i; int i;
out = ep_choose(gadget, if (config_ep_by_speed(gadget, f, fp->in_ep) ||
&pn_hs_sink_desc, config_ep_by_speed(gadget, f, fp->out_ep)) {
&pn_fs_sink_desc); fp->in_ep->desc = NULL;
in = ep_choose(gadget, fp->out_ep->desc = NULL;
&pn_hs_source_desc, return -EINVAL;
&pn_fs_source_desc); }
usb_ep_enable(fp->out_ep, out); usb_ep_enable(fp->out_ep);
usb_ep_enable(fp->in_ep, in); usb_ep_enable(fp->in_ep);
port->usb = fp; port->usb = fp;
fp->out_ep->driver_data = fp; fp->out_ep->driver_data = fp;
......
...@@ -76,23 +76,13 @@ ...@@ -76,23 +76,13 @@
* - MS-Windows drivers sometimes emit undocumented requests. * - MS-Windows drivers sometimes emit undocumented requests.
*/ */
struct rndis_ep_descs {
struct usb_endpoint_descriptor *in;
struct usb_endpoint_descriptor *out;
struct usb_endpoint_descriptor *notify;
};
struct f_rndis { struct f_rndis {
struct gether port; struct gether port;
u8 ctrl_id, data_id; u8 ctrl_id, data_id;
u8 ethaddr[ETH_ALEN]; u8 ethaddr[ETH_ALEN];
int config; int config;
struct rndis_ep_descs fs;
struct rndis_ep_descs hs;
struct usb_ep *notify; struct usb_ep *notify;
struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req; struct usb_request *notify_req;
atomic_t notify_count; atomic_t notify_count;
}; };
...@@ -105,7 +95,9 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f) ...@@ -105,7 +95,9 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)
/* peak (theoretical) bulk transfer rate in bits-per-second */ /* peak (theoretical) bulk transfer rate in bits-per-second */
static unsigned int bitrate(struct usb_gadget *g) static unsigned int bitrate(struct usb_gadget *g)
{ {
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
return 13 * 1024 * 8 * 1000 * 8;
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return 13 * 512 * 8 * 1000 * 8; return 13 * 512 * 8 * 1000 * 8;
else else
return 19 * 64 * 1 * 1000 * 8; return 19 * 64 * 1 * 1000 * 8;
...@@ -226,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = { ...@@ -226,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = {
static struct usb_descriptor_header *eth_fs_function[] = { static struct usb_descriptor_header *eth_fs_function[] = {
(struct usb_descriptor_header *) &rndis_iad_descriptor, (struct usb_descriptor_header *) &rndis_iad_descriptor,
/* control interface matches ACM, not Ethernet */ /* control interface matches ACM, not Ethernet */
(struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &rndis_control_intf,
(struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &header_desc,
...@@ -233,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = { ...@@ -233,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = {
(struct usb_descriptor_header *) &rndis_acm_descriptor, (struct usb_descriptor_header *) &rndis_acm_descriptor,
(struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &rndis_union_desc,
(struct usb_descriptor_header *) &fs_notify_desc, (struct usb_descriptor_header *) &fs_notify_desc,
/* data interface has no altsetting */ /* data interface has no altsetting */
(struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &rndis_data_intf,
(struct usb_descriptor_header *) &fs_in_desc, (struct usb_descriptor_header *) &fs_in_desc,
...@@ -251,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = { ...@@ -251,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
}; };
static struct usb_endpoint_descriptor hs_in_desc = { static struct usb_endpoint_descriptor hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
...@@ -271,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = { ...@@ -271,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = {
static struct usb_descriptor_header *eth_hs_function[] = { static struct usb_descriptor_header *eth_hs_function[] = {
(struct usb_descriptor_header *) &rndis_iad_descriptor, (struct usb_descriptor_header *) &rndis_iad_descriptor,
/* control interface matches ACM, not Ethernet */ /* control interface matches ACM, not Ethernet */
(struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &rndis_control_intf,
(struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &header_desc,
...@@ -278,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = { ...@@ -278,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = {
(struct usb_descriptor_header *) &rndis_acm_descriptor, (struct usb_descriptor_header *) &rndis_acm_descriptor,
(struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &rndis_union_desc,
(struct usb_descriptor_header *) &hs_notify_desc, (struct usb_descriptor_header *) &hs_notify_desc,
/* data interface has no altsetting */ /* data interface has no altsetting */
(struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &rndis_data_intf,
(struct usb_descriptor_header *) &hs_in_desc, (struct usb_descriptor_header *) &hs_in_desc,
...@@ -285,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = { ...@@ -285,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = {
NULL, NULL,
}; };
/* super speed support: */
static struct usb_endpoint_descriptor ss_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
};
static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
.bLength = sizeof ss_intr_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* the following 3 values can be tweaked if necessary */
/* .bMaxBurst = 0, */
/* .bmAttributes = 0, */
.wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
};
static struct usb_endpoint_descriptor ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_endpoint_descriptor ss_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
.bLength = sizeof ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* the following 2 values can be tweaked if necessary */
/* .bMaxBurst = 0, */
/* .bmAttributes = 0, */
};
static struct usb_descriptor_header *eth_ss_function[] = {
(struct usb_descriptor_header *) &rndis_iad_descriptor,
/* control interface matches ACM, not Ethernet */
(struct usb_descriptor_header *) &rndis_control_intf,
(struct usb_descriptor_header *) &header_desc,
(struct usb_descriptor_header *) &call_mgmt_descriptor,
(struct usb_descriptor_header *) &rndis_acm_descriptor,
(struct usb_descriptor_header *) &rndis_union_desc,
(struct usb_descriptor_header *) &ss_notify_desc,
(struct usb_descriptor_header *) &ss_intr_comp_desc,
/* data interface has no altsetting */
(struct usb_descriptor_header *) &rndis_data_intf,
(struct usb_descriptor_header *) &ss_in_desc,
(struct usb_descriptor_header *) &ss_bulk_comp_desc,
(struct usb_descriptor_header *) &ss_out_desc,
(struct usb_descriptor_header *) &ss_bulk_comp_desc,
NULL,
};
/* string descriptors: */ /* string descriptors: */
static struct usb_string rndis_string_defs[] = { static struct usb_string rndis_string_defs[] = {
...@@ -484,13 +551,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -484,13 +551,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (rndis->notify->driver_data) { if (rndis->notify->driver_data) {
VDBG(cdev, "reset rndis control %d\n", intf); VDBG(cdev, "reset rndis control %d\n", intf);
usb_ep_disable(rndis->notify); usb_ep_disable(rndis->notify);
} else { }
if (!rndis->notify->desc) {
VDBG(cdev, "init rndis ctrl %d\n", intf); VDBG(cdev, "init rndis ctrl %d\n", intf);
rndis->notify_desc = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
rndis->hs.notify, goto fail;
rndis->fs.notify);
} }
usb_ep_enable(rndis->notify, rndis->notify_desc); usb_ep_enable(rndis->notify);
rndis->notify->driver_data = rndis; rndis->notify->driver_data = rndis;
} else if (intf == rndis->data_id) { } else if (intf == rndis->data_id) {
...@@ -501,12 +568,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ...@@ -501,12 +568,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
gether_disconnect(&rndis->port); gether_disconnect(&rndis->port);
} }
if (!rndis->port.in) { if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
DBG(cdev, "init rndis\n"); DBG(cdev, "init rndis\n");
rndis->port.in = ep_choose(cdev->gadget, if (config_ep_by_speed(cdev->gadget, f,
rndis->hs.in, rndis->fs.in); rndis->port.in_ep) ||
rndis->port.out = ep_choose(cdev->gadget, config_ep_by_speed(cdev->gadget, f,
rndis->hs.out, rndis->fs.out); rndis->port.out_ep)) {
rndis->port.in_ep->desc = NULL;
rndis->port.out_ep->desc = NULL;
goto fail;
}
} }
/* Avoid ZLPs; they can be troublesome. */ /* Avoid ZLPs; they can be troublesome. */
...@@ -662,13 +733,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -662,13 +733,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
if (!f->descriptors) if (!f->descriptors)
goto fail; goto fail;
rndis->fs.in = usb_find_endpoint(eth_fs_function,
f->descriptors, &fs_in_desc);
rndis->fs.out = usb_find_endpoint(eth_fs_function,
f->descriptors, &fs_out_desc);
rndis->fs.notify = usb_find_endpoint(eth_fs_function,
f->descriptors, &fs_notify_desc);
/* support all relevant hardware speeds... we expect that when /* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
* both speeds * both speeds
...@@ -683,16 +747,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -683,16 +747,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors, and track endpoint copies */ /* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(eth_hs_function); f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
if (!f->hs_descriptors) if (!f->hs_descriptors)
goto fail; goto fail;
}
if (gadget_is_superspeed(c->cdev->gadget)) {
ss_in_desc.bEndpointAddress =
fs_in_desc.bEndpointAddress;
ss_out_desc.bEndpointAddress =
fs_out_desc.bEndpointAddress;
ss_notify_desc.bEndpointAddress =
fs_notify_desc.bEndpointAddress;
rndis->hs.in = usb_find_endpoint(eth_hs_function, /* copy descriptors, and track endpoint copies */
f->hs_descriptors, &hs_in_desc); f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
rndis->hs.out = usb_find_endpoint(eth_hs_function, if (!f->ss_descriptors)
f->hs_descriptors, &hs_out_desc); goto fail;
rndis->hs.notify = usb_find_endpoint(eth_hs_function,
f->hs_descriptors, &hs_notify_desc);
} }
rndis->port.open = rndis_open; rndis->port.open = rndis_open;
...@@ -719,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -719,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
*/ */
DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->port.in_ep->name, rndis->port.out_ep->name,
rndis->notify->name); rndis->notify->name);
return 0; return 0;
fail: fail:
if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
if (f->descriptors) if (f->descriptors)
...@@ -738,9 +811,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -738,9 +811,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
/* we might as well release our claims on endpoints */ /* we might as well release our claims on endpoints */
if (rndis->notify) if (rndis->notify)
rndis->notify->driver_data = NULL; rndis->notify->driver_data = NULL;
if (rndis->port.out) if (rndis->port.out_ep->desc)
rndis->port.out_ep->driver_data = NULL; rndis->port.out_ep->driver_data = NULL;
if (rndis->port.in) if (rndis->port.in_ep->desc)
rndis->port.in_ep->driver_data = NULL; rndis->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
...@@ -756,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) ...@@ -756,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_deregister(rndis->config); rndis_deregister(rndis->config);
rndis_exit(); rndis_exit();
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) ...@@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_CONNECTED) if (uvc->state != UVC_STATE_CONNECTED)
return 0; return 0;
if (uvc->video.ep) if (uvc->video.ep) {
usb_ep_enable(uvc->video.ep, &uvc_streaming_ep); uvc->video.ep->desc = &uvc_streaming_ep;
usb_ep_enable(uvc->video.ep);
}
memset(&v4l2_event, 0, sizeof(v4l2_event)); memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event.type = UVC_EVENT_STREAMON;
...@@ -649,7 +651,7 @@ uvc_bind_config(struct usb_configuration *c, ...@@ -649,7 +651,7 @@ uvc_bind_config(struct usb_configuration *c,
if (ret) if (ret)
kfree(uvc); kfree(uvc);
return 0; return ret;
error: error:
kfree(uvc); kfree(uvc);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -162,6 +162,7 @@ static struct usb_composite_driver gfs_driver = { ...@@ -162,6 +162,7 @@ static struct usb_composite_driver gfs_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.dev = &gfs_dev_desc, .dev = &gfs_dev_desc,
.strings = gfs_dev_strings, .strings = gfs_dev_strings,
.max_speed = USB_SPEED_HIGH,
.unbind = gfs_unbind, .unbind = gfs_unbind,
.iProduct = DRIVER_DESC, .iProduct = DRIVER_DESC,
}; };
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册