mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 02:36:21 +00:00
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
This commit is contained in:
commit
f549953c15
@ -10,3 +10,26 @@ KernelVersion: 2.6.35
|
||||
Contact: masa-korg@dsn.okisemi.com
|
||||
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
|
||||
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.
|
||||
unknown_nmi_panic
|
||||
[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=
|
||||
[USB] The autosuspend time delay (in seconds) used
|
||||
for newly-detected USB devices (default 2). This
|
||||
|
@ -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
|
||||
to trigger "high bandwidth" modes.
|
||||
|
||||
TBD: More than standard 80% periodic bandwidth allocation is possible
|
||||
through sysfs uframe_periodic_max parameter. Describe that.
|
||||
|
@ -81,8 +81,8 @@ Send and receive HID reports
|
||||
to do this.
|
||||
|
||||
hid_gadget_test is a small interactive program to test the HID
|
||||
gadget driver. To use, point it at a hidg device and set the
|
||||
device type (keyboard / mouse / joystick) - E.G.:
|
||||
gadget driver. To use, point it at a hidg device and set the
|
||||
device type (keyboard / mouse / joystick) - E.G.:
|
||||
|
||||
# hid_gadget_test /dev/hidg0 keyboard
|
||||
|
||||
@ -97,7 +97,7 @@ Send and receive HID reports
|
||||
HID gadget.
|
||||
|
||||
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
|
||||
to the caps lock LED status.
|
||||
|
||||
|
@ -33,8 +33,6 @@
|
||||
#include <plat/omap_device.h>
|
||||
#include "mux.h"
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
|
||||
|
||||
static struct musb_hdrc_config musb_config = {
|
||||
.multipoint = 1,
|
||||
.dyn_fifo = 1,
|
||||
@ -175,11 +173,3 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
|
||||
if (cpu_is_omap44xx())
|
||||
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 {
|
||||
u32 address;
|
||||
u16 offset;
|
||||
u32 data;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
struct uea_cmvs_v2 {
|
||||
u32 group;
|
||||
u32 address;
|
||||
u32 offset;
|
||||
u32 data;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
/* information about currently processed cmv */
|
||||
struct cmv_dsc_e1 {
|
||||
@ -352,7 +352,7 @@ struct block_index {
|
||||
__le32 PageAddress;
|
||||
__le16 dummy1;
|
||||
__le16 PageNumber;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
|
||||
#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
|
||||
@ -367,7 +367,7 @@ struct l1_code {
|
||||
u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
|
||||
struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
|
||||
u8 code[0];
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
/* structures describing a block within a DSP page */
|
||||
struct block_info_e1 {
|
||||
@ -377,7 +377,7 @@ struct block_info_e1 {
|
||||
__le16 wOvlOffset;
|
||||
__le16 wOvl; /* overlay */
|
||||
__le16 wLast;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
#define E1_BLOCK_INFO_SIZE 12
|
||||
|
||||
struct block_info_e4 {
|
||||
@ -387,7 +387,7 @@ struct block_info_e4 {
|
||||
__be32 dwSize;
|
||||
__be32 dwAddress;
|
||||
__be16 wReserved;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
#define E4_BLOCK_INFO_SIZE 14
|
||||
|
||||
#define UEA_BIHDR 0xabcd
|
||||
@ -467,7 +467,7 @@ struct cmv_e1 {
|
||||
__le32 dwSymbolicAddress;
|
||||
__le16 wOffsetAddress;
|
||||
__le32 dwData;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
struct cmv_e4 {
|
||||
__be16 wGroup;
|
||||
@ -475,17 +475,17 @@ struct cmv_e4 {
|
||||
__be16 wOffset;
|
||||
__be16 wAddress;
|
||||
__be32 dwData[6];
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
/* structures representing swap information */
|
||||
struct swap_info_e1 {
|
||||
__u8 bSwapPageNo;
|
||||
__u8 bOvl; /* overlay */
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
struct swap_info_e4 {
|
||||
__u8 bSwapPageNo;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
/* structures representing interrupt data */
|
||||
#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
|
||||
@ -499,23 +499,23 @@ union intr_data_e1 {
|
||||
struct {
|
||||
struct swap_info_e1 swapinfo;
|
||||
__le16 wDataSize;
|
||||
} __attribute__ ((packed)) s1;
|
||||
} __packed s1;
|
||||
struct {
|
||||
struct cmv_e1 cmv;
|
||||
__le16 wDataSize;
|
||||
} __attribute__ ((packed)) s2;
|
||||
} __attribute__ ((packed));
|
||||
} __packed s2;
|
||||
} __packed;
|
||||
|
||||
union intr_data_e4 {
|
||||
struct {
|
||||
struct swap_info_e4 swapinfo;
|
||||
__le16 wDataSize;
|
||||
} __attribute__ ((packed)) s1;
|
||||
} __packed s1;
|
||||
struct {
|
||||
struct cmv_e4 cmv;
|
||||
__le16 wDataSize;
|
||||
} __attribute__ ((packed)) s2;
|
||||
} __attribute__ ((packed));
|
||||
} __packed s2;
|
||||
} __packed;
|
||||
|
||||
struct intr_pkt {
|
||||
__u8 bType;
|
||||
@ -528,15 +528,15 @@ struct intr_pkt {
|
||||
union intr_data_e1 e1;
|
||||
union intr_data_e4 e4;
|
||||
} u;
|
||||
} __attribute__ ((packed));
|
||||
} __packed;
|
||||
|
||||
#define E1_INTR_PKT_SIZE 28
|
||||
#define E4_INTR_PKT_SIZE 64
|
||||
|
||||
static struct usb_driver uea_driver;
|
||||
static DEFINE_MUTEX(uea_mutex);
|
||||
static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III",
|
||||
"Eagle IV"};
|
||||
static const char * const chip_name[] = {
|
||||
"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
|
||||
|
||||
static int modem_index;
|
||||
static unsigned int debug;
|
||||
|
@ -81,6 +81,7 @@
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
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)
|
||||
/* racy disconnection check - fine */
|
||||
if (!instance || instance->disconnected) {
|
||||
#ifdef DEBUG
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
|
||||
printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
|
||||
#endif
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#undef DEBUG
|
||||
#include <linux/usb.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
@ -348,8 +349,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
|
||||
mutex_lock(&usblp->mut);
|
||||
if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
|
||||
mutex_unlock(&usblp->mut);
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_ERR
|
||||
printk_ratelimited(KERN_ERR
|
||||
"usblp%d: error %d reading printer status\n",
|
||||
usblp->minor, error);
|
||||
return 0;
|
||||
@ -653,8 +653,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
|
||||
case LPGETSTATUS:
|
||||
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_ERR "usblp%d:"
|
||||
printk_ratelimited(KERN_ERR "usblp%d:"
|
||||
"failed reading printer status (%d)\n",
|
||||
usblp->minor, retval);
|
||||
retval = -EIO;
|
||||
|
@ -337,6 +337,17 @@ static const u8 ss_rh_config_descriptor[] = {
|
||||
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,
|
||||
|
||||
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
|
||||
|
||||
hcd->authorized_default = hcd->wireless? 0 : 1;
|
||||
/* 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;
|
||||
else
|
||||
hcd->authorized_default = authorized_default;
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* HC is in reset state, but accessible. Now do the one-time init,
|
||||
|
@ -96,9 +96,6 @@ config USB_GADGET_VBUS_DRAW
|
||||
This value will be used except for system-specific gadget
|
||||
drivers that have more specific information.
|
||||
|
||||
config USB_GADGET_SELECTED
|
||||
boolean
|
||||
|
||||
#
|
||||
# USB Peripheral Controller Support
|
||||
#
|
||||
@ -122,10 +119,9 @@ choice
|
||||
# Integrated controllers
|
||||
#
|
||||
|
||||
config USB_GADGET_AT91
|
||||
boolean "Atmel AT91 USB Device Port"
|
||||
config USB_AT91
|
||||
tristate "Atmel AT91 USB Device Port"
|
||||
depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
|
||||
select USB_GADGET_SELECTED
|
||||
help
|
||||
Many Atmel AT91 processors (such as the AT91RM2000) have a
|
||||
full speed USB Device Port with support for five configurable
|
||||
@ -135,27 +131,16 @@ config USB_GADGET_AT91
|
||||
dynamically linked module called "at91_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_AT91
|
||||
tristate
|
||||
depends on USB_GADGET_AT91
|
||||
default USB_GADGET
|
||||
|
||||
config USB_GADGET_ATMEL_USBA
|
||||
boolean "Atmel USBA"
|
||||
config USB_ATMEL_USBA
|
||||
tristate "Atmel USBA"
|
||||
select USB_GADGET_DUALSPEED
|
||||
depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
|
||||
help
|
||||
USBA is the integrated high-speed USB Device controller on
|
||||
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
|
||||
|
||||
config USB_ATMEL_USBA
|
||||
tristate
|
||||
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"
|
||||
config USB_FSL_USB2
|
||||
tristate "Freescale Highspeed USB DR Peripheral Controller"
|
||||
depends on FSL_SOC || ARCH_MXC
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_FSL_MPH_DR_OF if OF
|
||||
@ -170,26 +155,15 @@ config USB_GADGET_FSL_USB2
|
||||
dynamically linked module called "fsl_usb2_udc" and force
|
||||
all gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_FSL_USB2
|
||||
tristate
|
||||
depends on USB_GADGET_FSL_USB2
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_FUSB300
|
||||
boolean "Faraday FUSB300 USB Peripheral Controller"
|
||||
config USB_FUSB300
|
||||
tristate "Faraday FUSB300 USB Peripheral Controller"
|
||||
depends on !PHYS_ADDR_T_64BIT
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Faraday usb device controller FUSB300 driver
|
||||
|
||||
config USB_FUSB300
|
||||
tristate
|
||||
depends on USB_GADGET_FUSB300
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_OMAP
|
||||
boolean "OMAP USB Device Controller"
|
||||
config USB_OMAP
|
||||
tristate "OMAP USB Device Controller"
|
||||
depends on ARCH_OMAP
|
||||
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
|
||||
select USB_OTG_UTILS if ARCH_OMAP
|
||||
@ -204,14 +178,8 @@ config USB_GADGET_OMAP
|
||||
dynamically linked module called "omap_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_OMAP
|
||||
tristate
|
||||
depends on USB_GADGET_OMAP
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA25X
|
||||
boolean "PXA 25x or IXP 4xx"
|
||||
config USB_PXA25X
|
||||
tristate "PXA 25x or IXP 4xx"
|
||||
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
@ -226,24 +194,18 @@ config USB_GADGET_PXA25X
|
||||
dynamically linked module called "pxa25x_udc" and force all
|
||||
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,
|
||||
# don't waste memory for the other endpoints
|
||||
config USB_PXA25X_SMALL
|
||||
depends on USB_GADGET_PXA25X
|
||||
depends on USB_PXA25X
|
||||
bool
|
||||
default n if USB_ETH_RNDIS
|
||||
default y if USB_ZERO
|
||||
default y if USB_ETH
|
||||
default y if USB_G_SERIAL
|
||||
|
||||
config USB_GADGET_R8A66597
|
||||
boolean "Renesas R8A66597 USB Peripheral Controller"
|
||||
config USB_R8A66597
|
||||
tristate "Renesas R8A66597 USB Peripheral Controller"
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
R8A66597 is a discrete USB host and peripheral controller chip that
|
||||
@ -254,32 +216,22 @@ config USB_GADGET_R8A66597
|
||||
dynamically linked module called "r8a66597_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_R8A66597
|
||||
tristate
|
||||
depends on USB_GADGET_R8A66597
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_RENESAS_USBHS
|
||||
boolean "Renesas USBHS"
|
||||
config USB_RENESAS_USBHS_UDC
|
||||
tristate 'Renesas USBHS controller'
|
||||
depends on SUPERH || ARCH_SHMOBILE
|
||||
depends on USB_RENESAS_USBHS
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Renesas USBHS is a discrete USB host and peripheral controller
|
||||
chip that supports both full and high speed USB 2.0 data transfers.
|
||||
platform is able to configure endpoint (pipe) style
|
||||
Renesas USBHS is a discrete USB host and peripheral controller chip
|
||||
that supports both full and high speed USB 2.0 data transfers.
|
||||
It has nine or more configurable endpoints, and endpoint zero.
|
||||
|
||||
Say "y" to enable the gadget specific portion of the USBHS driver.
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "renesas_usbhs" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
|
||||
config USB_RENESAS_USBHS_UDC
|
||||
tristate
|
||||
depends on USB_GADGET_RENESAS_USBHS
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA27X
|
||||
boolean "PXA 27x"
|
||||
config USB_PXA27X
|
||||
tristate "PXA 27x"
|
||||
depends on ARCH_PXA && (PXA27x || PXA3xx)
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
@ -293,14 +245,8 @@ config USB_GADGET_PXA27X
|
||||
dynamically linked module called "pxa27x_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_PXA27X
|
||||
tristate
|
||||
depends on USB_GADGET_PXA27X
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_S3C_HSOTG
|
||||
boolean "S3C HS/OtG USB Device controller"
|
||||
config USB_S3C_HSOTG
|
||||
tristate "S3C HS/OtG USB Device controller"
|
||||
depends on S3C_DEV_USB_HSOTG
|
||||
select USB_GADGET_S3C_HSOTG_PIO
|
||||
select USB_GADGET_DUALSPEED
|
||||
@ -308,14 +254,8 @@ config USB_GADGET_S3C_HSOTG
|
||||
The Samsung S3C64XX USB2.0 high-speed gadget controller
|
||||
integrated into the S3C64XX series SoC.
|
||||
|
||||
config USB_S3C_HSOTG
|
||||
tristate
|
||||
depends on USB_GADGET_S3C_HSOTG
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_IMX
|
||||
boolean "Freescale IMX USB Peripheral Controller"
|
||||
config USB_IMX
|
||||
tristate "Freescale IMX USB Peripheral Controller"
|
||||
depends on ARCH_MX1
|
||||
help
|
||||
Freescale's IMX series include an integrated full speed
|
||||
@ -329,14 +269,8 @@ config USB_GADGET_IMX
|
||||
dynamically linked module called "imx_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_IMX
|
||||
tristate
|
||||
depends on USB_GADGET_IMX
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_S3C2410
|
||||
boolean "S3C2410 USB Device Controller"
|
||||
config USB_S3C2410
|
||||
tristate "S3C2410 USB Device Controller"
|
||||
depends on ARCH_S3C2410
|
||||
help
|
||||
Samsung's S3C2410 is an ARM-4 processor with an integrated
|
||||
@ -346,18 +280,12 @@ config USB_GADGET_S3C2410
|
||||
This driver has been tested on the S3C2410, S3C2412, and
|
||||
S3C2440 processors.
|
||||
|
||||
config USB_S3C2410
|
||||
tristate
|
||||
depends on USB_GADGET_S3C2410
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_S3C2410_DEBUG
|
||||
boolean "S3C2410 udc debug messages"
|
||||
depends on USB_GADGET_S3C2410
|
||||
depends on USB_S3C2410
|
||||
|
||||
config USB_GADGET_S3C_HSUDC
|
||||
boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
|
||||
config USB_S3C_HSUDC
|
||||
tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
|
||||
depends on ARCH_S3C2410
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
@ -367,41 +295,29 @@ config USB_GADGET_S3C_HSUDC
|
||||
|
||||
This driver has been tested on S3C2416 and S3C2450 processors.
|
||||
|
||||
config USB_S3C_HSUDC
|
||||
tristate
|
||||
depends on USB_GADGET_S3C_HSUDC
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA_U2O
|
||||
boolean "PXA9xx Processor USB2.0 controller"
|
||||
config USB_PXA_U2O
|
||||
tristate "PXA9xx Processor USB2.0 controller"
|
||||
depends on ARCH_MMP
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
PXA9xx Processor series include a high speed USB2.0 device
|
||||
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
|
||||
#
|
||||
|
||||
# musb builds in ../musb along with host support
|
||||
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)
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SELECTED
|
||||
help
|
||||
This OTG-capable silicon IP is used in dual designs including
|
||||
the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
|
||||
|
||||
config USB_GADGET_M66592
|
||||
boolean "Renesas M66592 USB Peripheral Controller"
|
||||
config USB_M66592
|
||||
tristate "Renesas M66592 USB Peripheral Controller"
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
M66592 is a discrete USB peripheral controller chip that
|
||||
@ -412,18 +328,12 @@ config USB_GADGET_M66592
|
||||
dynamically linked module called "m66592_udc" and force all
|
||||
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)
|
||||
#
|
||||
|
||||
config USB_GADGET_AMD5536UDC
|
||||
boolean "AMD5536 UDC"
|
||||
config USB_AMD5536UDC
|
||||
tristate "AMD5536 UDC"
|
||||
depends on PCI
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
@ -437,14 +347,8 @@ config USB_GADGET_AMD5536UDC
|
||||
dynamically linked module called "amd5536udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_AMD5536UDC
|
||||
tristate
|
||||
depends on USB_GADGET_AMD5536UDC
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_FSL_QE
|
||||
boolean "Freescale QE/CPM USB Device Controller"
|
||||
config USB_FSL_QE
|
||||
tristate "Freescale QE/CPM USB Device Controller"
|
||||
depends on FSL_SOC && (QUICC_ENGINE || CPM)
|
||||
help
|
||||
Some of Freescale PowerPC processors have a Full Speed
|
||||
@ -456,14 +360,8 @@ config USB_GADGET_FSL_QE
|
||||
Set CONFIG_USB_GADGET to "m" to build this driver as a
|
||||
dynamically linked module called "fsl_qe_udc".
|
||||
|
||||
config USB_FSL_QE
|
||||
tristate
|
||||
depends on USB_GADGET_FSL_QE
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_CI13XXX_PCI
|
||||
boolean "MIPS USB CI13xxx PCI UDC"
|
||||
config USB_CI13XXX_PCI
|
||||
tristate "MIPS USB CI13xxx PCI UDC"
|
||||
depends on PCI
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
@ -474,14 +372,31 @@ config USB_GADGET_CI13XXX_PCI
|
||||
dynamically linked module called "ci13xxx_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_CI13XXX_PCI
|
||||
tristate
|
||||
depends on USB_GADGET_CI13XXX_PCI
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
config USB_NET2272
|
||||
tristate "PLX NET2272"
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
PLX NET2272 is a USB peripheral controller which supports
|
||||
both full and high speed USB 2.0 data transfers.
|
||||
|
||||
config USB_GADGET_NET2280
|
||||
boolean "NetChip 228x"
|
||||
It has three configurable endpoints, as well as endpoint zero
|
||||
(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
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
@ -496,14 +411,8 @@ config USB_GADGET_NET2280
|
||||
dynamically linked module called "net2280" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_NET2280
|
||||
tristate
|
||||
depends on USB_GADGET_NET2280
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_GOKU
|
||||
boolean "Toshiba TC86C001 'Goku-S'"
|
||||
config USB_GOKU
|
||||
tristate "Toshiba TC86C001 'Goku-S'"
|
||||
depends on PCI
|
||||
help
|
||||
The Toshiba TC86C001 is a PCI device which includes controllers
|
||||
@ -516,15 +425,10 @@ config USB_GADGET_GOKU
|
||||
dynamically linked module called "goku_udc" and to force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_GOKU
|
||||
tristate
|
||||
depends on USB_GADGET_GOKU
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_LANGWELL
|
||||
boolean "Intel Langwell USB Device Controller"
|
||||
config USB_LANGWELL
|
||||
tristate "Intel Langwell USB Device Controller"
|
||||
depends on PCI
|
||||
depends on !PHYS_ADDR_T_64BIT
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Intel Langwell USB Device Controller is a High-Speed USB
|
||||
@ -537,14 +441,8 @@ config USB_GADGET_LANGWELL
|
||||
dynamically linked module called "langwell_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_LANGWELL
|
||||
tristate
|
||||
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"
|
||||
config USB_EG20T
|
||||
tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
|
||||
depends on PCI
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
@ -565,14 +463,8 @@ config USB_GADGET_EG20T
|
||||
ML7213 is companion chip for Intel Atom E6xx series.
|
||||
ML7213 is completely compatible for Intel EG20T PCH.
|
||||
|
||||
config USB_EG20T
|
||||
tristate
|
||||
depends on USB_GADGET_EG20T
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_CI13XXX_MSM
|
||||
boolean "MIPS USB CI13xxx for MSM"
|
||||
config USB_CI13XXX_MSM
|
||||
tristate "MIPS USB CI13xxx for MSM"
|
||||
depends on ARCH_MSM
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_MSM_OTG
|
||||
@ -588,31 +480,26 @@ config USB_GADGET_CI13XXX_MSM
|
||||
dynamically linked module called "ci13xxx_msm" and force all
|
||||
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
|
||||
#
|
||||
|
||||
config USB_GADGET_DUMMY_HCD
|
||||
boolean "Dummy HCD (DEVELOPMENT)"
|
||||
config USB_DUMMY_HCD
|
||||
tristate "Dummy HCD (DEVELOPMENT)"
|
||||
depends on USB=y || (USB=m && USB_GADGET=m)
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SUPERSPEED
|
||||
help
|
||||
This host controller driver emulates USB, looping all data transfer
|
||||
requests back to a USB "gadget driver" in the same host. The host
|
||||
side is the master; the gadget side is the slave. Gadget drivers
|
||||
can be high, full, or low speed; and they have access to endpoints
|
||||
like those from NET2280, PXA2xx, or SA1100 hardware.
|
||||
|
||||
|
||||
This may help in some stages of creating a driver to embed in a
|
||||
Linux device, since it lets you debug several parts of the gadget
|
||||
driver without its hardware or drivers being involved.
|
||||
|
||||
|
||||
Since such a gadget side driver needs to interoperate with a host
|
||||
side Linux-USB device driver, this may help to debug both sides
|
||||
of a USB protocol stack.
|
||||
@ -621,12 +508,6 @@ config USB_GADGET_DUMMY_HCD
|
||||
dynamically linked module called "dummy_hcd" and force all
|
||||
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
|
||||
# first and will be selected by default.
|
||||
|
||||
@ -637,12 +518,18 @@ config USB_GADGET_DUALSPEED
|
||||
bool
|
||||
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
|
||||
#
|
||||
choice
|
||||
tristate "USB Gadget Drivers"
|
||||
depends on USB_GADGET && USB_GADGET_SELECTED
|
||||
depends on USB_GADGET
|
||||
default USB_ETH
|
||||
help
|
||||
A Linux "Gadget Driver" talks to the USB Peripheral Controller
|
||||
@ -848,7 +735,7 @@ config USB_FUNCTIONFS_GENERIC
|
||||
no Ethernet interface.
|
||||
|
||||
config USB_FILE_STORAGE
|
||||
tristate "File-backed Storage Gadget"
|
||||
tristate "File-backed Storage Gadget (DEPRECATED)"
|
||||
depends on BLOCK
|
||||
help
|
||||
The File-backed Storage Gadget acts as a USB Mass Storage
|
||||
@ -859,6 +746,9 @@ config USB_FILE_STORAGE
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "g_file_storage".
|
||||
|
||||
NOTE: This driver is deprecated. Its replacement is the
|
||||
Mass Storage Gadget.
|
||||
|
||||
config USB_FILE_STORAGE_TEST
|
||||
bool "File-backed Storage Gadget testing version"
|
||||
depends on USB_FILE_STORAGE
|
||||
@ -878,14 +768,11 @@ config USB_MASS_STORAGE
|
||||
device (in much the same way as the "loop" device driver),
|
||||
specified as a module parameter or sysfs option.
|
||||
|
||||
This is heavily based on File-backed Storage Gadget and in most
|
||||
cases you will want to use FSG instead. This gadget is mostly
|
||||
here to test the functionality of the Mass Storage Function
|
||||
which may be used with composite framework.
|
||||
This driver is an updated replacement for the deprecated
|
||||
File-backed Storage Gadget (g_file_storage).
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build
|
||||
a dynamically linked module called "g_mass_storage". If unsure,
|
||||
consider File-backed Storage Gadget.
|
||||
a dynamically linked module called "g_mass_storage".
|
||||
|
||||
config USB_G_SERIAL
|
||||
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
|
||||
|
@ -3,7 +3,9 @@
|
||||
#
|
||||
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_GADGET) += udc-core.o
|
||||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2272) += net2272.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
|
||||
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
|
||||
|
@ -1438,10 +1438,15 @@ static int udc_wakeup(struct usb_gadget *gadget)
|
||||
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 */
|
||||
static const struct usb_gadget_ops udc_ops = {
|
||||
.wakeup = udc_wakeup,
|
||||
.get_frame = udc_get_frame,
|
||||
.start = amd5536_start,
|
||||
.stop = amd5536_stop,
|
||||
};
|
||||
|
||||
/* Setups endpoint parameters, adds endpoints to linked list */
|
||||
@ -1955,7 +1960,7 @@ static int setup_ep0(struct udc *dev)
|
||||
}
|
||||
|
||||
/* 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 *))
|
||||
{
|
||||
struct udc *dev = udc;
|
||||
@ -2002,7 +2007,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/* shutdown requests and disconnect from gadget */
|
||||
static void
|
||||
@ -2027,7 +2031,7 @@ __acquires(dev->lock)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
unsigned long flags;
|
||||
@ -2057,8 +2061,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
|
||||
/* Clear pending NAK bits */
|
||||
static void udc_process_cnak_queue(struct udc *dev)
|
||||
@ -3134,6 +3136,7 @@ static void udc_pci_remove(struct pci_dev *pdev)
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
/* gadget driver must not be registered */
|
||||
BUG_ON(dev->driver != NULL);
|
||||
|
||||
@ -3382,8 +3385,13 @@ static int udc_probe(struct udc *dev)
|
||||
"driver version: %s(for Geode5536 B1)\n", tmp);
|
||||
udc = dev;
|
||||
|
||||
retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto finished;
|
||||
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval) {
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
put_device(&dev->gadget.dev);
|
||||
goto finished;
|
||||
}
|
||||
|
@ -985,12 +985,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
|
||||
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 = {
|
||||
.get_frame = at91_get_frame,
|
||||
.wakeup = at91_wakeup,
|
||||
.set_selfpowered = at91_set_selfpowered,
|
||||
.vbus_session = at91_vbus_session,
|
||||
.pullup = at91_pullup,
|
||||
.start = at91_start,
|
||||
.stop = at91_stop,
|
||||
|
||||
/*
|
||||
* VBUS-powered devices may also also want to support bigger
|
||||
@ -1628,7 +1634,7 @@ static void at91_vbus_timer(unsigned long data)
|
||||
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 *))
|
||||
{
|
||||
struct at91_udc *udc = &controller;
|
||||
@ -1672,9 +1678,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
DBG("bound to %s\n", driver->driver.name);
|
||||
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;
|
||||
unsigned long flags;
|
||||
@ -1696,7 +1701,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
DBG("unbound from %s\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL (usb_gadget_unregister_driver);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -1854,13 +1858,18 @@ static int __init at91udc_probe(struct platform_device *pdev)
|
||||
DBG("no VBUS detection, assuming always-on\n");
|
||||
udc->vbus = 1;
|
||||
}
|
||||
retval = usb_add_gadget_udc(dev, &udc->gadget);
|
||||
if (retval)
|
||||
goto fail4;
|
||||
dev_set_drvdata(dev, udc);
|
||||
device_init_wakeup(dev, 1);
|
||||
create_debug_file(udc);
|
||||
|
||||
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
|
||||
return 0;
|
||||
|
||||
fail4:
|
||||
if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled)
|
||||
free_irq(udc->board.vbus_pin, udc);
|
||||
fail3:
|
||||
if (udc->board.vbus_pin > 0)
|
||||
gpio_free(udc->board.vbus_pin);
|
||||
@ -1887,6 +1896,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
|
||||
|
||||
DBG("remove\n");
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -1007,10 +1007,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
|
||||
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 = {
|
||||
.get_frame = usba_udc_get_frame,
|
||||
.wakeup = usba_udc_wakeup,
|
||||
.set_selfpowered = usba_udc_set_selfpowered,
|
||||
.start = atmel_usba_start,
|
||||
.stop = atmel_usba_stop,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor usba_ep0_desc = {
|
||||
@ -1789,7 +1795,7 @@ out:
|
||||
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 *))
|
||||
{
|
||||
struct usba_udc *udc = &the_udc;
|
||||
@ -1842,9 +1848,8 @@ err_driver_bind:
|
||||
udc->gadget.dev.driver = NULL;
|
||||
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;
|
||||
unsigned long flags;
|
||||
@ -1880,7 +1885,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
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);
|
||||
for (i = 1; i < pdata->num_ep; i++)
|
||||
usba_ep_init_debugfs(udc, &usba_ep[i]);
|
||||
|
||||
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:
|
||||
free_irq(irq, udc);
|
||||
err_request_irq:
|
||||
@ -2053,6 +2069,8 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
|
||||
|
||||
udc = platform_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
|
||||
for (i = 1; i < pdata->num_ep; i++)
|
||||
usba_ep_cleanup_debugfs(&usba_ep[i]);
|
||||
usba_cleanup_debugfs(udc);
|
||||
|
@ -165,6 +165,7 @@ static struct usb_composite_driver audio_driver = {
|
||||
.name = "g_audio",
|
||||
.dev = &device_desc,
|
||||
.strings = audio_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = __exit_p(audio_unbind),
|
||||
};
|
||||
|
||||
|
@ -244,6 +244,7 @@ static struct usb_composite_driver cdc_driver = {
|
||||
.name = "g_cdc",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = __exit_p(cdc_unbind),
|
||||
};
|
||||
|
||||
|
@ -126,6 +126,7 @@ static struct platform_driver ci13xxx_msm_driver = {
|
||||
.probe = ci13xxx_msm_probe,
|
||||
.driver = { .name = "msm_hsusb", },
|
||||
};
|
||||
MODULE_ALIAS("platform:msm_hsusb");
|
||||
|
||||
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)
|
||||
stamp = stamp * 1000000 + tval.tv_usec;
|
||||
|
||||
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);
|
||||
|
||||
dbg_inc(&dbg_data.idx);
|
||||
@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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",
|
||||
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);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n",
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
|
||||
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);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n",
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
|
||||
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);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
|
||||
isr_statistics.none);
|
||||
@ -1214,12 +1214,13 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
#define DUMP_ENTRIES 512
|
||||
static ssize_t show_registers(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
u32 dump[512];
|
||||
u32 *dump;
|
||||
unsigned i, k, n = 0;
|
||||
|
||||
dbg_trace("[%s] %p\n", __func__, buf);
|
||||
@ -1228,8 +1229,14 @@ static ssize_t show_registers(struct device *dev,
|
||||
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);
|
||||
k = hw_register_read(dump, sizeof(dump)/sizeof(u32));
|
||||
k = hw_register_read(dump, DUMP_ENTRIES);
|
||||
spin_unlock_irqrestore(udc->lock, flags);
|
||||
|
||||
for (i = 0; i < k; i++) {
|
||||
@ -1237,6 +1244,7 @@ static ssize_t show_registers(struct device *dev,
|
||||
"reg[0x%04X] = 0x%08X\n",
|
||||
i * (unsigned)sizeof(u32), dump[i]);
|
||||
}
|
||||
kfree(dump);
|
||||
|
||||
return n;
|
||||
}
|
||||
@ -2515,6 +2523,9 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
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,
|
||||
* which don't involve endpoints (or i/o)
|
||||
@ -2524,17 +2535,19 @@ static const struct usb_gadget_ops usb_gadget_ops = {
|
||||
.vbus_session = ci13xxx_vbus_session,
|
||||
.wakeup = ci13xxx_wakeup,
|
||||
.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
|
||||
* @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.
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int ci13xxx_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct ci13xxx *udc = _udc;
|
||||
@ -2615,10 +2628,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
if (retval)
|
||||
goto done;
|
||||
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)
|
||||
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)
|
||||
return retval;
|
||||
spin_lock_irqsave(udc->lock, flags);
|
||||
@ -2657,14 +2673,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
spin_unlock_irqrestore(udc->lock, flags);
|
||||
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
|
||||
*/
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int ci13xxx_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct ci13xxx *udc = _udc;
|
||||
unsigned long i, flags;
|
||||
@ -2726,7 +2741,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/******************************************************************************
|
||||
* BUS block
|
||||
@ -2901,12 +2915,23 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
|
||||
if (retval)
|
||||
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_enable(&udc->gadget.dev);
|
||||
|
||||
_udc = udc;
|
||||
return retval;
|
||||
|
||||
remove_trans:
|
||||
if (udc->transceiver) {
|
||||
otg_set_peripheral(udc->transceiver, &udc->gadget);
|
||||
otg_put_transceiver(udc->transceiver);
|
||||
}
|
||||
|
||||
err("error = %i", retval);
|
||||
remove_dbg:
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
@ -2936,6 +2961,7 @@ static void udc_remove(void)
|
||||
err("EINVAL");
|
||||
return;
|
||||
}
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
|
||||
if (udc->transceiver) {
|
||||
otg_set_peripheral(udc->transceiver, &udc->gadget);
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/*
|
||||
* The code in this file is utility code, used to build a gadget driver
|
||||
@ -74,6 +74,130 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
|
||||
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
|
||||
@ -123,6 +247,8 @@ int usb_add_function(struct usb_configuration *config,
|
||||
config->fullspeed = true;
|
||||
if (!config->highspeed && function->hs_descriptors)
|
||||
config->highspeed = true;
|
||||
if (!config->superspeed && function->ss_descriptors)
|
||||
config->superspeed = true;
|
||||
|
||||
done:
|
||||
if (value)
|
||||
@ -266,10 +392,17 @@ static int config_buf(struct usb_configuration *config,
|
||||
list_for_each_entry(f, &config->functions, list) {
|
||||
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;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
descriptors = f->descriptors;
|
||||
}
|
||||
|
||||
if (!descriptors)
|
||||
continue;
|
||||
status = usb_descriptor_fillbuf(next, len,
|
||||
@ -292,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
|
||||
u8 type = w_value >> 8;
|
||||
enum usb_device_speed speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
if (gadget_is_dualspeed(gadget)) {
|
||||
int hs = 0;
|
||||
|
||||
if (gadget->speed == USB_SPEED_SUPER)
|
||||
speed = gadget->speed;
|
||||
else if (gadget_is_dualspeed(gadget)) {
|
||||
int hs = 0;
|
||||
if (gadget->speed == USB_SPEED_HIGH)
|
||||
hs = 1;
|
||||
if (type == USB_DT_OTHER_SPEED_CONFIG)
|
||||
@ -308,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
|
||||
w_value &= 0xff;
|
||||
list_for_each_entry(c, &cdev->configs, list) {
|
||||
/* 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)
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
if (!c->fullspeed)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (w_value == 0)
|
||||
return config_buf(c, speed, cdev->req->buf, type);
|
||||
w_value--;
|
||||
@ -328,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
|
||||
struct usb_configuration *c;
|
||||
unsigned count = 0;
|
||||
int hs = 0;
|
||||
int ss = 0;
|
||||
|
||||
if (gadget_is_dualspeed(gadget)) {
|
||||
if (gadget->speed == USB_SPEED_HIGH)
|
||||
hs = 1;
|
||||
if (gadget->speed == USB_SPEED_SUPER)
|
||||
ss = 1;
|
||||
if (type == USB_DT_DEVICE_QUALIFIER)
|
||||
hs = !hs;
|
||||
}
|
||||
list_for_each_entry(c, &cdev->configs, list) {
|
||||
/* ignore configs that won't work at this speed */
|
||||
if (hs) {
|
||||
if (ss) {
|
||||
if (!c->superspeed)
|
||||
continue;
|
||||
} else if (hs) {
|
||||
if (!c->highspeed)
|
||||
continue;
|
||||
} else {
|
||||
@ -349,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
|
||||
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)
|
||||
{
|
||||
struct usb_qualifier_descriptor *qual = cdev->req->buf;
|
||||
@ -361,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev)
|
||||
qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
|
||||
qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
|
||||
/* 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->bRESERVED = 0;
|
||||
}
|
||||
@ -392,28 +604,46 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
unsigned power = gadget_is_otg(gadget) ? 8 : 100;
|
||||
int tmp;
|
||||
|
||||
if (cdev->config)
|
||||
reset_config(cdev);
|
||||
|
||||
if (number) {
|
||||
list_for_each_entry(c, &cdev->configs, list) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result < 0)
|
||||
goto done;
|
||||
} else
|
||||
} else { /* Zero configuration value - need to reset the config */
|
||||
if (cdev->config)
|
||||
reset_config(cdev);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
INFO(cdev, "%s speed config #%d: %s\n",
|
||||
({ char *speed;
|
||||
switch (gadget->speed) {
|
||||
case USB_SPEED_LOW: speed = "low"; break;
|
||||
case USB_SPEED_FULL: speed = "full"; break;
|
||||
case USB_SPEED_HIGH: speed = "high"; break;
|
||||
default: speed = "?"; break;
|
||||
case USB_SPEED_LOW:
|
||||
speed = "low";
|
||||
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");
|
||||
|
||||
if (!c)
|
||||
@ -435,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
* function's setup callback instead of the current
|
||||
* 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;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
descriptors = f->descriptors;
|
||||
}
|
||||
|
||||
for (; *descriptors; ++descriptors) {
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
@ -531,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
||||
} else {
|
||||
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->superspeed ? " super" : "",
|
||||
config->highspeed ? " high" : "",
|
||||
config->fullspeed
|
||||
? (gadget_is_dualspeed(cdev->gadget)
|
||||
@ -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_request *req = cdev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
int status = 0;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
u8 intf = w_index & 0xFF;
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
@ -838,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
case USB_DT_DEVICE:
|
||||
cdev->desc.bNumConfigurations =
|
||||
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);
|
||||
memcpy(req->buf, &cdev->desc, value);
|
||||
break;
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
if (!gadget_is_dualspeed(gadget))
|
||||
if (!gadget_is_dualspeed(gadget) ||
|
||||
gadget->speed >= USB_SPEED_SUPER)
|
||||
break;
|
||||
device_qual(cdev);
|
||||
value = min_t(int, w_length,
|
||||
sizeof(struct usb_qualifier_descriptor));
|
||||
break;
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
if (!gadget_is_dualspeed(gadget))
|
||||
if (!gadget_is_dualspeed(gadget) ||
|
||||
gadget->speed >= USB_SPEED_SUPER)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case USB_DT_CONFIG:
|
||||
@ -863,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
if (value >= 0)
|
||||
value = min(w_length, (u16) value);
|
||||
break;
|
||||
case USB_DT_BOS:
|
||||
if (gadget_is_superspeed(gadget)) {
|
||||
value = bos_desc(cdev);
|
||||
value = min(w_length, (u16) value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -930,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
*((u8 *)req->buf) = value;
|
||||
value = min(w_length, (u16) 1);
|
||||
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:
|
||||
unknown:
|
||||
VDBG(cdev,
|
||||
@ -1140,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget)
|
||||
goto fail;
|
||||
|
||||
cdev->desc = *composite->dev;
|
||||
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
/* standardized runtime overrides for device ID data */
|
||||
if (idVendor)
|
||||
@ -1247,7 +1556,11 @@ composite_resume(struct usb_gadget *gadget)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_gadget_driver composite_driver = {
|
||||
#ifdef CONFIG_USB_GADGET_SUPERSPEED
|
||||
.speed = USB_SPEED_SUPER,
|
||||
#else
|
||||
.speed = USB_SPEED_HIGH,
|
||||
#endif
|
||||
|
||||
.unbind = composite_unbind,
|
||||
|
||||
@ -1293,6 +1606,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,
|
||||
driver->iProduct = driver->name;
|
||||
composite_driver.function = (char *) driver->name;
|
||||
composite_driver.driver.name = driver->name;
|
||||
composite_driver.speed = min((u8)composite_driver.speed,
|
||||
(u8)driver->max_speed);
|
||||
composite = driver;
|
||||
composite_gadget_bind = bind;
|
||||
|
||||
|
@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
|
||||
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 @@ fail_1:
|
||||
|
||||
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;
|
||||
return err;
|
||||
}
|
||||
@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
|
||||
dbgp.serial->in = dbgp.i_ep;
|
||||
dbgp.serial->out = dbgp.o_ep;
|
||||
|
||||
dbgp.serial->in_desc = &i_desc;
|
||||
dbgp.serial->out_desc = &o_desc;
|
||||
dbgp.serial->in->desc = &i_desc;
|
||||
dbgp.serial->out->desc = &o_desc;
|
||||
|
||||
if (gserial_setup(gadget, 1) < 0) {
|
||||
stp = 3;
|
||||
@ -312,7 +314,6 @@ static int __init dbgp_bind(struct usb_gadget *gadget)
|
||||
|
||||
dbgp.req->length = DBGP_REQ_EP0_LEN;
|
||||
gadget->ep0->driver_data = gadget;
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
|
||||
@ -363,6 +364,7 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
||||
dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
|
||||
len = sizeof device_desc;
|
||||
data = &device_desc;
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
break;
|
||||
case USB_DT_DEBUG:
|
||||
dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -63,13 +63,16 @@ static int
|
||||
ep_matches (
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_ep *ep,
|
||||
struct usb_endpoint_descriptor *desc
|
||||
struct usb_endpoint_descriptor *desc,
|
||||
struct usb_ss_ep_comp_descriptor *ep_comp
|
||||
)
|
||||
{
|
||||
u8 type;
|
||||
const char *tmp;
|
||||
u16 max;
|
||||
|
||||
int num_req_streams = 0;
|
||||
|
||||
/* endpoint already claimed? */
|
||||
if (NULL != ep->driver_data)
|
||||
return 0;
|
||||
@ -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
|
||||
* and wants to know the maximum possible, provide the info.
|
||||
@ -142,13 +161,13 @@ ep_matches (
|
||||
max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
|
||||
switch (type) {
|
||||
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)
|
||||
return 0;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
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)
|
||||
return 0;
|
||||
if (!gadget->is_dualspeed && max > 1023)
|
||||
@ -183,7 +202,7 @@ ep_matches (
|
||||
}
|
||||
|
||||
/* report (variable) full speed bulk maxpacket */
|
||||
if (USB_ENDPOINT_XFER_BULK == type) {
|
||||
if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
|
||||
int size = ep->maxpacket;
|
||||
|
||||
/* min() doesn't work on bitfields with gcc-3.5 */
|
||||
@ -191,6 +210,7 @@ ep_matches (
|
||||
size = 64;
|
||||
desc->wMaxPacketSize = cpu_to_le16(size);
|
||||
}
|
||||
ep->address = desc->bEndpointAddress;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -207,7 +227,120 @@ 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.
|
||||
* @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.
|
||||
* @ep_comp: Endpoint companion descriptor, with the required
|
||||
* number of streams. Will be modified when the chosen EP
|
||||
* supports a different number of streams.
|
||||
*
|
||||
* This routine replaces the usb_ep_autoconfig when needed
|
||||
* superspeed enhancments. If such enhancemnets are required,
|
||||
* the FD should call usb_ep_autoconfig_ss directly and provide
|
||||
* 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.
|
||||
* 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 and
|
||||
* the bmAttribute field in the ep companion descriptor is
|
||||
* 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.
|
||||
*/
|
||||
struct usb_ep *usb_ep_autoconfig_ss(
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_endpoint_descriptor *desc,
|
||||
struct usb_ss_ep_comp_descriptor *ep_comp
|
||||
)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
u8 type;
|
||||
|
||||
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
/* First, apply chip-specific "best usage" knowledge.
|
||||
* This might make a good usb_gadget_ops hook ...
|
||||
*/
|
||||
if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
|
||||
/* ep-e, ep-f are PIO with only 64 byte fifos */
|
||||
ep = find_ep (gadget, "ep-e");
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
return ep;
|
||||
ep = find_ep (gadget, "ep-f");
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
return ep;
|
||||
|
||||
} else if (gadget_is_goku (gadget)) {
|
||||
if (USB_ENDPOINT_XFER_INT == type) {
|
||||
/* single buffering is enough */
|
||||
ep = find_ep(gadget, "ep3-bulk");
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
return ep;
|
||||
} else if (USB_ENDPOINT_XFER_BULK == type
|
||||
&& (USB_DIR_IN & desc->bEndpointAddress)) {
|
||||
/* DMA may be available */
|
||||
ep = find_ep(gadget, "ep2-bulk");
|
||||
if (ep && ep_matches(gadget, ep, desc,
|
||||
ep_comp))
|
||||
return ep;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLACKFIN
|
||||
} else if (gadget_is_musbhdrc(gadget)) {
|
||||
if ((USB_ENDPOINT_XFER_BULK == type) ||
|
||||
(USB_ENDPOINT_XFER_ISOC == type)) {
|
||||
if (USB_DIR_IN & desc->bEndpointAddress)
|
||||
ep = find_ep (gadget, "ep5in");
|
||||
else
|
||||
ep = find_ep (gadget, "ep6out");
|
||||
} else if (USB_ENDPOINT_XFER_INT == type) {
|
||||
if (USB_DIR_IN & desc->bEndpointAddress)
|
||||
ep = find_ep(gadget, "ep1in");
|
||||
else
|
||||
ep = find_ep(gadget, "ep2out");
|
||||
} else
|
||||
ep = NULL;
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
return ep;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Second, look at endpoints until an unclaimed one looks usable */
|
||||
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
|
||||
if (ep_matches(gadget, ep, desc, ep_comp))
|
||||
return ep;
|
||||
}
|
||||
|
||||
/* Fail */
|
||||
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
|
||||
@ -236,72 +369,15 @@ find_ep (struct usb_gadget *gadget, const char *name)
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
*/
|
||||
struct usb_ep *usb_ep_autoconfig (
|
||||
struct usb_ep *usb_ep_autoconfig(
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_endpoint_descriptor *desc
|
||||
)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
u8 type;
|
||||
|
||||
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
/* First, apply chip-specific "best usage" knowledge.
|
||||
* This might make a good usb_gadget_ops hook ...
|
||||
*/
|
||||
if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
|
||||
/* ep-e, ep-f are PIO with only 64 byte fifos */
|
||||
ep = find_ep (gadget, "ep-e");
|
||||
if (ep && ep_matches (gadget, ep, desc))
|
||||
return ep;
|
||||
ep = find_ep (gadget, "ep-f");
|
||||
if (ep && ep_matches (gadget, ep, desc))
|
||||
return ep;
|
||||
|
||||
} else if (gadget_is_goku (gadget)) {
|
||||
if (USB_ENDPOINT_XFER_INT == type) {
|
||||
/* single buffering is enough */
|
||||
ep = find_ep (gadget, "ep3-bulk");
|
||||
if (ep && ep_matches (gadget, ep, desc))
|
||||
return ep;
|
||||
} else if (USB_ENDPOINT_XFER_BULK == type
|
||||
&& (USB_DIR_IN & desc->bEndpointAddress)) {
|
||||
/* DMA may be available */
|
||||
ep = find_ep (gadget, "ep2-bulk");
|
||||
if (ep && ep_matches (gadget, ep, desc))
|
||||
return ep;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLACKFIN
|
||||
} else if (gadget_is_musbhdrc(gadget)) {
|
||||
if ((USB_ENDPOINT_XFER_BULK == type) ||
|
||||
(USB_ENDPOINT_XFER_ISOC == type)) {
|
||||
if (USB_DIR_IN & desc->bEndpointAddress)
|
||||
ep = find_ep (gadget, "ep5in");
|
||||
else
|
||||
ep = find_ep (gadget, "ep6out");
|
||||
} else if (USB_ENDPOINT_XFER_INT == type) {
|
||||
if (USB_DIR_IN & desc->bEndpointAddress)
|
||||
ep = find_ep(gadget, "ep1in");
|
||||
else
|
||||
ep = find_ep(gadget, "ep2out");
|
||||
} else
|
||||
ep = NULL;
|
||||
if (ep && ep_matches (gadget, ep, desc))
|
||||
return ep;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Second, look at endpoints until an unclaimed one looks usable */
|
||||
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
|
||||
if (ep_matches (gadget, ep, desc))
|
||||
return ep;
|
||||
}
|
||||
|
||||
/* Fail */
|
||||
return NULL;
|
||||
return usb_ep_autoconfig_ss(gadget, desc, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* usb_ep_autoconfig_reset - reset endpoint autoconfig state
|
||||
* @gadget: device for which autoconfig state will be reset
|
||||
|
@ -401,6 +401,7 @@ static struct usb_composite_driver eth_driver = {
|
||||
.name = "g_ether",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_SUPER,
|
||||
.unbind = __exit_p(eth_unbind),
|
||||
};
|
||||
|
||||
|
@ -39,12 +39,6 @@
|
||||
* 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 gserial port;
|
||||
u8 ctrl_id, data_id;
|
||||
@ -58,11 +52,7 @@ struct f_acm {
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
struct acm_ep_descs fs;
|
||||
struct acm_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
struct usb_endpoint_descriptor *notify_desc;
|
||||
struct usb_request *notify_req;
|
||||
|
||||
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)
|
||||
usb_ep_disable(acm->notify);
|
||||
} else {
|
||||
VDBG(cdev, "init acm ctrl interface %d\n", intf);
|
||||
acm->notify_desc = ep_choose(cdev->gadget,
|
||||
acm->hs.notify,
|
||||
acm->fs.notify);
|
||||
if (config_ep_by_speed(cdev->gadget, f, acm->notify))
|
||||
return -EINVAL;
|
||||
}
|
||||
usb_ep_enable(acm->notify, acm->notify_desc);
|
||||
usb_ep_enable(acm->notify);
|
||||
acm->notify->driver_data = acm;
|
||||
|
||||
} else if (intf == acm->data_id) {
|
||||
if (acm->port.in->driver_data) {
|
||||
DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
|
||||
gserial_disconnect(&acm->port);
|
||||
} else {
|
||||
}
|
||||
if (!acm->port.in->desc || !acm->port.out->desc) {
|
||||
DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
|
||||
acm->port.in_desc = ep_choose(cdev->gadget,
|
||||
acm->hs.in, acm->fs.in);
|
||||
acm->port.out_desc = ep_choose(cdev->gadget,
|
||||
acm->hs.out, acm->fs.out);
|
||||
if (config_ep_by_speed(cdev->gadget, f,
|
||||
acm->port.in) ||
|
||||
config_ep_by_speed(cdev->gadget, f,
|
||||
acm->port.out)) {
|
||||
acm->port.in->desc = NULL;
|
||||
acm->port.out->desc = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
gserial_connect(&acm->port, acm->port_num);
|
||||
|
||||
@ -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->context = acm;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
/* copy descriptors */
|
||||
f->descriptors = usb_copy_descriptors(acm_fs_function);
|
||||
if (!f->descriptors)
|
||||
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
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
@ -653,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
acm_hs_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);
|
||||
|
||||
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",
|
||||
|
@ -279,7 +279,6 @@ struct f_audio {
|
||||
|
||||
/* endpoints handle full and/or high speeds */
|
||||
struct usb_ep *out_ep;
|
||||
struct usb_endpoint_descriptor *out_desc;
|
||||
|
||||
spinlock_t lock;
|
||||
struct f_audio_buf *copy_buf;
|
||||
@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
|
||||
if (intf == 1) {
|
||||
if (alt == 1) {
|
||||
usb_ep_enable(out_ep, audio->out_desc);
|
||||
usb_ep_enable(out_ep);
|
||||
out_ep->driver_data = audio;
|
||||
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
|
||||
if (IS_ERR(audio->copy_buf))
|
||||
@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (!ep)
|
||||
goto fail;
|
||||
audio->out_ep = ep;
|
||||
audio->out_ep->desc = &as_out_ep_desc;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
status = -ENOMEM;
|
||||
@ -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.setup = f_audio_setup;
|
||||
audio->card.func.disable = f_audio_disable;
|
||||
audio->out_desc = &as_out_ep_desc;
|
||||
|
||||
control_selector_init(audio);
|
||||
|
||||
|
@ -46,11 +46,6 @@
|
||||
* 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 {
|
||||
ECM_NOTIFY_NONE, /* don't notify */
|
||||
@ -64,11 +59,7 @@ struct f_ecm {
|
||||
|
||||
char ethaddr[14];
|
||||
|
||||
struct ecm_ep_descs fs;
|
||||
struct ecm_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
struct usb_endpoint_descriptor *notify_desc;
|
||||
struct usb_request *notify_req;
|
||||
u8 notify_state;
|
||||
bool is_open;
|
||||
@ -86,10 +77,12 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
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;
|
||||
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[] = {
|
||||
(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 *) &fs_ecm_notify_desc,
|
||||
|
||||
/* data interface, altsettings 0 and 1 */
|
||||
(struct usb_descriptor_header *) &ecm_data_nop_intf,
|
||||
(struct usb_descriptor_header *) &ecm_data_intf,
|
||||
@ -240,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ecm_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
@ -264,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
|
||||
(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 *) &hs_ecm_notify_desc,
|
||||
|
||||
/* data interface, altsettings 0 and 1 */
|
||||
(struct usb_descriptor_header *) &ecm_data_nop_intf,
|
||||
(struct usb_descriptor_header *) &ecm_data_intf,
|
||||
@ -274,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
|
||||
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: */
|
||||
|
||||
static struct usb_string ecm_string_defs[] = {
|
||||
@ -464,13 +532,13 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
if (ecm->notify->driver_data) {
|
||||
VDBG(cdev, "reset ecm control %d\n", intf);
|
||||
usb_ep_disable(ecm->notify);
|
||||
} else {
|
||||
VDBG(cdev, "init ecm ctrl %d\n", intf);
|
||||
ecm->notify_desc = ep_choose(cdev->gadget,
|
||||
ecm->hs.notify,
|
||||
ecm->fs.notify);
|
||||
}
|
||||
usb_ep_enable(ecm->notify, ecm->notify_desc);
|
||||
if (!(ecm->notify->desc)) {
|
||||
VDBG(cdev, "init ecm ctrl %d\n", intf);
|
||||
if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
|
||||
goto fail;
|
||||
}
|
||||
usb_ep_enable(ecm->notify);
|
||||
ecm->notify->driver_data = ecm;
|
||||
|
||||
/* 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)
|
||||
gether_disconnect(&ecm->port);
|
||||
}
|
||||
|
||||
if (!ecm->port.in) {
|
||||
if (!ecm->port.in_ep->desc ||
|
||||
!ecm->port.out_ep->desc) {
|
||||
DBG(cdev, "init ecm\n");
|
||||
ecm->port.in = ep_choose(cdev->gadget,
|
||||
ecm->hs.in, ecm->fs.in);
|
||||
ecm->port.out = ep_choose(cdev->gadget,
|
||||
ecm->hs.out, ecm->fs.out);
|
||||
if (config_ep_by_speed(cdev->gadget, f,
|
||||
ecm->port.in_ep) ||
|
||||
config_ep_by_speed(cdev->gadget, f,
|
||||
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.
|
||||
@ -549,7 +622,7 @@ static void ecm_disable(struct usb_function *f)
|
||||
if (ecm->notify->driver_data) {
|
||||
usb_ep_disable(ecm->notify);
|
||||
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)
|
||||
if (!f->descriptors)
|
||||
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
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
@ -688,13 +754,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ecm->hs.in = usb_find_endpoint(ecm_hs_function,
|
||||
f->hs_descriptors, &hs_ecm_in_desc);
|
||||
ecm->hs.out = usb_find_endpoint(ecm_hs_function,
|
||||
f->hs_descriptors, &hs_ecm_out_desc);
|
||||
ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
|
||||
f->hs_descriptors, &hs_ecm_notify_desc);
|
||||
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;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* NOTE: all that is done without knowing or caring about
|
||||
@ -706,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
ecm->port.close = ecm_close;
|
||||
|
||||
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",
|
||||
ecm->port.in_ep->name, ecm->port.out_ep->name,
|
||||
ecm->notify->name);
|
||||
@ -714,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fail:
|
||||
if (f->descriptors)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
if (f->hs_descriptors)
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
|
||||
if (ecm->notify_req) {
|
||||
kfree(ecm->notify_req->buf);
|
||||
@ -723,9 +799,9 @@ fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (ecm->notify)
|
||||
ecm->notify->driver_data = NULL;
|
||||
if (ecm->port.out)
|
||||
if (ecm->port.out_ep->desc)
|
||||
ecm->port.out_ep->driver_data = NULL;
|
||||
if (ecm->port.in)
|
||||
if (ecm->port.in_ep->desc)
|
||||
ecm->port.in_ep->driver_data = NULL;
|
||||
|
||||
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)
|
||||
|
||||
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))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
@ -35,17 +35,9 @@
|
||||
* Ethernet link.
|
||||
*/
|
||||
|
||||
struct eem_ep_descs {
|
||||
struct usb_endpoint_descriptor *in;
|
||||
struct usb_endpoint_descriptor *out;
|
||||
};
|
||||
|
||||
struct f_eem {
|
||||
struct gether port;
|
||||
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)
|
||||
@ -123,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {
|
||||
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: */
|
||||
|
||||
static struct usb_string eem_string_defs[] = {
|
||||
@ -176,12 +207,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
gether_disconnect(&eem->port);
|
||||
}
|
||||
|
||||
if (!eem->port.in) {
|
||||
if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
|
||||
DBG(cdev, "init eem\n");
|
||||
eem->port.in = ep_choose(cdev->gadget,
|
||||
eem->hs.in, eem->fs.in);
|
||||
eem->port.out = ep_choose(cdev->gadget,
|
||||
eem->hs.out, eem->fs.out);
|
||||
if (config_ep_by_speed(cdev->gadget, f,
|
||||
eem->port.in_ep) ||
|
||||
config_ep_by_speed(cdev->gadget, f,
|
||||
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
|
||||
@ -253,11 +288,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (!f->descriptors)
|
||||
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
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
@ -272,14 +302,22 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
eem->hs.in = usb_find_endpoint(eem_hs_function,
|
||||
f->hs_descriptors, &eem_hs_in_desc);
|
||||
eem->hs.out = usb_find_endpoint(eem_hs_function,
|
||||
f->hs_descriptors, &eem_hs_out_desc);
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
eem_ss_in_desc.bEndpointAddress =
|
||||
eem_fs_in_desc.bEndpointAddress;
|
||||
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",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
eem->port.in_ep->name, eem->port.out_ep->name);
|
||||
return 0;
|
||||
@ -287,11 +325,13 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fail:
|
||||
if (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 */
|
||||
if (eem->port.out)
|
||||
if (eem->port.out_ep->desc)
|
||||
eem->port.out_ep->driver_data = NULL;
|
||||
if (eem->port.in)
|
||||
if (eem->port.in_ep->desc)
|
||||
eem->port.in_ep->driver_data = NULL;
|
||||
|
||||
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)
|
||||
|
||||
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))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func)
|
||||
ds = ep->descs[ep->descs[1] ? 1 : 0];
|
||||
|
||||
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)) {
|
||||
epfile->ep = ep;
|
||||
epfile->in = usb_endpoint_dir_in(ds);
|
||||
|
@ -59,8 +59,6 @@ struct f_hidg {
|
||||
struct cdev cdev;
|
||||
struct usb_function func;
|
||||
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)
|
||||
@ -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 f_hidg *hidg = func_to_hidg(f);
|
||||
const struct usb_endpoint_descriptor *ep_desc;
|
||||
int status = 0;
|
||||
|
||||
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)
|
||||
if (hidg->in_ep->driver_data != NULL)
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
|
||||
ep_desc = ep_choose(f->config->cdev->gadget,
|
||||
hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
|
||||
status = usb_ep_enable(hidg->in_ep, ep_desc);
|
||||
status = config_ep_by_speed(f->config->cdev->gadget, f,
|
||||
hidg->in_ep);
|
||||
if (status) {
|
||||
ERROR(cdev, "config_ep_by_speed FAILED!\n");
|
||||
goto fail;
|
||||
}
|
||||
status = usb_ep_enable(hidg->in_ep);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "Enable endpoint FAILED!\n");
|
||||
goto fail;
|
||||
@ -498,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (!f->descriptors)
|
||||
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)) {
|
||||
hidg_hs_in_ep_desc.bEndpointAddress =
|
||||
hidg_fs_in_ep_desc.bEndpointAddress;
|
||||
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
|
||||
if (!f->hs_descriptors)
|
||||
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);
|
||||
|
@ -118,6 +118,49 @@ static struct usb_descriptor_header *hs_loopback_descs[] = {
|
||||
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: */
|
||||
|
||||
static struct usb_string strings_loopback[] = {
|
||||
@ -175,8 +218,18 @@ autoconf_fail:
|
||||
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",
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
@ -250,26 +303,27 @@ static int
|
||||
enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
|
||||
{
|
||||
int result = 0;
|
||||
const struct usb_endpoint_descriptor *src, *sink;
|
||||
struct usb_ep *ep;
|
||||
struct usb_request *req;
|
||||
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 */
|
||||
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)
|
||||
return result;
|
||||
ep->driver_data = loop;
|
||||
|
||||
/* one endpoint just reads OUT packets */
|
||||
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) {
|
||||
fail0:
|
||||
ep = loop->in_ep;
|
||||
|
@ -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,
|
||||
struct usb_request **preq)
|
||||
{
|
||||
@ -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). */
|
||||
static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
|
||||
{
|
||||
const struct usb_endpoint_descriptor *d;
|
||||
struct fsg_dev *fsg;
|
||||
int i, rc = 0;
|
||||
|
||||
@ -2396,20 +2383,26 @@ reset:
|
||||
fsg = common->fsg;
|
||||
|
||||
/* Enable the endpoints */
|
||||
d = fsg_ep_desc(common->gadget,
|
||||
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
|
||||
rc = enable_endpoint(common, fsg->bulk_in, d);
|
||||
rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
|
||||
if (rc)
|
||||
goto reset;
|
||||
rc = usb_ep_enable(fsg->bulk_in);
|
||||
if (rc)
|
||||
goto reset;
|
||||
fsg->bulk_in->driver_data = common;
|
||||
fsg->bulk_in_enabled = 1;
|
||||
|
||||
d = fsg_ep_desc(common->gadget,
|
||||
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
|
||||
rc = enable_endpoint(common, fsg->bulk_out, d);
|
||||
rc = config_ep_by_speed(common->gadget, &(fsg->function),
|
||||
fsg->bulk_out);
|
||||
if (rc)
|
||||
goto reset;
|
||||
rc = usb_ep_enable(fsg->bulk_out);
|
||||
if (rc)
|
||||
goto reset;
|
||||
fsg->bulk_out->driver_data = common;
|
||||
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);
|
||||
|
||||
/* Allocate the requests */
|
||||
|
@ -48,12 +48,6 @@
|
||||
#define NCM_NDP_HDR_CRC 0x01000000
|
||||
#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 {
|
||||
NCM_NOTIFY_NONE, /* don't notify */
|
||||
NCM_NOTIFY_CONNECT, /* issue CONNECT next */
|
||||
@ -66,11 +60,7 @@ struct f_ncm {
|
||||
|
||||
char ethaddr[14];
|
||||
|
||||
struct ncm_ep_descs fs;
|
||||
struct ncm_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
struct usb_endpoint_descriptor *notify_desc;
|
||||
struct usb_request *notify_req;
|
||||
u8 notify_state;
|
||||
bool is_open;
|
||||
@ -802,13 +792,14 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
if (ncm->notify->driver_data) {
|
||||
DBG(cdev, "reset ncm control %d\n", intf);
|
||||
usb_ep_disable(ncm->notify);
|
||||
} else {
|
||||
DBG(cdev, "init ncm ctrl %d\n", intf);
|
||||
ncm->notify_desc = ep_choose(cdev->gadget,
|
||||
ncm->hs.notify,
|
||||
ncm->fs.notify);
|
||||
}
|
||||
usb_ep_enable(ncm->notify, ncm->notify_desc);
|
||||
|
||||
if (!(ncm->notify->desc)) {
|
||||
DBG(cdev, "init ncm ctrl %d\n", intf);
|
||||
if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
|
||||
goto fail;
|
||||
}
|
||||
usb_ep_enable(ncm->notify);
|
||||
ncm->notify->driver_data = ncm;
|
||||
|
||||
/* 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)
|
||||
if (alt == 1) {
|
||||
struct net_device *net;
|
||||
|
||||
if (!ncm->port.in) {
|
||||
if (!ncm->port.in_ep->desc ||
|
||||
!ncm->port.out_ep->desc) {
|
||||
DBG(cdev, "init ncm\n");
|
||||
ncm->port.in = ep_choose(cdev->gadget,
|
||||
ncm->hs.in,
|
||||
ncm->fs.in);
|
||||
ncm->port.out = ep_choose(cdev->gadget,
|
||||
ncm->hs.out,
|
||||
ncm->fs.out);
|
||||
if (config_ep_by_speed(cdev->gadget, f,
|
||||
ncm->port.in_ep) ||
|
||||
config_ep_by_speed(cdev->gadget, f,
|
||||
ncm->port.out_ep)) {
|
||||
ncm->port.in_ep->desc = NULL;
|
||||
ncm->port.out_ep->desc = NULL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
@ -1111,7 +1105,7 @@ static void ncm_disable(struct usb_function *f)
|
||||
if (ncm->notify->driver_data) {
|
||||
usb_ep_disable(ncm->notify);
|
||||
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)
|
||||
if (!f->descriptors)
|
||||
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
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
@ -1252,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
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 @@ fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (ncm->notify)
|
||||
ncm->notify->driver_data = NULL;
|
||||
if (ncm->port.out)
|
||||
if (ncm->port.out_ep->desc)
|
||||
ncm->port.out_ep->driver_data = NULL;
|
||||
if (ncm->port.in)
|
||||
if (ncm->port.in_ep->desc)
|
||||
ncm->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
@ -39,20 +39,12 @@
|
||||
* 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 gserial port;
|
||||
u8 ctrl_id;
|
||||
u8 data_id;
|
||||
u8 port_num;
|
||||
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)
|
||||
@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
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);
|
||||
obex->port.in_desc = ep_choose(cdev->gadget,
|
||||
obex->hs.obex_in, obex->fs.obex_in);
|
||||
obex->port.out_desc = ep_choose(cdev->gadget,
|
||||
obex->hs.obex_out, obex->fs.obex_out);
|
||||
if (config_ep_by_speed(cdev->gadget, f,
|
||||
obex->port.in) ||
|
||||
config_ep_by_speed(cdev->gadget, f,
|
||||
obex->port.out)) {
|
||||
obex->port.out->desc = NULL;
|
||||
obex->port.in->desc = NULL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (alt == 1) {
|
||||
@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
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
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
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
|
||||
|
@ -428,17 +428,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
spin_lock(&port->lock);
|
||||
__pn_reset(f);
|
||||
if (alt == 1) {
|
||||
struct usb_endpoint_descriptor *out, *in;
|
||||
int i;
|
||||
|
||||
out = ep_choose(gadget,
|
||||
&pn_hs_sink_desc,
|
||||
&pn_fs_sink_desc);
|
||||
in = ep_choose(gadget,
|
||||
&pn_hs_source_desc,
|
||||
&pn_fs_source_desc);
|
||||
usb_ep_enable(fp->out_ep, out);
|
||||
usb_ep_enable(fp->in_ep, in);
|
||||
if (config_ep_by_speed(gadget, f, fp->in_ep) ||
|
||||
config_ep_by_speed(gadget, f, fp->out_ep)) {
|
||||
fp->in_ep->desc = NULL;
|
||||
fp->out_ep->desc = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
usb_ep_enable(fp->out_ep);
|
||||
usb_ep_enable(fp->in_ep);
|
||||
|
||||
port->usb = fp;
|
||||
fp->out_ep->driver_data = fp;
|
||||
|
@ -76,23 +76,13 @@
|
||||
* - 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 gether port;
|
||||
u8 ctrl_id, data_id;
|
||||
u8 ethaddr[ETH_ALEN];
|
||||
int config;
|
||||
|
||||
struct rndis_ep_descs fs;
|
||||
struct rndis_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
struct usb_endpoint_descriptor *notify_desc;
|
||||
struct usb_request *notify_req;
|
||||
atomic_t notify_count;
|
||||
};
|
||||
@ -105,10 +95,12 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
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;
|
||||
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 = {
|
||||
|
||||
static struct usb_descriptor_header *eth_fs_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,
|
||||
@ -233,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &rndis_acm_descriptor,
|
||||
(struct usb_descriptor_header *) &rndis_union_desc,
|
||||
(struct usb_descriptor_header *) &fs_notify_desc,
|
||||
|
||||
/* data interface has no altsetting */
|
||||
(struct usb_descriptor_header *) &rndis_data_intf,
|
||||
(struct usb_descriptor_header *) &fs_in_desc,
|
||||
@ -251,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
@ -271,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = {
|
||||
|
||||
static struct usb_descriptor_header *eth_hs_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,
|
||||
@ -278,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &rndis_acm_descriptor,
|
||||
(struct usb_descriptor_header *) &rndis_union_desc,
|
||||
(struct usb_descriptor_header *) &hs_notify_desc,
|
||||
|
||||
/* data interface has no altsetting */
|
||||
(struct usb_descriptor_header *) &rndis_data_intf,
|
||||
(struct usb_descriptor_header *) &hs_in_desc,
|
||||
@ -285,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = {
|
||||
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: */
|
||||
|
||||
static struct usb_string rndis_string_defs[] = {
|
||||
@ -484,13 +551,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
if (rndis->notify->driver_data) {
|
||||
VDBG(cdev, "reset rndis control %d\n", intf);
|
||||
usb_ep_disable(rndis->notify);
|
||||
} else {
|
||||
VDBG(cdev, "init rndis ctrl %d\n", intf);
|
||||
rndis->notify_desc = ep_choose(cdev->gadget,
|
||||
rndis->hs.notify,
|
||||
rndis->fs.notify);
|
||||
}
|
||||
usb_ep_enable(rndis->notify, rndis->notify_desc);
|
||||
if (!rndis->notify->desc) {
|
||||
VDBG(cdev, "init rndis ctrl %d\n", intf);
|
||||
if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
|
||||
goto fail;
|
||||
}
|
||||
usb_ep_enable(rndis->notify);
|
||||
rndis->notify->driver_data = rndis;
|
||||
|
||||
} else if (intf == rndis->data_id) {
|
||||
@ -501,12 +568,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
gether_disconnect(&rndis->port);
|
||||
}
|
||||
|
||||
if (!rndis->port.in) {
|
||||
if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
|
||||
DBG(cdev, "init rndis\n");
|
||||
rndis->port.in = ep_choose(cdev->gadget,
|
||||
rndis->hs.in, rndis->fs.in);
|
||||
rndis->port.out = ep_choose(cdev->gadget,
|
||||
rndis->hs.out, rndis->fs.out);
|
||||
if (config_ep_by_speed(cdev->gadget, f,
|
||||
rndis->port.in_ep) ||
|
||||
config_ep_by_speed(cdev->gadget, f,
|
||||
rndis->port.out_ep)) {
|
||||
rndis->port.in_ep->desc = NULL;
|
||||
rndis->port.out_ep->desc = NULL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid ZLPs; they can be troublesome. */
|
||||
@ -662,13 +733,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (!f->descriptors)
|
||||
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
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
@ -683,16 +747,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
|
||||
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rndis->hs.in = usb_find_endpoint(eth_hs_function,
|
||||
f->hs_descriptors, &hs_in_desc);
|
||||
rndis->hs.out = usb_find_endpoint(eth_hs_function,
|
||||
f->hs_descriptors, &hs_out_desc);
|
||||
rndis->hs.notify = usb_find_endpoint(eth_hs_function,
|
||||
f->hs_descriptors, &hs_notify_desc);
|
||||
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;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rndis->port.open = rndis_open;
|
||||
@ -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",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
rndis->port.in_ep->name, rndis->port.out_ep->name,
|
||||
rndis->notify->name);
|
||||
return 0;
|
||||
|
||||
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)
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
if (f->descriptors)
|
||||
@ -738,9 +811,9 @@ fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (rndis->notify)
|
||||
rndis->notify->driver_data = NULL;
|
||||
if (rndis->port.out)
|
||||
if (rndis->port.out_ep->desc)
|
||||
rndis->port.out_ep->driver_data = NULL;
|
||||
if (rndis->port.in)
|
||||
if (rndis->port.in_ep->desc)
|
||||
rndis->port.in_ep->driver_data = NULL;
|
||||
|
||||
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)
|
||||
rndis_deregister(rndis->config);
|
||||
rndis_exit();
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
@ -27,18 +27,10 @@
|
||||
* if you can arrange appropriate host side drivers.
|
||||
*/
|
||||
|
||||
struct gser_descs {
|
||||
struct usb_endpoint_descriptor *in;
|
||||
struct usb_endpoint_descriptor *out;
|
||||
};
|
||||
|
||||
struct f_gser {
|
||||
struct gserial port;
|
||||
u8 data_id;
|
||||
u8 port_num;
|
||||
|
||||
struct gser_descs fs;
|
||||
struct gser_descs hs;
|
||||
};
|
||||
|
||||
static inline struct f_gser *func_to_gser(struct usb_function *f)
|
||||
@ -136,12 +128,15 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
if (gser->port.in->driver_data) {
|
||||
DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
|
||||
gserial_disconnect(&gser->port);
|
||||
} else {
|
||||
}
|
||||
if (!gser->port.in->desc || !gser->port.out->desc) {
|
||||
DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
|
||||
gser->port.in_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.in, gser->fs.in);
|
||||
gser->port.out_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.out, gser->fs.out);
|
||||
if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
|
||||
!config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
|
||||
gser->port.in->desc = NULL;
|
||||
gser->port.out->desc = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
gserial_connect(&gser->port, gser->port_num);
|
||||
return 0;
|
||||
@ -193,12 +188,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(gser_fs_function);
|
||||
|
||||
gser->fs.in = usb_find_endpoint(gser_fs_function,
|
||||
f->descriptors, &gser_fs_in_desc);
|
||||
gser->fs.out = usb_find_endpoint(gser_fs_function,
|
||||
f->descriptors, &gser_fs_out_desc);
|
||||
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
@ -211,11 +200,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
|
||||
|
||||
gser->hs.in = usb_find_endpoint(gser_hs_function,
|
||||
f->hs_descriptors, &gser_hs_in_desc);
|
||||
gser->hs.out = usb_find_endpoint(gser_hs_function,
|
||||
f->hs_descriptors, &gser_hs_out_desc);
|
||||
}
|
||||
|
||||
DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
|
@ -131,6 +131,49 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* super speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor ss_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_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_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_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_source_sink_descs[] = {
|
||||
(struct usb_descriptor_header *) &source_sink_intf,
|
||||
(struct usb_descriptor_header *) &ss_source_desc,
|
||||
(struct usb_descriptor_header *) &ss_source_comp_desc,
|
||||
(struct usb_descriptor_header *) &ss_sink_desc,
|
||||
(struct usb_descriptor_header *) &ss_sink_comp_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* function-specific strings: */
|
||||
|
||||
static struct usb_string strings_sourcesink[] = {
|
||||
@ -187,8 +230,18 @@ autoconf_fail:
|
||||
f->hs_descriptors = hs_source_sink_descs;
|
||||
}
|
||||
|
||||
/* support super speed hardware */
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_source_desc.bEndpointAddress =
|
||||
fs_source_desc.bEndpointAddress;
|
||||
ss_sink_desc.bEndpointAddress =
|
||||
fs_sink_desc.bEndpointAddress;
|
||||
f->ss_descriptors = ss_source_sink_descs;
|
||||
}
|
||||
|
||||
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, ss->in_ep->name, ss->out_ep->name);
|
||||
return 0;
|
||||
}
|
||||
@ -343,15 +396,14 @@ static int
|
||||
enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
|
||||
{
|
||||
int result = 0;
|
||||
const struct usb_endpoint_descriptor *src, *sink;
|
||||
struct usb_ep *ep;
|
||||
|
||||
src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
|
||||
sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
|
||||
|
||||
/* one endpoint writes (sources) zeroes IN (to the host) */
|
||||
ep = ss->in_ep;
|
||||
result = usb_ep_enable(ep, src);
|
||||
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
|
||||
if (result)
|
||||
return result;
|
||||
result = usb_ep_enable(ep);
|
||||
if (result < 0)
|
||||
return result;
|
||||
ep->driver_data = ss;
|
||||
@ -367,7 +419,10 @@ fail:
|
||||
|
||||
/* one endpoint reads (sinks) anything OUT (from the host) */
|
||||
ep = ss->out_ep;
|
||||
result = usb_ep_enable(ep, sink);
|
||||
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
|
||||
if (result)
|
||||
goto fail;
|
||||
result = usb_ep_enable(ep);
|
||||
if (result < 0)
|
||||
goto fail;
|
||||
ep->driver_data = ss;
|
||||
@ -435,6 +490,8 @@ static int sourcesink_setup(struct usb_configuration *c,
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
|
||||
req->length = USB_BUFSIZ;
|
||||
|
||||
/* composite driver infrastructure handles everything except
|
||||
* the two control test requests.
|
||||
*/
|
||||
|
@ -57,18 +57,10 @@
|
||||
* caring about specific product and vendor IDs.
|
||||
*/
|
||||
|
||||
struct geth_descs {
|
||||
struct usb_endpoint_descriptor *in;
|
||||
struct usb_endpoint_descriptor *out;
|
||||
};
|
||||
|
||||
struct f_gether {
|
||||
struct gether port;
|
||||
|
||||
char ethaddr[14];
|
||||
|
||||
struct geth_descs fs;
|
||||
struct geth_descs hs;
|
||||
};
|
||||
|
||||
static inline struct f_gether *func_to_geth(struct usb_function *f)
|
||||
@ -209,6 +201,46 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* super speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = {
|
||||
.bLength = sizeof ss_subset_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 *ss_eth_function[] __initdata = {
|
||||
(struct usb_descriptor_header *) &subset_data_intf,
|
||||
(struct usb_descriptor_header *) &mdlm_header_desc,
|
||||
(struct usb_descriptor_header *) &mdlm_desc,
|
||||
(struct usb_descriptor_header *) &mdlm_detail_desc,
|
||||
(struct usb_descriptor_header *) ðer_desc,
|
||||
(struct usb_descriptor_header *) &ss_subset_in_desc,
|
||||
(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
|
||||
(struct usb_descriptor_header *) &ss_subset_out_desc,
|
||||
(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* string descriptors: */
|
||||
|
||||
static struct usb_string geth_string_defs[] = {
|
||||
@ -243,10 +275,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
}
|
||||
|
||||
DBG(cdev, "init + activate cdc subset\n");
|
||||
geth->port.in = ep_choose(cdev->gadget,
|
||||
geth->hs.in, geth->fs.in);
|
||||
geth->port.out = ep_choose(cdev->gadget,
|
||||
geth->hs.out, geth->fs.out);
|
||||
if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
|
||||
config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
|
||||
geth->port.in_ep->desc = NULL;
|
||||
geth->port.out_ep->desc = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
net = gether_connect(&geth->port);
|
||||
return IS_ERR(net) ? PTR_ERR(net) : 0;
|
||||
@ -296,12 +330,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(fs_eth_function);
|
||||
|
||||
geth->fs.in = usb_find_endpoint(fs_eth_function,
|
||||
f->descriptors, &fs_subset_in_desc);
|
||||
geth->fs.out = usb_find_endpoint(fs_eth_function,
|
||||
f->descriptors, &fs_subset_out_desc);
|
||||
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
@ -315,11 +345,20 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
geth->hs.in = usb_find_endpoint(hs_eth_function,
|
||||
f->hs_descriptors, &hs_subset_in_desc);
|
||||
geth->hs.out = usb_find_endpoint(hs_eth_function,
|
||||
f->hs_descriptors, &hs_subset_out_desc);
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_subset_in_desc.bEndpointAddress =
|
||||
fs_subset_in_desc.bEndpointAddress;
|
||||
ss_subset_out_desc.bEndpointAddress =
|
||||
fs_subset_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(ss_eth_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* NOTE: all that is done without knowing or caring about
|
||||
@ -328,15 +367,21 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
*/
|
||||
|
||||
DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
geth->port.in_ep->name, geth->port.out_ep->name);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (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 */
|
||||
if (geth->port.out)
|
||||
if (geth->port.out_ep->desc)
|
||||
geth->port.out_ep->driver_data = NULL;
|
||||
if (geth->port.in)
|
||||
if (geth->port.in_ep->desc)
|
||||
geth->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
@ -347,6 +392,8 @@ fail:
|
||||
static void
|
||||
geth_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
||||
if (uvc->state != UVC_STATE_CONNECTED)
|
||||
return 0;
|
||||
|
||||
if (uvc->video.ep)
|
||||
usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
|
||||
if (uvc->video.ep) {
|
||||
uvc->video.ep->desc = &uvc_streaming_ep;
|
||||
usb_ep_enable(uvc->video.ep);
|
||||
}
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_STREAMON;
|
||||
@ -649,7 +651,7 @@ uvc_bind_config(struct usb_configuration *c,
|
||||
if (ret)
|
||||
kfree(uvc);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
|
||||
error:
|
||||
kfree(uvc);
|
||||
|
@ -929,6 +929,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
|
||||
|
||||
case USB_DT_DEVICE:
|
||||
VDBG(fsg, "get device descriptor\n");
|
||||
device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
|
||||
value = sizeof device_desc;
|
||||
memcpy(req->buf, &device_desc, value);
|
||||
break;
|
||||
@ -936,6 +937,11 @@ static int standard_setup_req(struct fsg_dev *fsg,
|
||||
VDBG(fsg, "get device qualifier\n");
|
||||
if (!gadget_is_dualspeed(fsg->gadget))
|
||||
break;
|
||||
/*
|
||||
* Assume ep0 uses the same maxpacket value for both
|
||||
* speeds
|
||||
*/
|
||||
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
|
||||
value = sizeof dev_qualifier;
|
||||
memcpy(req->buf, &dev_qualifier, value);
|
||||
break;
|
||||
@ -2713,7 +2719,8 @@ static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
|
||||
int rc;
|
||||
|
||||
ep->driver_data = fsg;
|
||||
rc = usb_ep_enable(ep, d);
|
||||
ep->desc = d;
|
||||
rc = usb_ep_enable(ep);
|
||||
if (rc)
|
||||
ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
|
||||
return rc;
|
||||
@ -3416,7 +3423,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
||||
}
|
||||
|
||||
/* Fix up the descriptors */
|
||||
device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
|
||||
device_desc.idVendor = cpu_to_le16(mod_data.vendor);
|
||||
device_desc.idProduct = cpu_to_le16(mod_data.product);
|
||||
device_desc.bcdDevice = cpu_to_le16(mod_data.release);
|
||||
@ -3430,9 +3436,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
||||
if (gadget_is_dualspeed(gadget)) {
|
||||
fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
|
||||
|
||||
/* Assume ep0 uses the same maxpacket value for both speeds */
|
||||
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
|
||||
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
fsg_hs_bulk_in_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_in_desc.bEndpointAddress;
|
||||
@ -3486,6 +3489,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
||||
}
|
||||
|
||||
INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
|
||||
INFO(fsg, "NOTE: This driver is deprecated. "
|
||||
"Consider using g_mass_storage instead.\n");
|
||||
INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
|
||||
|
||||
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
|
@ -1927,6 +1927,10 @@ static int qe_pullup(struct usb_gadget *gadget, int is_on)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int fsl_qe_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int fsl_qe_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
/* defined in usb_gadget.h */
|
||||
static struct usb_gadget_ops qe_gadget_ops = {
|
||||
.get_frame = qe_get_frame,
|
||||
@ -1935,6 +1939,8 @@ static struct usb_gadget_ops qe_gadget_ops = {
|
||||
.vbus_session = qe_vbus_session,
|
||||
.vbus_draw = qe_vbus_draw,
|
||||
.pullup = qe_pullup,
|
||||
.start = fsl_qe_start,
|
||||
.stop = fsl_qe_stop,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
@ -2320,7 +2326,7 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)
|
||||
/*-------------------------------------------------------------------------
|
||||
Gadget driver probe and unregister.
|
||||
--------------------------------------------------------------------------*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int fsl_qe_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
int retval;
|
||||
@ -2369,9 +2375,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
udc_controller->gadget.name, driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int fsl_qe_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct qe_ep *loop_ep;
|
||||
unsigned long flags;
|
||||
@ -2411,7 +2416,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/* udc structure's alloc and setup, include ep-param alloc */
|
||||
static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
|
||||
@ -2662,11 +2666,17 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
|
||||
if (ret)
|
||||
goto err6;
|
||||
|
||||
ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
|
||||
if (ret)
|
||||
goto err7;
|
||||
|
||||
dev_info(udc_controller->dev,
|
||||
"%s USB controller initialized as device\n",
|
||||
(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
|
||||
return 0;
|
||||
|
||||
err7:
|
||||
device_unregister(&udc_controller->gadget.dev);
|
||||
err6:
|
||||
free_irq(udc_controller->usb_irq, udc_controller);
|
||||
err5:
|
||||
@ -2721,6 +2731,8 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev)
|
||||
if (!udc_controller)
|
||||
return -ENODEV;
|
||||
|
||||
usb_del_gadget_udc(&udc_controller->gadget);
|
||||
|
||||
udc_controller->done = &done;
|
||||
tasklet_disable(&udc_controller->rx_tasklet);
|
||||
|
||||
|
@ -1244,6 +1244,9 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int fsl_stop(struct usb_gadget_driver *driver);
|
||||
/* defined in gadget.h */
|
||||
static struct usb_gadget_ops fsl_gadget_ops = {
|
||||
.get_frame = fsl_get_frame,
|
||||
@ -1252,6 +1255,8 @@ static struct usb_gadget_ops fsl_gadget_ops = {
|
||||
.vbus_session = fsl_vbus_session,
|
||||
.vbus_draw = fsl_vbus_draw,
|
||||
.pullup = fsl_pullup,
|
||||
.start = fsl_start,
|
||||
.stop = fsl_stop,
|
||||
};
|
||||
|
||||
/* Set protocol stall on ep0, protocol stall will automatically be cleared
|
||||
@ -1927,7 +1932,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
|
||||
* Hook to gadget drivers
|
||||
* Called by initialization code of gadget drivers
|
||||
*----------------------------------------------------------------*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int fsl_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
int retval = -ENODEV;
|
||||
@ -1995,10 +2000,9 @@ out:
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/* Disconnect from gadget driver */
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int fsl_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct fsl_ep *loop_ep;
|
||||
unsigned long flags;
|
||||
@ -2041,7 +2045,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
PROC File System Support
|
||||
@ -2590,9 +2593,16 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
|
||||
if (ret)
|
||||
goto err_del_udc;
|
||||
|
||||
create_proc_file();
|
||||
return 0;
|
||||
|
||||
err_del_udc:
|
||||
dma_pool_destroy(udc_controller->td_pool);
|
||||
err_unregister:
|
||||
device_unregister(&udc_controller->gadget.dev);
|
||||
err_free_irq:
|
||||
@ -2624,6 +2634,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
|
||||
|
||||
if (!udc_controller)
|
||||
return -ENODEV;
|
||||
|
||||
usb_del_gadget_udc(&udc_controller->gadget);
|
||||
udc_controller->done = &done;
|
||||
|
||||
fsl_udc_clk_release();
|
||||
|
@ -767,56 +767,6 @@ static void fusb300_rdfifo(struct fusb300_ep *ep,
|
||||
} while (!reg);
|
||||
}
|
||||
|
||||
/* write data to fifo */
|
||||
static void fusb300_wrfifo(struct fusb300_ep *ep,
|
||||
struct fusb300_request *req)
|
||||
{
|
||||
int i = 0;
|
||||
u8 *tmp;
|
||||
u32 data, reg;
|
||||
struct fusb300 *fusb300 = ep->fusb300;
|
||||
|
||||
tmp = req->req.buf;
|
||||
req->req.actual = req->req.length;
|
||||
|
||||
for (i = (req->req.length >> 2); i > 0; i--) {
|
||||
data = *tmp | *(tmp + 1) << 8 |
|
||||
*(tmp + 2) << 16 | *(tmp + 3) << 24;
|
||||
|
||||
iowrite32(data, fusb300->reg +
|
||||
FUSB300_OFFSET_EPPORT(ep->epnum));
|
||||
tmp += 4;
|
||||
}
|
||||
|
||||
switch (req->req.length % 4) {
|
||||
case 1:
|
||||
data = *tmp;
|
||||
iowrite32(data, fusb300->reg +
|
||||
FUSB300_OFFSET_EPPORT(ep->epnum));
|
||||
break;
|
||||
case 2:
|
||||
data = *tmp | *(tmp + 1) << 8;
|
||||
iowrite32(data, fusb300->reg +
|
||||
FUSB300_OFFSET_EPPORT(ep->epnum));
|
||||
break;
|
||||
case 3:
|
||||
data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
|
||||
iowrite32(data, fusb300->reg +
|
||||
FUSB300_OFFSET_EPPORT(ep->epnum));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
|
||||
reg &= FUSB300_IGR1_SYNF0_EMPTY_INT;
|
||||
if (i)
|
||||
printk(KERN_INFO"sync fifo is not empty!\n");
|
||||
i++;
|
||||
} while (!reg);
|
||||
}
|
||||
|
||||
static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)
|
||||
{
|
||||
u8 value;
|
||||
@ -980,11 +930,6 @@ static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void fusb300_ep0_complete(struct usb_ep *ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
}
|
||||
|
||||
static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
u8 *p = (u8 *)ctrl;
|
||||
@ -1029,17 +974,6 @@ static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fusb300_set_ep_bycnt(struct fusb300_ep *ep, u32 bycnt)
|
||||
{
|
||||
struct fusb300 *fusb300 = ep->fusb300;
|
||||
u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
|
||||
|
||||
reg &= ~FUSB300_FFR_BYCNT;
|
||||
reg |= bycnt & FUSB300_FFR_BYCNT;
|
||||
|
||||
iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
|
||||
}
|
||||
|
||||
static void done(struct fusb300_ep *ep, struct fusb300_request *req,
|
||||
int status)
|
||||
{
|
||||
@ -1063,8 +997,8 @@ static void done(struct fusb300_ep *ep, struct fusb300_request *req,
|
||||
fusb300_set_cxdone(ep->fusb300);
|
||||
}
|
||||
|
||||
void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep,
|
||||
struct fusb300_request *req)
|
||||
static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d,
|
||||
u32 len)
|
||||
{
|
||||
u32 value;
|
||||
u32 reg;
|
||||
@ -1076,10 +1010,9 @@ void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep,
|
||||
reg &= FUSB300_EPPRD0_H;
|
||||
} while (reg);
|
||||
|
||||
iowrite32((u32) req->req.buf, ep->fusb300->reg +
|
||||
FUSB300_OFFSET_EPPRD_W1(ep->epnum));
|
||||
iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum));
|
||||
|
||||
value = FUSB300_EPPRD0_BTC(req->req.length) | FUSB300_EPPRD0_H |
|
||||
value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H |
|
||||
FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;
|
||||
iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum));
|
||||
|
||||
@ -1116,13 +1049,12 @@ static void fusb300_set_idma(struct fusb300_ep *ep,
|
||||
struct fusb300_request *req)
|
||||
{
|
||||
dma_addr_t d;
|
||||
u8 *tmp = NULL;
|
||||
|
||||
d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
|
||||
|
||||
if (dma_mapping_error(NULL, d)) {
|
||||
kfree(req->req.buf);
|
||||
printk(KERN_DEBUG "dma_mapping_error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
|
||||
@ -1130,17 +1062,11 @@ static void fusb300_set_idma(struct fusb300_ep *ep,
|
||||
fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
|
||||
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
|
||||
|
||||
tmp = req->req.buf;
|
||||
req->req.buf = (u8 *)d;
|
||||
|
||||
fusb300_fill_idma_prdtbl(ep, req);
|
||||
fusb300_fill_idma_prdtbl(ep, d, req->req.length);
|
||||
/* check idma is done */
|
||||
fusb300_wait_idma_finished(ep);
|
||||
|
||||
req->req.buf = tmp;
|
||||
|
||||
if (d)
|
||||
dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
|
||||
dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void in_ep_fifo_handler(struct fusb300_ep *ep)
|
||||
@ -1148,14 +1074,8 @@ static void in_ep_fifo_handler(struct fusb300_ep *ep)
|
||||
struct fusb300_request *req = list_entry(ep->queue.next,
|
||||
struct fusb300_request, queue);
|
||||
|
||||
if (req->req.length) {
|
||||
#if 0
|
||||
fusb300_set_ep_bycnt(ep, req->req.length);
|
||||
fusb300_wrfifo(ep, req);
|
||||
#else
|
||||
if (req->req.length)
|
||||
fusb300_set_idma(ep, req);
|
||||
#endif
|
||||
}
|
||||
done(ep, req, 0);
|
||||
}
|
||||
|
||||
@ -1500,7 +1420,7 @@ static void init_controller(struct fusb300 *fusb300)
|
||||
/*------------------------------------------------------------------------*/
|
||||
static struct fusb300 *the_controller;
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int fusb300_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct fusb300 *fusb300 = the_controller;
|
||||
@ -1544,9 +1464,8 @@ error:
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int fusb300_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct fusb300 *fusb300 = the_controller;
|
||||
|
||||
@ -1562,7 +1481,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
|
||||
@ -1572,12 +1490,15 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
|
||||
|
||||
static struct usb_gadget_ops fusb300_gadget_ops = {
|
||||
.pullup = fusb300_udc_pullup,
|
||||
.start = fusb300_udc_start,
|
||||
.stop = fusb300_udc_stop,
|
||||
};
|
||||
|
||||
static int __exit fusb300_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
usb_del_gadget_udc(&fusb300->gadget);
|
||||
iounmap(fusb300->reg);
|
||||
free_irq(platform_get_irq(pdev, 0), fusb300);
|
||||
|
||||
@ -1702,9 +1623,15 @@ static int __init fusb300_probe(struct platform_device *pdev)
|
||||
goto clean_up3;
|
||||
|
||||
init_controller(fusb300);
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
|
||||
|
||||
return 0;
|
||||
err_add_udc:
|
||||
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
|
||||
|
||||
clean_up3:
|
||||
free_irq(ires->start, fusb300);
|
||||
|
@ -162,6 +162,7 @@ static struct usb_composite_driver gfs_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.dev = &gfs_dev_desc,
|
||||
.strings = gfs_dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = gfs_unbind,
|
||||
.iProduct = DRIVER_DESC,
|
||||
};
|
||||
|
@ -15,150 +15,40 @@
|
||||
#ifndef __GADGET_CHIPS_H
|
||||
#define __GADGET_CHIPS_H
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_NET2280
|
||||
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
|
||||
#else
|
||||
#define gadget_is_net2280(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_AMD5536UDC
|
||||
#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_amd5536udc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
|
||||
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_dummy(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_PXA25X
|
||||
#define gadget_is_pxa(g) !strcmp("pxa25x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_pxa(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_GOKU
|
||||
#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_goku(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_omap(g) 0
|
||||
#endif
|
||||
|
||||
/* various unstable versions available */
|
||||
#ifdef CONFIG_USB_GADGET_PXA27X
|
||||
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_pxa27x(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_ATMEL_USBA
|
||||
#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_atmel_usba(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_S3C2410
|
||||
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_s3c2410(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_AT91
|
||||
#define gadget_is_at91(g) !strcmp("at91_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_at91(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_IMX
|
||||
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_imx(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_FSL_USB2
|
||||
#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_fsl_usb2(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed "dual role" controller, in peripheral role */
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
#define gadget_is_musbhdrc(g) !strcmp("musb-hdrc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhdrc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_LANGWELL
|
||||
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_langwell(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_M66592
|
||||
#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_m66592(g) 0
|
||||
#endif
|
||||
|
||||
/* Freescale CPM/QE UDC SUPPORT */
|
||||
#ifdef CONFIG_USB_GADGET_FSL_QE
|
||||
#define gadget_is_fsl_qe(g) !strcmp("fsl_qe_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_fsl_qe(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_CI13XXX_PCI
|
||||
#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
|
||||
#else
|
||||
#define gadget_is_ci13xxx_pci(g) 0
|
||||
#endif
|
||||
|
||||
// CONFIG_USB_GADGET_SX2
|
||||
// CONFIG_USB_GADGET_AU1X00
|
||||
// ...
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_R8A66597
|
||||
#define gadget_is_r8a66597(g) !strcmp("r8a66597_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_r8a66597(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_S3C_HSOTG
|
||||
#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name))
|
||||
#else
|
||||
#define gadget_is_s3c_hsotg(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_S3C_HSUDC
|
||||
#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_s3c_hsudc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_EG20T
|
||||
#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_pch(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_CI13XXX_MSM
|
||||
/*
|
||||
* NOTICE: the entries below are alphabetical and should be kept
|
||||
* that way.
|
||||
*
|
||||
* Always be sure to add new entries to the correct position or
|
||||
* accept the bashing later.
|
||||
*
|
||||
* If you have forgotten the alphabetical order let VIM/EMACS
|
||||
* do that for you.
|
||||
*/
|
||||
#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name))
|
||||
#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name))
|
||||
#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name))
|
||||
#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
|
||||
#else
|
||||
#define gadget_is_ci13xxx_msm(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_RENESAS_USBHS
|
||||
#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_renesas_usbhs(g) 0
|
||||
#endif
|
||||
#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
|
||||
#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name))
|
||||
#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name))
|
||||
#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name))
|
||||
#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
|
||||
#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name))
|
||||
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
|
||||
#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name))
|
||||
#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name))
|
||||
#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name))
|
||||
#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name))
|
||||
#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name))
|
||||
#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
|
||||
#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name))
|
||||
#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name))
|
||||
#define gadget_is_r8a66597(g) (!strcmp("r8a66597_udc", (g)->name))
|
||||
#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
|
||||
#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name))
|
||||
#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name))
|
||||
#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
|
||||
|
||||
/**
|
||||
* usb_gadget_controller_number - support bcdDevice id convention
|
||||
@ -223,6 +113,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
||||
return 0x29;
|
||||
else if (gadget_is_s3c_hsudc(gadget))
|
||||
return 0x30;
|
||||
else if (gadget_is_net2272(gadget))
|
||||
return 0x31;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -537,14 +537,16 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
|
||||
struct usb_ep *ep;
|
||||
unsigned i;
|
||||
|
||||
err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
|
||||
dev->in_ep->desc = &bulk_in_desc;
|
||||
err = usb_ep_enable(dev->in_ep);
|
||||
if (err) {
|
||||
ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
|
||||
goto fail;
|
||||
}
|
||||
dev->in_ep->driver_data = dev;
|
||||
|
||||
err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
|
||||
dev->out_ep->desc = &bulk_out_desc;
|
||||
err = usb_ep_enable(dev->out_ep);
|
||||
if (err) {
|
||||
ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
|
||||
goto fail;
|
||||
@ -693,6 +695,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
|
||||
switch (w_value >> 8) {
|
||||
|
||||
case USB_DT_DEVICE:
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
value = min(w_length, (u16) sizeof(device_desc));
|
||||
memcpy(req->buf, &device_desc, value);
|
||||
break;
|
||||
@ -1247,8 +1250,6 @@ autoconf_fail:
|
||||
|
||||
dev->req->complete = gmidi_setup_complete;
|
||||
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
gadget->ep0->driver_data = dev;
|
||||
|
||||
INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
|
||||
|
@ -996,8 +996,14 @@ static int goku_get_frame(struct usb_gadget *_gadget)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int goku_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int goku_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
static const struct usb_gadget_ops goku_ops = {
|
||||
.get_frame = goku_get_frame,
|
||||
.start = goku_start,
|
||||
.stop = goku_stop,
|
||||
// no remote wakeup
|
||||
// not selfpowered
|
||||
};
|
||||
@ -1344,7 +1350,7 @@ static struct goku_udc *the_controller;
|
||||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int goku_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct goku_udc *dev = the_controller;
|
||||
@ -1382,7 +1388,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
static void
|
||||
stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
|
||||
@ -1408,7 +1413,7 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
|
||||
udc_enable(dev);
|
||||
}
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int goku_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct goku_udc *dev = the_controller;
|
||||
unsigned long flags;
|
||||
@ -1429,8 +1434,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -1730,6 +1733,8 @@ static void goku_remove(struct pci_dev *pdev)
|
||||
|
||||
DBG(dev, "%s\n", __func__);
|
||||
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
|
||||
BUG_ON(dev->driver);
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
@ -1854,6 +1859,10 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
goto err;
|
||||
}
|
||||
dev->registered = 1;
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -255,6 +255,7 @@ static struct usb_composite_driver hidg_driver = {
|
||||
.name = "g_hid",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = __exit_p(hid_unbind),
|
||||
};
|
||||
|
||||
|
@ -1237,9 +1237,14 @@ irq_handler_t intr_handler(int i)
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
static int imx_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int imx_udc_stop(struct usb_gadget_driver *driver);
|
||||
static const struct usb_gadget_ops imx_udc_ops = {
|
||||
.get_frame = imx_udc_get_frame,
|
||||
.wakeup = imx_udc_wakeup,
|
||||
.start = imx_udc_start,
|
||||
.stop = imx_udc_stop,
|
||||
};
|
||||
|
||||
static struct imx_udc_struct controller = {
|
||||
@ -1324,7 +1329,7 @@ static struct imx_udc_struct controller = {
|
||||
* USB gadget driver functions
|
||||
*******************************************************************************
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int imx_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct imx_udc_struct *imx_usb = &controller;
|
||||
@ -1368,9 +1373,8 @@ fail:
|
||||
imx_usb->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int imx_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct imx_udc_struct *imx_usb = &controller;
|
||||
|
||||
@ -1394,7 +1398,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/*******************************************************************************
|
||||
* Module functions
|
||||
@ -1504,8 +1507,14 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
||||
imx_usb->timer.function = handle_config;
|
||||
imx_usb->timer.data = (unsigned long)imx_usb;
|
||||
|
||||
return 0;
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
|
||||
if (ret)
|
||||
goto fail4;
|
||||
|
||||
return 0;
|
||||
fail4:
|
||||
for (i = 0; i < IMX_USB_NB_EP + 1; i++)
|
||||
free_irq(imx_usb->usbd_int[i], imx_usb);
|
||||
fail3:
|
||||
clk_put(clk);
|
||||
clk_disable(clk);
|
||||
@ -1525,6 +1534,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
|
||||
struct imxusb_platform_data *pdata = pdev->dev.platform_data;
|
||||
int i;
|
||||
|
||||
usb_del_gadget_udc(&imx_usb->gadget);
|
||||
imx_udc_disable(imx_usb);
|
||||
del_timer(&imx_usb->timer);
|
||||
|
||||
|
@ -832,14 +832,16 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
switch (data->dev->gadget->speed) {
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
value = usb_ep_enable (ep, &data->desc);
|
||||
ep->desc = &data->desc;
|
||||
value = usb_ep_enable(ep);
|
||||
if (value == 0)
|
||||
data->state = STATE_EP_ENABLED;
|
||||
break;
|
||||
#ifdef CONFIG_USB_GADGET_DUALSPEED
|
||||
case USB_SPEED_HIGH:
|
||||
/* fails if caller didn't provide that descriptor... */
|
||||
value = usb_ep_enable (ep, &data->hs_desc);
|
||||
ep->desc = &data->hs_desc;
|
||||
value = usb_ep_enable(ep);
|
||||
if (value == 0)
|
||||
data->state = STATE_EP_ENABLED;
|
||||
break;
|
||||
@ -1345,7 +1347,7 @@ static void make_qualifier (struct dev_data *dev)
|
||||
qual.bDeviceProtocol = desc->bDeviceProtocol;
|
||||
|
||||
/* assumes ep0 uses the same value for both speeds ... */
|
||||
qual.bMaxPacketSize0 = desc->bMaxPacketSize0;
|
||||
qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
|
||||
|
||||
qual.bNumConfigurations = 1;
|
||||
qual.bRESERVED = 0;
|
||||
@ -1402,7 +1404,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
}
|
||||
|
||||
dev->state = STATE_DEV_CONNECTED;
|
||||
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
INFO (dev, "connected\n");
|
||||
event = next_event (dev, GADGETFS_CONNECT);
|
||||
@ -1430,6 +1431,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
|
||||
case USB_DT_DEVICE:
|
||||
value = min (w_length, (u16) sizeof *dev->dev);
|
||||
dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
|
||||
req->buf = dev->dev;
|
||||
break;
|
||||
#ifdef CONFIG_USB_GADGET_DUALSPEED
|
||||
@ -1710,7 +1712,6 @@ gadgetfs_bind (struct usb_gadget *gadget)
|
||||
set_gadget_data (gadget, dev);
|
||||
dev->gadget = gadget;
|
||||
gadget->ep0->driver_data = dev;
|
||||
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
/* preallocate control response and buffer */
|
||||
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
|
||||
|
@ -593,8 +593,8 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)
|
||||
/* ep0 */
|
||||
dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep));
|
||||
|
||||
dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%08x\n",
|
||||
i, (u32)&(dev->ep_dqh[i]));
|
||||
dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n",
|
||||
i, &(dev->ep_dqh[i]));
|
||||
|
||||
bit_mask = is_in(ep) ?
|
||||
(1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
|
||||
@ -1321,7 +1321,9 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int langwell_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int langwell_stop(struct usb_gadget_driver *driver);
|
||||
/* device controller usb_gadget_ops structure */
|
||||
static const struct usb_gadget_ops langwell_ops = {
|
||||
|
||||
@ -1342,6 +1344,9 @@ static const struct usb_gadget_ops langwell_ops = {
|
||||
|
||||
/* D+ pullup, software-controlled connect/disconnect to USB host */
|
||||
.pullup = langwell_pullup,
|
||||
|
||||
.start = langwell_start,
|
||||
.stop = langwell_stop,
|
||||
};
|
||||
|
||||
|
||||
@ -1852,7 +1857,7 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int langwell_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct langwell_udc *dev = the_controller;
|
||||
@ -1914,11 +1919,9 @@ err_unbind:
|
||||
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
|
||||
/* unregister gadget driver */
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int langwell_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct langwell_udc *dev = the_controller;
|
||||
unsigned long flags;
|
||||
@ -1965,8 +1968,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -3270,7 +3271,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
|
||||
|
||||
/* allocate device dQH memory */
|
||||
size = dev->ep_max * sizeof(struct langwell_dqh);
|
||||
dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size);
|
||||
dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
|
||||
if (size < DQH_ALIGNMENT)
|
||||
size = DQH_ALIGNMENT;
|
||||
else if ((size % DQH_ALIGNMENT) != 0) {
|
||||
@ -3285,7 +3286,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
|
||||
goto error;
|
||||
}
|
||||
dev->ep_dqh_size = size;
|
||||
dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
|
||||
dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
|
||||
|
||||
/* initialize ep0 status request structure */
|
||||
dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
|
||||
@ -3373,6 +3374,10 @@ static int langwell_udc_probe(struct pci_dev *pdev,
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
|
||||
if (retval)
|
||||
goto error;
|
||||
@ -3403,6 +3408,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
||||
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
|
||||
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
/* disable interrupt and set controller to stop state */
|
||||
langwell_udc_stop(dev);
|
||||
|
||||
@ -3464,7 +3470,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)
|
||||
|
||||
/* allocate device dQH memory */
|
||||
size = dev->ep_max * sizeof(struct langwell_dqh);
|
||||
dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size);
|
||||
dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
|
||||
if (size < DQH_ALIGNMENT)
|
||||
size = DQH_ALIGNMENT;
|
||||
else if ((size % DQH_ALIGNMENT) != 0) {
|
||||
@ -3478,7 +3484,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->ep_dqh_size = size;
|
||||
dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
|
||||
dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
|
||||
|
||||
/* create dTD dma_pool resource */
|
||||
dev->dtd_pool = dma_pool_create("langwell_dtd",
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2006-2007 Renesas Solutions Corp.
|
||||
*
|
||||
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
|
||||
* Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -691,6 +691,7 @@ static void init_controller(struct m66592 *m66592)
|
||||
|
||||
static void disable_controller(struct m66592 *m66592)
|
||||
{
|
||||
m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE);
|
||||
if (!m66592->pdata->on_chip) {
|
||||
m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
|
||||
udelay(1);
|
||||
@ -780,7 +781,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
|
||||
/* write fifo */
|
||||
if (req->req.buf) {
|
||||
if (size > 0)
|
||||
m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
|
||||
m66592_write_fifo(m66592, ep, buf, size);
|
||||
if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
|
||||
m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
|
||||
}
|
||||
@ -826,7 +827,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
|
||||
|
||||
/* write fifo */
|
||||
if (req->req.buf) {
|
||||
m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
|
||||
m66592_write_fifo(m66592, ep, buf, size);
|
||||
if ((size == 0)
|
||||
|| ((size % ep->ep.maxpacket) != 0)
|
||||
|| ((bufsize != ep->ep.maxpacket)
|
||||
@ -1048,10 +1049,30 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
|
||||
|
||||
static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
u16 tmp;
|
||||
int timeout = 3000;
|
||||
|
||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_DEVICE:
|
||||
control_end(m66592, 1);
|
||||
switch (le16_to_cpu(ctrl->wValue)) {
|
||||
case USB_DEVICE_TEST_MODE:
|
||||
control_end(m66592, 1);
|
||||
/* Wait for the completion of status stage */
|
||||
do {
|
||||
tmp = m66592_read(m66592, M66592_INTSTS0) &
|
||||
M66592_CTSQ;
|
||||
udelay(1);
|
||||
} while (tmp != M66592_CS_IDST || timeout-- > 0);
|
||||
|
||||
if (tmp == M66592_CS_IDST)
|
||||
m66592_bset(m66592,
|
||||
le16_to_cpu(ctrl->wIndex >> 8),
|
||||
M66592_TESTMODE);
|
||||
break;
|
||||
default:
|
||||
pipe_stall(m66592, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
control_end(m66592, 1);
|
||||
@ -1454,7 +1475,7 @@ static struct usb_ep_ops m66592_ep_ops = {
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static struct m66592 *the_controller;
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int m66592_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct m66592 *m66592 = the_controller;
|
||||
@ -1506,9 +1527,8 @@ error:
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int m66592_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct m66592 *m66592 = the_controller;
|
||||
unsigned long flags;
|
||||
@ -1533,7 +1553,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
m66592->driver = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int m66592_get_frame(struct usb_gadget *_gadget)
|
||||
@ -1542,14 +1561,34 @@ static int m66592_get_frame(struct usb_gadget *_gadget)
|
||||
return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;
|
||||
}
|
||||
|
||||
static int m66592_pullup(struct usb_gadget *gadget, int is_on)
|
||||
{
|
||||
struct m66592 *m66592 = gadget_to_m66592(gadget);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&m66592->lock, flags);
|
||||
if (is_on)
|
||||
m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
|
||||
else
|
||||
m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
|
||||
spin_unlock_irqrestore(&m66592->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_gadget_ops m66592_gadget_ops = {
|
||||
.get_frame = m66592_get_frame,
|
||||
.start = m66592_start,
|
||||
.stop = m66592_stop,
|
||||
.pullup = m66592_pullup,
|
||||
};
|
||||
|
||||
static int __exit m66592_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
usb_del_gadget_udc(&m66592->gadget);
|
||||
|
||||
del_timer_sync(&m66592->timer);
|
||||
iounmap(m66592->reg);
|
||||
free_irq(platform_get_irq(pdev, 0), m66592);
|
||||
@ -1691,9 +1730,16 @@ static int __init m66592_probe(struct platform_device *pdev)
|
||||
|
||||
init_controller(m66592);
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
|
||||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
|
||||
|
||||
clean_up3:
|
||||
#ifdef CONFIG_HAVE_CLK
|
||||
if (m66592->pdata->on_chip) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2006-2007 Renesas Solutions Corp.
|
||||
*
|
||||
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
|
||||
* Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -561,11 +561,26 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,
|
||||
iowrite16(val, m66592->reg + offset);
|
||||
}
|
||||
|
||||
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
|
||||
unsigned long offset)
|
||||
{
|
||||
u16 tmp;
|
||||
tmp = m66592_read(m66592, offset);
|
||||
tmp = tmp & (~pat);
|
||||
tmp = tmp | val;
|
||||
m66592_write(m66592, tmp, offset);
|
||||
}
|
||||
|
||||
#define m66592_bclr(m66592, val, offset) \
|
||||
m66592_mdfy(m66592, 0, val, offset)
|
||||
#define m66592_bset(m66592, val, offset) \
|
||||
m66592_mdfy(m66592, val, 0, offset)
|
||||
|
||||
static inline void m66592_write_fifo(struct m66592 *m66592,
|
||||
unsigned long offset,
|
||||
struct m66592_ep *ep,
|
||||
void *buf, unsigned long len)
|
||||
{
|
||||
void __iomem *fifoaddr = m66592->reg + offset;
|
||||
void __iomem *fifoaddr = m66592->reg + ep->fifoaddr;
|
||||
|
||||
if (m66592->pdata->on_chip) {
|
||||
unsigned long count;
|
||||
@ -591,26 +606,15 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
|
||||
iowrite16_rep(fifoaddr, buf, len);
|
||||
if (odd) {
|
||||
unsigned char *p = buf + len*2;
|
||||
if (m66592->pdata->wr0_shorted_to_wr1)
|
||||
m66592_bclr(m66592, M66592_MBW_16, ep->fifosel);
|
||||
iowrite8(*p, fifoaddr);
|
||||
if (m66592->pdata->wr0_shorted_to_wr1)
|
||||
m66592_bset(m66592, M66592_MBW_16, ep->fifosel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
|
||||
unsigned long offset)
|
||||
{
|
||||
u16 tmp;
|
||||
tmp = m66592_read(m66592, offset);
|
||||
tmp = tmp & (~pat);
|
||||
tmp = tmp | val;
|
||||
m66592_write(m66592, tmp, offset);
|
||||
}
|
||||
|
||||
#define m66592_bclr(m66592, val, offset) \
|
||||
m66592_mdfy(m66592, 0, val, offset)
|
||||
#define m66592_bset(m66592, val, offset) \
|
||||
m66592_mdfy(m66592, val, 0, offset)
|
||||
|
||||
#endif /* ifndef __M66592_UDC_H__ */
|
||||
|
||||
|
||||
|
@ -169,6 +169,7 @@ static struct usb_composite_driver msg_driver = {
|
||||
.name = "g_mass_storage",
|
||||
.dev = &msg_device_desc,
|
||||
.iProduct = DRIVER_DESC,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.needs_serial = 1,
|
||||
};
|
||||
|
||||
|
@ -351,6 +351,7 @@ static struct usb_composite_driver multi_driver = {
|
||||
.name = "g_multi",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = __exit_p(multi_unbind),
|
||||
.iProduct = DRIVER_DESC,
|
||||
.needs_serial = 1,
|
||||
|
@ -1128,6 +1128,9 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int mv_udc_stop(struct usb_gadget_driver *driver);
|
||||
/* device controller usb_gadget_ops structure */
|
||||
static const struct usb_gadget_ops mv_ops = {
|
||||
|
||||
@ -1139,6 +1142,8 @@ static const struct usb_gadget_ops mv_ops = {
|
||||
|
||||
/* D+ pullup, software-controlled connect/disconnect to USB host */
|
||||
.pullup = mv_udc_pullup,
|
||||
.start = mv_udc_start,
|
||||
.stop = mv_udc_stop,
|
||||
};
|
||||
|
||||
static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
|
||||
@ -1230,7 +1235,7 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
|
||||
}
|
||||
}
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int mv_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
@ -1270,9 +1275,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int mv_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
unsigned long flags;
|
||||
@ -1296,7 +1300,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
static int
|
||||
udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
|
||||
@ -1880,9 +1883,10 @@ static void gadget_release(struct device *_dev)
|
||||
static int mv_udc_remove(struct platform_device *dev)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
|
||||
DECLARE_COMPLETION(done);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
|
||||
udc->done = &done;
|
||||
|
||||
/* free memory allocated in probe */
|
||||
@ -2074,11 +2078,12 @@ int mv_udc_probe(struct platform_device *dev)
|
||||
|
||||
the_controller = udc;
|
||||
|
||||
goto out;
|
||||
retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
|
||||
if (!retval)
|
||||
return retval;
|
||||
error:
|
||||
if (udc)
|
||||
mv_udc_remove(udc->dev);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -2126,7 +2131,7 @@ static struct platform_driver udc_driver = {
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:pxa-u2o");
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
|
||||
|
@ -228,6 +228,7 @@ static struct usb_composite_driver ncm_driver = {
|
||||
.name = "g_ncm",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = __exit_p(gncm_unbind),
|
||||
};
|
||||
|
||||
|
2752
drivers/usb/gadget/net2272.c
Normal file
2752
drivers/usb/gadget/net2272.c
Normal file
File diff suppressed because it is too large
Load Diff
601
drivers/usb/gadget/net2272.h
Normal file
601
drivers/usb/gadget/net2272.h
Normal file
@ -0,0 +1,601 @@
|
||||
/*
|
||||
* PLX NET2272 high/full speed USB device controller
|
||||
*
|
||||
* Copyright (C) 2005-2006 PLX Technology, Inc.
|
||||
* Copyright (C) 2006-2011 Analog Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __NET2272_H__
|
||||
#define __NET2272_H__
|
||||
|
||||
/* Main Registers */
|
||||
#define REGADDRPTR 0x00
|
||||
#define REGDATA 0x01
|
||||
#define IRQSTAT0 0x02
|
||||
#define ENDPOINT_0_INTERRUPT 0
|
||||
#define ENDPOINT_A_INTERRUPT 1
|
||||
#define ENDPOINT_B_INTERRUPT 2
|
||||
#define ENDPOINT_C_INTERRUPT 3
|
||||
#define VIRTUALIZED_ENDPOINT_INTERRUPT 4
|
||||
#define SETUP_PACKET_INTERRUPT 5
|
||||
#define DMA_DONE_INTERRUPT 6
|
||||
#define SOF_INTERRUPT 7
|
||||
#define IRQSTAT1 0x03
|
||||
#define CONTROL_STATUS_INTERRUPT 1
|
||||
#define VBUS_INTERRUPT 2
|
||||
#define SUSPEND_REQUEST_INTERRUPT 3
|
||||
#define SUSPEND_REQUEST_CHANGE_INTERRUPT 4
|
||||
#define RESUME_INTERRUPT 5
|
||||
#define ROOT_PORT_RESET_INTERRUPT 6
|
||||
#define RESET_STATUS 7
|
||||
#define PAGESEL 0x04
|
||||
#define DMAREQ 0x1c
|
||||
#define DMA_ENDPOINT_SELECT 0
|
||||
#define DREQ_POLARITY 1
|
||||
#define DACK_POLARITY 2
|
||||
#define EOT_POLARITY 3
|
||||
#define DMA_CONTROL_DACK 4
|
||||
#define DMA_REQUEST_ENABLE 5
|
||||
#define DMA_REQUEST 6
|
||||
#define DMA_BUFFER_VALID 7
|
||||
#define SCRATCH 0x1d
|
||||
#define IRQENB0 0x20
|
||||
#define ENDPOINT_0_INTERRUPT_ENABLE 0
|
||||
#define ENDPOINT_A_INTERRUPT_ENABLE 1
|
||||
#define ENDPOINT_B_INTERRUPT_ENABLE 2
|
||||
#define ENDPOINT_C_INTERRUPT_ENABLE 3
|
||||
#define VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE 4
|
||||
#define SETUP_PACKET_INTERRUPT_ENABLE 5
|
||||
#define DMA_DONE_INTERRUPT_ENABLE 6
|
||||
#define SOF_INTERRUPT_ENABLE 7
|
||||
#define IRQENB1 0x21
|
||||
#define VBUS_INTERRUPT_ENABLE 2
|
||||
#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
|
||||
#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 4
|
||||
#define RESUME_INTERRUPT_ENABLE 5
|
||||
#define ROOT_PORT_RESET_INTERRUPT_ENABLE 6
|
||||
#define LOCCTL 0x22
|
||||
#define DATA_WIDTH 0
|
||||
#define LOCAL_CLOCK_OUTPUT 1
|
||||
#define LOCAL_CLOCK_OUTPUT_OFF 0
|
||||
#define LOCAL_CLOCK_OUTPUT_3_75MHZ 1
|
||||
#define LOCAL_CLOCK_OUTPUT_7_5MHZ 2
|
||||
#define LOCAL_CLOCK_OUTPUT_15MHZ 3
|
||||
#define LOCAL_CLOCK_OUTPUT_30MHZ 4
|
||||
#define LOCAL_CLOCK_OUTPUT_60MHZ 5
|
||||
#define DMA_SPLIT_BUS_MODE 4
|
||||
#define BYTE_SWAP 5
|
||||
#define BUFFER_CONFIGURATION 6
|
||||
#define BUFFER_CONFIGURATION_EPA512_EPB512 0
|
||||
#define BUFFER_CONFIGURATION_EPA1024_EPB512 1
|
||||
#define BUFFER_CONFIGURATION_EPA1024_EPB1024 2
|
||||
#define BUFFER_CONFIGURATION_EPA1024DB 3
|
||||
#define CHIPREV_LEGACY 0x23
|
||||
#define NET2270_LEGACY_REV 0x40
|
||||
#define LOCCTL1 0x24
|
||||
#define DMA_MODE 0
|
||||
#define SLOW_DREQ 0
|
||||
#define FAST_DREQ 1
|
||||
#define BURST_MODE 2
|
||||
#define DMA_DACK_ENABLE 2
|
||||
#define CHIPREV_2272 0x25
|
||||
#define CHIPREV_NET2272_R1 0x10
|
||||
#define CHIPREV_NET2272_R1A 0x11
|
||||
/* USB Registers */
|
||||
#define USBCTL0 0x18
|
||||
#define IO_WAKEUP_ENABLE 1
|
||||
#define USB_DETECT_ENABLE 3
|
||||
#define USB_ROOT_PORT_WAKEUP_ENABLE 5
|
||||
#define USBCTL1 0x19
|
||||
#define VBUS_PIN 0
|
||||
#define USB_FULL_SPEED 1
|
||||
#define USB_HIGH_SPEED 2
|
||||
#define GENERATE_RESUME 3
|
||||
#define VIRTUAL_ENDPOINT_ENABLE 4
|
||||
#define FRAME0 0x1a
|
||||
#define FRAME1 0x1b
|
||||
#define OURADDR 0x30
|
||||
#define FORCE_IMMEDIATE 7
|
||||
#define USBDIAG 0x31
|
||||
#define FORCE_TRANSMIT_CRC_ERROR 0
|
||||
#define PREVENT_TRANSMIT_BIT_STUFF 1
|
||||
#define FORCE_RECEIVE_ERROR 2
|
||||
#define FAST_TIMES 4
|
||||
#define USBTEST 0x32
|
||||
#define TEST_MODE_SELECT 0
|
||||
#define NORMAL_OPERATION 0
|
||||
#define TEST_J 1
|
||||
#define TEST_K 2
|
||||
#define TEST_SE0_NAK 3
|
||||
#define TEST_PACKET 4
|
||||
#define TEST_FORCE_ENABLE 5
|
||||
#define XCVRDIAG 0x33
|
||||
#define FORCE_FULL_SPEED 2
|
||||
#define FORCE_HIGH_SPEED 3
|
||||
#define OPMODE 4
|
||||
#define NORMAL_OPERATION 0
|
||||
#define NON_DRIVING 1
|
||||
#define DISABLE_BITSTUFF_AND_NRZI_ENCODE 2
|
||||
#define LINESTATE 6
|
||||
#define SE0_STATE 0
|
||||
#define J_STATE 1
|
||||
#define K_STATE 2
|
||||
#define SE1_STATE 3
|
||||
#define VIRTOUT0 0x34
|
||||
#define VIRTOUT1 0x35
|
||||
#define VIRTIN0 0x36
|
||||
#define VIRTIN1 0x37
|
||||
#define SETUP0 0x40
|
||||
#define SETUP1 0x41
|
||||
#define SETUP2 0x42
|
||||
#define SETUP3 0x43
|
||||
#define SETUP4 0x44
|
||||
#define SETUP5 0x45
|
||||
#define SETUP6 0x46
|
||||
#define SETUP7 0x47
|
||||
/* Endpoint Registers (Paged via PAGESEL) */
|
||||
#define EP_DATA 0x05
|
||||
#define EP_STAT0 0x06
|
||||
#define DATA_IN_TOKEN_INTERRUPT 0
|
||||
#define DATA_OUT_TOKEN_INTERRUPT 1
|
||||
#define DATA_PACKET_TRANSMITTED_INTERRUPT 2
|
||||
#define DATA_PACKET_RECEIVED_INTERRUPT 3
|
||||
#define SHORT_PACKET_TRANSFERRED_INTERRUPT 4
|
||||
#define NAK_OUT_PACKETS 5
|
||||
#define BUFFER_EMPTY 6
|
||||
#define BUFFER_FULL 7
|
||||
#define EP_STAT1 0x07
|
||||
#define TIMEOUT 0
|
||||
#define USB_OUT_ACK_SENT 1
|
||||
#define USB_OUT_NAK_SENT 2
|
||||
#define USB_IN_ACK_RCVD 3
|
||||
#define USB_IN_NAK_SENT 4
|
||||
#define USB_STALL_SENT 5
|
||||
#define LOCAL_OUT_ZLP 6
|
||||
#define BUFFER_FLUSH 7
|
||||
#define EP_TRANSFER0 0x08
|
||||
#define EP_TRANSFER1 0x09
|
||||
#define EP_TRANSFER2 0x0a
|
||||
#define EP_IRQENB 0x0b
|
||||
#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0
|
||||
#define DATA_OUT_TOKEN_INTERRUPT_ENABLE 1
|
||||
#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2
|
||||
#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3
|
||||
#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 4
|
||||
#define EP_AVAIL0 0x0c
|
||||
#define EP_AVAIL1 0x0d
|
||||
#define EP_RSPCLR 0x0e
|
||||
#define EP_RSPSET 0x0f
|
||||
#define ENDPOINT_HALT 0
|
||||
#define ENDPOINT_TOGGLE 1
|
||||
#define NAK_OUT_PACKETS_MODE 2
|
||||
#define CONTROL_STATUS_PHASE_HANDSHAKE 3
|
||||
#define INTERRUPT_MODE 4
|
||||
#define AUTOVALIDATE 5
|
||||
#define HIDE_STATUS_PHASE 6
|
||||
#define ALT_NAK_OUT_PACKETS 7
|
||||
#define EP_MAXPKT0 0x28
|
||||
#define EP_MAXPKT1 0x29
|
||||
#define ADDITIONAL_TRANSACTION_OPPORTUNITIES 3
|
||||
#define NONE_ADDITIONAL_TRANSACTION 0
|
||||
#define ONE_ADDITIONAL_TRANSACTION 1
|
||||
#define TWO_ADDITIONAL_TRANSACTION 2
|
||||
#define EP_CFG 0x2a
|
||||
#define ENDPOINT_NUMBER 0
|
||||
#define ENDPOINT_DIRECTION 4
|
||||
#define ENDPOINT_TYPE 5
|
||||
#define ENDPOINT_ENABLE 7
|
||||
#define EP_HBW 0x2b
|
||||
#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 0
|
||||
#define DATA0_PID 0
|
||||
#define DATA1_PID 1
|
||||
#define DATA2_PID 2
|
||||
#define MDATA_PID 3
|
||||
#define EP_BUFF_STATES 0x2c
|
||||
#define BUFFER_A_STATE 0
|
||||
#define BUFFER_B_STATE 2
|
||||
#define BUFF_FREE 0
|
||||
#define BUFF_VALID 1
|
||||
#define BUFF_LCL 2
|
||||
#define BUFF_USB 3
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define PCI_DEVICE_ID_RDK1 0x9054
|
||||
|
||||
/* PCI-RDK EPLD Registers */
|
||||
#define RDK_EPLD_IO_REGISTER1 0x00000000
|
||||
#define RDK_EPLD_USB_RESET 0
|
||||
#define RDK_EPLD_USB_POWERDOWN 1
|
||||
#define RDK_EPLD_USB_WAKEUP 2
|
||||
#define RDK_EPLD_USB_EOT 3
|
||||
#define RDK_EPLD_DPPULL 4
|
||||
#define RDK_EPLD_IO_REGISTER2 0x00000004
|
||||
#define RDK_EPLD_BUSWIDTH 0
|
||||
#define RDK_EPLD_USER 2
|
||||
#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3
|
||||
#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4
|
||||
#define RDK_EPLD_STATUS_REGISTER 0x00000008
|
||||
#define RDK_EPLD_USB_LRESET 0
|
||||
#define RDK_EPLD_REVISION_REGISTER 0x0000000c
|
||||
|
||||
/* PCI-RDK PLX 9054 Registers */
|
||||
#define INTCSR 0x68
|
||||
#define PCI_INTERRUPT_ENABLE 8
|
||||
#define LOCAL_INTERRUPT_INPUT_ENABLE 11
|
||||
#define LOCAL_INPUT_INTERRUPT_ACTIVE 15
|
||||
#define LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE 18
|
||||
#define LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE 19
|
||||
#define DMA_CHANNEL_0_INTERRUPT_ACTIVE 21
|
||||
#define DMA_CHANNEL_1_INTERRUPT_ACTIVE 22
|
||||
#define CNTRL 0x6C
|
||||
#define RELOAD_CONFIGURATION_REGISTERS 29
|
||||
#define PCI_ADAPTER_SOFTWARE_RESET 30
|
||||
#define DMAMODE0 0x80
|
||||
#define LOCAL_BUS_WIDTH 0
|
||||
#define INTERNAL_WAIT_STATES 2
|
||||
#define TA_READY_INPUT_ENABLE 6
|
||||
#define LOCAL_BURST_ENABLE 8
|
||||
#define SCATTER_GATHER_MODE 9
|
||||
#define DONE_INTERRUPT_ENABLE 10
|
||||
#define LOCAL_ADDRESSING_MODE 11
|
||||
#define DEMAND_MODE 12
|
||||
#define DMA_EOT_ENABLE 14
|
||||
#define FAST_SLOW_TERMINATE_MODE_SELECT 15
|
||||
#define DMA_CHANNEL_INTERRUPT_SELECT 17
|
||||
#define DMAPADR0 0x84
|
||||
#define DMALADR0 0x88
|
||||
#define DMASIZ0 0x8c
|
||||
#define DMADPR0 0x90
|
||||
#define DESCRIPTOR_LOCATION 0
|
||||
#define END_OF_CHAIN 1
|
||||
#define INTERRUPT_AFTER_TERMINAL_COUNT 2
|
||||
#define DIRECTION_OF_TRANSFER 3
|
||||
#define DMACSR0 0xa8
|
||||
#define CHANNEL_ENABLE 0
|
||||
#define CHANNEL_START 1
|
||||
#define CHANNEL_ABORT 2
|
||||
#define CHANNEL_CLEAR_INTERRUPT 3
|
||||
#define CHANNEL_DONE 4
|
||||
#define DMATHR 0xb0
|
||||
#define LBRD1 0xf8
|
||||
#define MEMORY_SPACE_LOCAL_BUS_WIDTH 0
|
||||
#define W8_BIT 0
|
||||
#define W16_BIT 1
|
||||
|
||||
/* Special OR'ing of INTCSR bits */
|
||||
#define LOCAL_INTERRUPT_TEST \
|
||||
((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \
|
||||
(1 << LOCAL_INTERRUPT_INPUT_ENABLE))
|
||||
|
||||
#define DMA_CHANNEL_0_TEST \
|
||||
((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \
|
||||
(1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE))
|
||||
|
||||
#define DMA_CHANNEL_1_TEST \
|
||||
((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \
|
||||
(1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE))
|
||||
|
||||
/* EPLD Registers */
|
||||
#define RDK_EPLD_IO_REGISTER1 0x00000000
|
||||
#define RDK_EPLD_USB_RESET 0
|
||||
#define RDK_EPLD_USB_POWERDOWN 1
|
||||
#define RDK_EPLD_USB_WAKEUP 2
|
||||
#define RDK_EPLD_USB_EOT 3
|
||||
#define RDK_EPLD_DPPULL 4
|
||||
#define RDK_EPLD_IO_REGISTER2 0x00000004
|
||||
#define RDK_EPLD_BUSWIDTH 0
|
||||
#define RDK_EPLD_USER 2
|
||||
#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3
|
||||
#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4
|
||||
#define RDK_EPLD_STATUS_REGISTER 0x00000008
|
||||
#define RDK_EPLD_USB_LRESET 0
|
||||
#define RDK_EPLD_REVISION_REGISTER 0x0000000c
|
||||
|
||||
#define EPLD_IO_CONTROL_REGISTER 0x400
|
||||
#define NET2272_RESET 0
|
||||
#define BUSWIDTH 1
|
||||
#define MPX_MODE 3
|
||||
#define USER 4
|
||||
#define DMA_TIMEOUT_ENABLE 5
|
||||
#define DMA_CTL_DACK 6
|
||||
#define EPLD_DMA_ENABLE 7
|
||||
#define EPLD_DMA_CONTROL_REGISTER 0x800
|
||||
#define SPLIT_DMA_MODE 0
|
||||
#define SPLIT_DMA_DIRECTION 1
|
||||
#define SPLIT_DMA_ENABLE 2
|
||||
#define SPLIT_DMA_INTERRUPT_ENABLE 3
|
||||
#define SPLIT_DMA_INTERRUPT 4
|
||||
#define EPLD_DMA_MODE 5
|
||||
#define EPLD_DMA_CONTROLLER_ENABLE 7
|
||||
#define SPLIT_DMA_ADDRESS_LOW 0xc00
|
||||
#define SPLIT_DMA_ADDRESS_HIGH 0x1000
|
||||
#define SPLIT_DMA_BYTE_COUNT_LOW 0x1400
|
||||
#define SPLIT_DMA_BYTE_COUNT_HIGH 0x1800
|
||||
#define EPLD_REVISION_REGISTER 0x1c00
|
||||
#define SPLIT_DMA_RAM 0x4000
|
||||
#define DMA_RAM_SIZE 0x1000
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define PCI_DEVICE_ID_RDK2 0x3272
|
||||
|
||||
/* PCI-RDK version 2 registers */
|
||||
|
||||
/* Main Control Registers */
|
||||
|
||||
#define RDK2_IRQENB 0x00
|
||||
#define RDK2_IRQSTAT 0x04
|
||||
#define PB7 23
|
||||
#define PB6 22
|
||||
#define PB5 21
|
||||
#define PB4 20
|
||||
#define PB3 19
|
||||
#define PB2 18
|
||||
#define PB1 17
|
||||
#define PB0 16
|
||||
#define GP3 23
|
||||
#define GP2 23
|
||||
#define GP1 23
|
||||
#define GP0 23
|
||||
#define DMA_RETRY_ABORT 6
|
||||
#define DMA_PAUSE_DONE 5
|
||||
#define DMA_ABORT_DONE 4
|
||||
#define DMA_OUT_FIFO_TRANSFER_DONE 3
|
||||
#define DMA_LOCAL_DONE 2
|
||||
#define DMA_PCI_DONE 1
|
||||
#define NET2272_PCI_IRQ 0
|
||||
|
||||
#define RDK2_LOCCTLRDK 0x08
|
||||
#define CHIP_RESET 3
|
||||
#define SPLIT_DMA 2
|
||||
#define MULTIPLEX_MODE 1
|
||||
#define BUS_WIDTH 0
|
||||
|
||||
#define RDK2_GPIOCTL 0x10
|
||||
#define GP3_OUT_ENABLE 7
|
||||
#define GP2_OUT_ENABLE 6
|
||||
#define GP1_OUT_ENABLE 5
|
||||
#define GP0_OUT_ENABLE 4
|
||||
#define GP3_DATA 3
|
||||
#define GP2_DATA 2
|
||||
#define GP1_DATA 1
|
||||
#define GP0_DATA 0
|
||||
|
||||
#define RDK2_LEDSW 0x14
|
||||
#define LED3 27
|
||||
#define LED2 26
|
||||
#define LED1 25
|
||||
#define LED0 24
|
||||
#define PBUTTON 16
|
||||
#define DIPSW 0
|
||||
|
||||
#define RDK2_DIAG 0x18
|
||||
#define RDK2_FAST_TIMES 2
|
||||
#define FORCE_PCI_SERR 1
|
||||
#define FORCE_PCI_INT 0
|
||||
#define RDK2_FPGAREV 0x1C
|
||||
|
||||
/* Dma Control registers */
|
||||
#define RDK2_DMACTL 0x80
|
||||
#define ADDR_HOLD 24
|
||||
#define RETRY_COUNT 16 /* 23:16 */
|
||||
#define FIFO_THRESHOLD 11 /* 15:11 */
|
||||
#define MEM_WRITE_INVALIDATE 10
|
||||
#define READ_MULTIPLE 9
|
||||
#define READ_LINE 8
|
||||
#define RDK2_DMA_MODE 6 /* 7:6 */
|
||||
#define CONTROL_DACK 5
|
||||
#define EOT_ENABLE 4
|
||||
#define EOT_POLARITY 3
|
||||
#define DACK_POLARITY 2
|
||||
#define DREQ_POLARITY 1
|
||||
#define DMA_ENABLE 0
|
||||
|
||||
#define RDK2_DMASTAT 0x84
|
||||
#define GATHER_COUNT 12 /* 14:12 */
|
||||
#define FIFO_COUNT 6 /* 11:6 */
|
||||
#define FIFO_FLUSH 5
|
||||
#define FIFO_TRANSFER 4
|
||||
#define PAUSE_DONE 3
|
||||
#define ABORT_DONE 2
|
||||
#define DMA_ABORT 1
|
||||
#define DMA_START 0
|
||||
|
||||
#define RDK2_DMAPCICOUNT 0x88
|
||||
#define DMA_DIRECTION 31
|
||||
#define DMA_PCI_BYTE_COUNT 0 /* 0:23 */
|
||||
|
||||
#define RDK2_DMALOCCOUNT 0x8C /* 0:23 dma local byte count */
|
||||
|
||||
#define RDK2_DMAADDR 0x90 /* 2:31 PCI bus starting address */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define REG_INDEXED_THRESHOLD (1 << 5)
|
||||
|
||||
/* DRIVER DATA STRUCTURES and UTILITIES */
|
||||
struct net2272_ep {
|
||||
struct usb_ep ep;
|
||||
struct net2272 *dev;
|
||||
unsigned long irqs;
|
||||
|
||||
/* analogous to a host-side qh */
|
||||
struct list_head queue;
|
||||
const struct usb_endpoint_descriptor *desc;
|
||||
unsigned num:8,
|
||||
fifo_size:12,
|
||||
stopped:1,
|
||||
wedged:1,
|
||||
is_in:1,
|
||||
is_iso:1,
|
||||
dma:1,
|
||||
not_empty:1;
|
||||
};
|
||||
|
||||
struct net2272 {
|
||||
/* each device provides one gadget, several endpoints */
|
||||
struct usb_gadget gadget;
|
||||
struct device *dev;
|
||||
unsigned short dev_id;
|
||||
|
||||
spinlock_t lock;
|
||||
struct net2272_ep ep[4];
|
||||
struct usb_gadget_driver *driver;
|
||||
unsigned protocol_stall:1,
|
||||
softconnect:1,
|
||||
is_selfpowered:1,
|
||||
wakeup:1,
|
||||
dma_eot_polarity:1,
|
||||
dma_dack_polarity:1,
|
||||
dma_dreq_polarity:1,
|
||||
dma_busy:1;
|
||||
u16 chiprev;
|
||||
u8 pagesel;
|
||||
|
||||
unsigned int irq;
|
||||
unsigned short fifo_mode;
|
||||
|
||||
unsigned int base_shift;
|
||||
u16 __iomem *base_addr;
|
||||
union {
|
||||
#ifdef CONFIG_PCI
|
||||
struct {
|
||||
void __iomem *plx9054_base_addr;
|
||||
void __iomem *epld_base_addr;
|
||||
} rdk1;
|
||||
struct {
|
||||
/* Bar0, Bar1 is base_addr both mem-mapped */
|
||||
void __iomem *fpga_base_addr;
|
||||
} rdk2;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
static void __iomem *
|
||||
net2272_reg_addr(struct net2272 *dev, unsigned int reg)
|
||||
{
|
||||
return dev->base_addr + (reg << dev->base_shift);
|
||||
}
|
||||
|
||||
static void
|
||||
net2272_write(struct net2272 *dev, unsigned int reg, u8 value)
|
||||
{
|
||||
if (reg >= REG_INDEXED_THRESHOLD) {
|
||||
/*
|
||||
* Indexed register; use REGADDRPTR/REGDATA
|
||||
* - Save and restore REGADDRPTR. This prevents REGADDRPTR from
|
||||
* changes between other code sections, but it is time consuming.
|
||||
* - Performance tips: either do not save and restore REGADDRPTR (if it
|
||||
* is safe) or do save/restore operations only in critical sections.
|
||||
u8 tmp = readb(dev->base_addr + REGADDRPTR);
|
||||
*/
|
||||
writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR));
|
||||
writeb(value, net2272_reg_addr(dev, REGDATA));
|
||||
/* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */
|
||||
} else
|
||||
writeb(value, net2272_reg_addr(dev, reg));
|
||||
}
|
||||
|
||||
static u8
|
||||
net2272_read(struct net2272 *dev, unsigned int reg)
|
||||
{
|
||||
u8 ret;
|
||||
|
||||
if (reg >= REG_INDEXED_THRESHOLD) {
|
||||
/*
|
||||
* Indexed register; use REGADDRPTR/REGDATA
|
||||
* - Save and restore REGADDRPTR. This prevents REGADDRPTR from
|
||||
* changes between other code sections, but it is time consuming.
|
||||
* - Performance tips: either do not save and restore REGADDRPTR (if it
|
||||
* is safe) or do save/restore operations only in critical sections.
|
||||
u8 tmp = readb(dev->base_addr + REGADDRPTR);
|
||||
*/
|
||||
writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR));
|
||||
ret = readb(net2272_reg_addr(dev, REGDATA));
|
||||
/* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */
|
||||
} else
|
||||
ret = readb(net2272_reg_addr(dev, reg));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value)
|
||||
{
|
||||
struct net2272 *dev = ep->dev;
|
||||
|
||||
if (dev->pagesel != ep->num) {
|
||||
net2272_write(dev, PAGESEL, ep->num);
|
||||
dev->pagesel = ep->num;
|
||||
}
|
||||
net2272_write(dev, reg, value);
|
||||
}
|
||||
|
||||
static u8
|
||||
net2272_ep_read(struct net2272_ep *ep, unsigned int reg)
|
||||
{
|
||||
struct net2272 *dev = ep->dev;
|
||||
|
||||
if (dev->pagesel != ep->num) {
|
||||
net2272_write(dev, PAGESEL, ep->num);
|
||||
dev->pagesel = ep->num;
|
||||
}
|
||||
return net2272_read(dev, reg);
|
||||
}
|
||||
|
||||
static void allow_status(struct net2272_ep *ep)
|
||||
{
|
||||
/* ep0 only */
|
||||
net2272_ep_write(ep, EP_RSPCLR,
|
||||
(1 << CONTROL_STATUS_PHASE_HANDSHAKE) |
|
||||
(1 << ALT_NAK_OUT_PACKETS) |
|
||||
(1 << NAK_OUT_PACKETS_MODE));
|
||||
ep->stopped = 1;
|
||||
}
|
||||
|
||||
static void set_halt(struct net2272_ep *ep)
|
||||
{
|
||||
/* ep0 and bulk/intr endpoints */
|
||||
net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE);
|
||||
net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT);
|
||||
}
|
||||
|
||||
static void clear_halt(struct net2272_ep *ep)
|
||||
{
|
||||
/* ep0 and bulk/intr endpoints */
|
||||
net2272_ep_write(ep, EP_RSPCLR,
|
||||
(1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE));
|
||||
}
|
||||
|
||||
/* count (<= 4) bytes in the next fifo write will be valid */
|
||||
static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count)
|
||||
{
|
||||
/* net2272_ep_write will truncate to u8 for us */
|
||||
net2272_ep_write(ep, EP_TRANSFER2, count >> 16);
|
||||
net2272_ep_write(ep, EP_TRANSFER1, count >> 8);
|
||||
net2272_ep_write(ep, EP_TRANSFER0, count);
|
||||
}
|
||||
|
||||
struct net2272_request {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
unsigned mapped:1,
|
||||
valid:1;
|
||||
};
|
||||
|
||||
#endif
|
@ -1410,11 +1410,17 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net2280_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int net2280_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
static const struct usb_gadget_ops net2280_ops = {
|
||||
.get_frame = net2280_get_frame,
|
||||
.wakeup = net2280_wakeup,
|
||||
.set_selfpowered = net2280_set_selfpowered,
|
||||
.pullup = net2280_pullup,
|
||||
.start = net2280_start,
|
||||
.stop = net2280_stop,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1738,62 +1744,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
|
||||
list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
|
||||
}
|
||||
|
||||
/* just declare this in any driver that really need it */
|
||||
extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
|
||||
|
||||
/**
|
||||
* net2280_set_fifo_mode - change allocation of fifo buffers
|
||||
* @gadget: access to the net2280 device that will be updated
|
||||
* @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
|
||||
* 1 for two 2kB buffers (ep-a and ep-b only);
|
||||
* 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
|
||||
*
|
||||
* returns zero on success, else negative errno. when this succeeds,
|
||||
* the contents of gadget->ep_list may have changed.
|
||||
*
|
||||
* you may only call this function when endpoints a-d are all disabled.
|
||||
* use it whenever extra hardware buffering can help performance, such
|
||||
* as before enabling "high bandwidth" interrupt endpoints that use
|
||||
* maxpacket bigger than 512 (when double buffering would otherwise
|
||||
* be unavailable).
|
||||
*/
|
||||
int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
|
||||
{
|
||||
int i;
|
||||
struct net2280 *dev;
|
||||
int status = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!gadget)
|
||||
return -ENODEV;
|
||||
dev = container_of (gadget, struct net2280, gadget);
|
||||
|
||||
spin_lock_irqsave (&dev->lock, flags);
|
||||
|
||||
for (i = 1; i <= 4; i++)
|
||||
if (dev->ep [i].desc) {
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (mode < 0 || mode > 2)
|
||||
status = -EINVAL;
|
||||
if (status == 0)
|
||||
set_fifo_mode (dev, mode);
|
||||
spin_unlock_irqrestore (&dev->lock, flags);
|
||||
|
||||
if (status == 0) {
|
||||
if (mode == 1)
|
||||
DEBUG (dev, "fifo: ep-a 2K, ep-b 2K\n");
|
||||
else if (mode == 2)
|
||||
DEBUG (dev, "fifo: ep-a 2K, ep-b 1K, ep-c 1K\n");
|
||||
/* else all are 1K */
|
||||
}
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL (net2280_set_fifo_mode);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* keeping it simple:
|
||||
* - one bus driver, initted first;
|
||||
* - one function driver, initted second
|
||||
@ -1930,7 +1880,7 @@ static void ep0_start (struct net2280 *dev)
|
||||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int net2280_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct net2280 *dev = the_controller;
|
||||
@ -1994,7 +1944,6 @@ err_unbind:
|
||||
dev->driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
static void
|
||||
stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
|
||||
@ -2022,7 +1971,7 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
|
||||
usb_reinit (dev);
|
||||
}
|
||||
|
||||
int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
static int net2280_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct net2280 *dev = the_controller;
|
||||
unsigned long flags;
|
||||
@ -2049,8 +1998,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL (usb_gadget_unregister_driver);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -2732,6 +2679,8 @@ static void net2280_remove (struct pci_dev *pdev)
|
||||
{
|
||||
struct net2280 *dev = pci_get_drvdata (pdev);
|
||||
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
|
||||
BUG_ON(dev->driver);
|
||||
|
||||
/* then clean up the resources we allocated during probe() */
|
||||
@ -2916,6 +2865,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
retval = device_create_file (&pdev->dev, &dev_attr_registers);
|
||||
if (retval) goto done;
|
||||
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto done;
|
||||
return 0;
|
||||
|
||||
done:
|
||||
|
@ -241,6 +241,7 @@ static struct usb_composite_driver nokia_driver = {
|
||||
.name = "g_nokia",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = __exit_p(nokia_unbind),
|
||||
};
|
||||
|
||||
|
@ -1375,6 +1375,10 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int omap_udc_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
static struct usb_gadget_ops omap_gadget_ops = {
|
||||
.get_frame = omap_get_frame,
|
||||
.wakeup = omap_wakeup,
|
||||
@ -1382,6 +1386,8 @@ static struct usb_gadget_ops omap_gadget_ops = {
|
||||
.vbus_session = omap_vbus_session,
|
||||
.vbus_draw = omap_vbus_draw,
|
||||
.pullup = omap_pullup,
|
||||
.start = omap_udc_start,
|
||||
.stop = omap_udc_stop,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -2102,7 +2108,7 @@ static inline int machine_without_vbus_sense(void)
|
||||
);
|
||||
}
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
int status = -ENODEV;
|
||||
@ -2186,9 +2192,8 @@ done:
|
||||
omap_udc_enable_clock(0);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
static int omap_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status = -ENODEV;
|
||||
@ -2222,8 +2227,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
DBG("unregistered driver '%s'\n", driver->driver.name);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -2991,9 +2994,16 @@ known:
|
||||
|
||||
create_proc_file();
|
||||
status = device_add(&udc->gadget.dev);
|
||||
if (status)
|
||||
goto cleanup4;
|
||||
|
||||
status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (!status)
|
||||
return status;
|
||||
/* If fail, fall through */
|
||||
cleanup4:
|
||||
remove_proc_file();
|
||||
|
||||
#ifdef USE_ISO
|
||||
cleanup3:
|
||||
free_irq(pdev->resource[2].start, udc);
|
||||
@ -3029,6 +3039,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
|
||||
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -1176,6 +1176,9 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int pch_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int pch_udc_stop(struct usb_gadget_driver *driver);
|
||||
static const struct usb_gadget_ops pch_udc_ops = {
|
||||
.get_frame = pch_udc_pcd_get_frame,
|
||||
.wakeup = pch_udc_pcd_wakeup,
|
||||
@ -1183,6 +1186,8 @@ static const struct usb_gadget_ops pch_udc_ops = {
|
||||
.pullup = pch_udc_pcd_pullup,
|
||||
.vbus_session = pch_udc_pcd_vbus_session,
|
||||
.vbus_draw = pch_udc_pcd_vbus_draw,
|
||||
.start = pch_udc_start,
|
||||
.stop = pch_udc_stop,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2690,7 +2695,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int pch_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct pch_udc_dev *dev = pch_udc;
|
||||
@ -2733,9 +2738,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
dev->connected = 1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int pch_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct pch_udc_dev *dev = pch_udc;
|
||||
|
||||
@ -2761,7 +2765,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
pch_udc_set_disconnect(dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
static void pch_udc_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
@ -2778,6 +2781,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct pch_udc_dev *dev = pci_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
|
||||
/* gadget driver must not be registered */
|
||||
if (dev->driver)
|
||||
dev_err(&pdev->dev,
|
||||
@ -2953,6 +2958,9 @@ static int pch_udc_probe(struct pci_dev *pdev,
|
||||
|
||||
/* Put the device in disconnected state till a driver is bound */
|
||||
pch_udc_set_disconnect(dev);
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto finished;
|
||||
return 0;
|
||||
|
||||
finished:
|
||||
|
@ -89,8 +89,7 @@ struct printer_dev {
|
||||
u8 config;
|
||||
s8 interface;
|
||||
struct usb_ep *in_ep, *out_ep;
|
||||
const struct usb_endpoint_descriptor
|
||||
*in, *out;
|
||||
|
||||
struct list_head rx_reqs; /* List of free RX structs */
|
||||
struct list_head rx_reqs_active; /* List of Active RX xfers */
|
||||
struct list_head rx_buffers; /* List of completed xfers */
|
||||
@ -898,19 +897,20 @@ set_printer_interface(struct printer_dev *dev)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
|
||||
dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
|
||||
dev->in_ep->driver_data = dev;
|
||||
|
||||
dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
|
||||
dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
|
||||
&fs_ep_out_desc);
|
||||
dev->out_ep->driver_data = dev;
|
||||
|
||||
result = usb_ep_enable(dev->in_ep, dev->in);
|
||||
result = usb_ep_enable(dev->in_ep);
|
||||
if (result != 0) {
|
||||
DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = usb_ep_enable(dev->out_ep, dev->out);
|
||||
result = usb_ep_enable(dev->out_ep);
|
||||
if (result != 0) {
|
||||
DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
|
||||
goto done;
|
||||
@ -921,8 +921,8 @@ done:
|
||||
if (result != 0) {
|
||||
(void) usb_ep_disable(dev->in_ep);
|
||||
(void) usb_ep_disable(dev->out_ep);
|
||||
dev->in = NULL;
|
||||
dev->out = NULL;
|
||||
dev->in_ep->desc = NULL;
|
||||
dev->out_ep->desc = NULL;
|
||||
}
|
||||
|
||||
/* caller is responsible for cleanup on error */
|
||||
@ -936,12 +936,14 @@ static void printer_reset_interface(struct printer_dev *dev)
|
||||
|
||||
DBG(dev, "%s\n", __func__);
|
||||
|
||||
if (dev->in)
|
||||
if (dev->in_ep->desc)
|
||||
usb_ep_disable(dev->in_ep);
|
||||
|
||||
if (dev->out)
|
||||
if (dev->out_ep->desc)
|
||||
usb_ep_disable(dev->out_ep);
|
||||
|
||||
dev->in_ep->desc = NULL;
|
||||
dev->out_ep->desc = NULL;
|
||||
dev->interface = -1;
|
||||
}
|
||||
|
||||
@ -1107,9 +1109,9 @@ static void printer_soft_reset(struct printer_dev *dev)
|
||||
list_add(&req->list, &dev->tx_reqs);
|
||||
}
|
||||
|
||||
if (usb_ep_enable(dev->in_ep, dev->in))
|
||||
if (usb_ep_enable(dev->in_ep))
|
||||
DBG(dev, "Failed to enable USB in_ep\n");
|
||||
if (usb_ep_enable(dev->out_ep, dev->out))
|
||||
if (usb_ep_enable(dev->out_ep))
|
||||
DBG(dev, "Failed to enable USB out_ep\n");
|
||||
|
||||
wake_up_interruptible(&dev->rx_wait);
|
||||
@ -1149,6 +1151,8 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
switch (wValue >> 8) {
|
||||
|
||||
case USB_DT_DEVICE:
|
||||
device_desc.bMaxPacketSize0 =
|
||||
gadget->ep0->maxpacket;
|
||||
value = min(wLength, (u16) sizeof device_desc);
|
||||
memcpy(req->buf, &device_desc, value);
|
||||
break;
|
||||
@ -1156,6 +1160,12 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
if (!gadget->is_dualspeed)
|
||||
break;
|
||||
/*
|
||||
* assumes ep0 uses the same value for both
|
||||
* speeds
|
||||
*/
|
||||
dev_qualifier.bMaxPacketSize0 =
|
||||
gadget->ep0->maxpacket;
|
||||
value = min(wLength,
|
||||
(u16) sizeof dev_qualifier);
|
||||
memcpy(req->buf, &dev_qualifier, value);
|
||||
@ -1451,15 +1461,11 @@ autoconf_fail:
|
||||
out_ep->driver_data = out_ep; /* claim */
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DUALSPEED
|
||||
/* assumes ep0 uses the same value for both speeds ... */
|
||||
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
|
||||
|
||||
/* and that all endpoints are dual-speed */
|
||||
/* assumes that all endpoints are dual-speed */
|
||||
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
|
||||
hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
|
||||
#endif /* DUALSPEED */
|
||||
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
|
||||
if (gadget->is_otg) {
|
||||
|
@ -1011,12 +1011,18 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int pxa25x_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int pxa25x_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
static const struct usb_gadget_ops pxa25x_udc_ops = {
|
||||
.get_frame = pxa25x_udc_get_frame,
|
||||
.wakeup = pxa25x_udc_wakeup,
|
||||
.vbus_session = pxa25x_udc_vbus_session,
|
||||
.pullup = pxa25x_udc_pullup,
|
||||
.vbus_draw = pxa25x_udc_vbus_draw,
|
||||
.start = pxa25x_start,
|
||||
.stop = pxa25x_stop,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1263,7 +1269,7 @@ static void udc_enable (struct pxa25x_udc *dev)
|
||||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int pxa25x_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct pxa25x_udc *dev = the_controller;
|
||||
@ -1322,7 +1328,6 @@ fail:
|
||||
bind_fail:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
static void
|
||||
stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
|
||||
@ -1351,7 +1356,7 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
|
||||
udc_reinit(dev);
|
||||
}
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int pxa25x_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct pxa25x_udc *dev = the_controller;
|
||||
|
||||
@ -1379,8 +1384,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
dump_state(dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -2231,8 +2234,11 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
|
||||
#endif
|
||||
create_debug_files(dev);
|
||||
|
||||
return 0;
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (!retval)
|
||||
return retval;
|
||||
|
||||
remove_debug_files(dev);
|
||||
#ifdef CONFIG_ARCH_LUBBOCK
|
||||
lubbock_fail0:
|
||||
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
|
||||
@ -2261,6 +2267,7 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa25x_udc *dev = platform_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -1680,12 +1680,18 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int pxa27x_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
static const struct usb_gadget_ops pxa_udc_ops = {
|
||||
.get_frame = pxa_udc_get_frame,
|
||||
.wakeup = pxa_udc_wakeup,
|
||||
.pullup = pxa_udc_pullup,
|
||||
.vbus_session = pxa_udc_vbus_session,
|
||||
.vbus_draw = pxa_udc_vbus_draw,
|
||||
.start = pxa27x_udc_start,
|
||||
.stop = pxa27x_udc_stop,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1791,7 +1797,7 @@ static void udc_enable(struct pxa_udc *udc)
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_probe_driver - Register gadget driver
|
||||
* pxa27x_start - Register gadget driver
|
||||
* @driver: gadget driver
|
||||
* @bind: bind function
|
||||
*
|
||||
@ -1805,7 +1811,7 @@ static void udc_enable(struct pxa_udc *udc)
|
||||
*
|
||||
* Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int pxa27x_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct pxa_udc *udc = the_controller;
|
||||
@ -1860,8 +1866,6 @@ add_fail:
|
||||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
|
||||
/**
|
||||
* stop_activity - Stops udc endpoints
|
||||
@ -1888,12 +1892,12 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_unregister_driver - Unregister the gadget driver
|
||||
* pxa27x_udc_stop - Unregister the gadget driver
|
||||
* @driver: gadget driver
|
||||
*
|
||||
* Returns 0 if no error, -ENODEV, -EINVAL otherwise
|
||||
*/
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct pxa_udc *udc = the_controller;
|
||||
|
||||
@ -1917,7 +1921,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
return otg_set_peripheral(udc->transceiver, NULL);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/**
|
||||
* handle_ep0_ctrl_req - handle control endpoint control request
|
||||
@ -2516,9 +2519,14 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
||||
driver_name, IRQ_USB, retval);
|
||||
goto err_irq;
|
||||
}
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (retval)
|
||||
goto err_add_udc;
|
||||
|
||||
pxa_init_debugfs(udc);
|
||||
return 0;
|
||||
err_add_udc:
|
||||
free_irq(udc->irq, udc);
|
||||
err_irq:
|
||||
iounmap(udc->regs);
|
||||
err_map:
|
||||
@ -2537,6 +2545,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)
|
||||
struct pxa_udc *udc = platform_get_drvdata(_dev);
|
||||
int gpio = udc->mach->gpio_pullup;
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
usb_gadget_unregister_driver(udc->driver);
|
||||
free_irq(udc->irq, udc);
|
||||
pxa_cleanup_debugfs(udc);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2006-2009 Renesas Solutions Corp.
|
||||
*
|
||||
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
|
||||
* Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -576,7 +576,11 @@ static void init_controller(struct r8a66597 *r8a66597)
|
||||
u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
|
||||
|
||||
if (r8a66597->pdata->on_chip) {
|
||||
r8a66597_bset(r8a66597, 0x04, SYSCFG1);
|
||||
if (r8a66597->pdata->buswait)
|
||||
r8a66597_write(r8a66597, r8a66597->pdata->buswait,
|
||||
SYSCFG1);
|
||||
else
|
||||
r8a66597_write(r8a66597, 0x0f, SYSCFG1);
|
||||
r8a66597_bset(r8a66597, HSE, SYSCFG0);
|
||||
|
||||
r8a66597_bclr(r8a66597, USBE, SYSCFG0);
|
||||
@ -618,6 +622,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
|
||||
{
|
||||
if (r8a66597->pdata->on_chip) {
|
||||
r8a66597_bset(r8a66597, SCKE, SYSCFG0);
|
||||
r8a66597_bclr(r8a66597, UTST, TESTMODE);
|
||||
|
||||
/* disable interrupts */
|
||||
r8a66597_write(r8a66597, 0, INTENB0);
|
||||
@ -635,6 +640,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
|
||||
r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
|
||||
|
||||
} else {
|
||||
r8a66597_bclr(r8a66597, UTST, TESTMODE);
|
||||
r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
|
||||
udelay(1);
|
||||
r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
|
||||
@ -999,10 +1005,29 @@ static void clear_feature(struct r8a66597 *r8a66597,
|
||||
|
||||
static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
u16 tmp;
|
||||
int timeout = 3000;
|
||||
|
||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_DEVICE:
|
||||
control_end(r8a66597, 1);
|
||||
switch (le16_to_cpu(ctrl->wValue)) {
|
||||
case USB_DEVICE_TEST_MODE:
|
||||
control_end(r8a66597, 1);
|
||||
/* Wait for the completion of status stage */
|
||||
do {
|
||||
tmp = r8a66597_read(r8a66597, INTSTS0) & CTSQ;
|
||||
udelay(1);
|
||||
} while (tmp != CS_IDST || timeout-- > 0);
|
||||
|
||||
if (tmp == CS_IDST)
|
||||
r8a66597_bset(r8a66597,
|
||||
le16_to_cpu(ctrl->wIndex >> 8),
|
||||
TESTMODE);
|
||||
break;
|
||||
default:
|
||||
pipe_stall(r8a66597, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
control_end(r8a66597, 1);
|
||||
@ -1410,7 +1435,7 @@ static struct usb_ep_ops r8a66597_ep_ops = {
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static struct r8a66597 *the_controller;
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int r8a66597_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct r8a66597 *r8a66597 = the_controller;
|
||||
@ -1444,6 +1469,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
goto error;
|
||||
}
|
||||
|
||||
init_controller(r8a66597);
|
||||
r8a66597_bset(r8a66597, VBSE, INTENB0);
|
||||
if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) {
|
||||
r8a66597_start_xclock(r8a66597);
|
||||
@ -1462,9 +1488,8 @@ error:
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int r8a66597_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = the_controller;
|
||||
unsigned long flags;
|
||||
@ -1475,20 +1500,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
spin_lock_irqsave(&r8a66597->lock, flags);
|
||||
if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN)
|
||||
r8a66597_usb_disconnect(r8a66597);
|
||||
r8a66597_bclr(r8a66597, VBSE, INTENB0);
|
||||
disable_controller(r8a66597);
|
||||
spin_unlock_irqrestore(&r8a66597->lock, flags);
|
||||
|
||||
r8a66597_bclr(r8a66597, VBSE, INTENB0);
|
||||
|
||||
driver->unbind(&r8a66597->gadget);
|
||||
|
||||
init_controller(r8a66597);
|
||||
disable_controller(r8a66597);
|
||||
|
||||
device_del(&r8a66597->gadget.dev);
|
||||
r8a66597->driver = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int r8a66597_get_frame(struct usb_gadget *_gadget)
|
||||
@ -1497,14 +1518,33 @@ static int r8a66597_get_frame(struct usb_gadget *_gadget)
|
||||
return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
|
||||
}
|
||||
|
||||
static int r8a66597_pullup(struct usb_gadget *gadget, int is_on)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&r8a66597->lock, flags);
|
||||
if (is_on)
|
||||
r8a66597_bset(r8a66597, DPRPU, SYSCFG0);
|
||||
else
|
||||
r8a66597_bclr(r8a66597, DPRPU, SYSCFG0);
|
||||
spin_unlock_irqrestore(&r8a66597->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_gadget_ops r8a66597_gadget_ops = {
|
||||
.get_frame = r8a66597_get_frame,
|
||||
.start = r8a66597_start,
|
||||
.stop = r8a66597_stop,
|
||||
.pullup = r8a66597_pullup,
|
||||
};
|
||||
|
||||
static int __exit r8a66597_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
usb_del_gadget_udc(&r8a66597->gadget);
|
||||
del_timer_sync(&r8a66597->timer);
|
||||
iounmap(r8a66597->reg);
|
||||
free_irq(platform_get_irq(pdev, 0), r8a66597);
|
||||
@ -1645,11 +1685,15 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
goto clean_up3;
|
||||
r8a66597->ep0_req->complete = nop_completion;
|
||||
|
||||
init_controller(r8a66597);
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
|
||||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
|
||||
clean_up3:
|
||||
free_irq(irq, r8a66597);
|
||||
clean_up2:
|
||||
@ -1679,6 +1723,7 @@ static struct platform_driver r8a66597_driver = {
|
||||
.name = (char *) udc_name,
|
||||
},
|
||||
};
|
||||
MODULE_ALIAS("platform:r8a66597_udc");
|
||||
|
||||
static int __init r8a66597_udc_init(void)
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2007-2009 Renesas Solutions Corp.
|
||||
*
|
||||
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
|
||||
* Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -2574,7 +2574,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int s3c_hsotg_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct s3c_hsotg *hsotg = our_hsotg;
|
||||
@ -2745,9 +2745,8 @@ err:
|
||||
hsotg->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct s3c_hsotg *hsotg = our_hsotg;
|
||||
int ep;
|
||||
@ -2775,7 +2774,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
|
||||
{
|
||||
@ -2784,6 +2782,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
|
||||
|
||||
static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
|
||||
.get_frame = s3c_hsotg_gadget_getframe,
|
||||
.start = s3c_hsotg_start,
|
||||
.stop = s3c_hsotg_stop,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3403,6 +3403,10 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
||||
for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
|
||||
s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
s3c_hsotg_create_debug(hsotg);
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
@ -3410,6 +3414,11 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
||||
our_hsotg = hsotg;
|
||||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
s3c_hsotg_gate(pdev, false);
|
||||
clk_disable(hsotg->clk);
|
||||
clk_put(hsotg->clk);
|
||||
|
||||
err_regs:
|
||||
iounmap(hsotg->regs);
|
||||
|
||||
@ -3427,6 +3436,8 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&hsotg->gadget);
|
||||
|
||||
s3c_hsotg_delete_debug(hsotg);
|
||||
|
||||
usb_gadget_unregister_driver(hsotg->driver);
|
||||
|
@ -1133,7 +1133,7 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int s3c_hsudc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct s3c_hsudc *hsudc = the_controller;
|
||||
@ -1181,9 +1181,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct s3c_hsudc *hsudc = the_controller;
|
||||
unsigned long flags;
|
||||
@ -1210,7 +1209,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)
|
||||
{
|
||||
@ -1224,6 +1222,8 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
|
||||
|
||||
static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
|
||||
.get_frame = s3c_hsudc_gadget_getframe,
|
||||
.start = s3c_hsudc_start,
|
||||
.stop = s3c_hsudc_stop,
|
||||
};
|
||||
|
||||
static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
@ -1311,7 +1311,15 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
|
||||
disable_irq(hsudc->irq);
|
||||
local_irq_enable();
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
return 0;
|
||||
err_add_udc:
|
||||
clk_disable(hsudc->uclk);
|
||||
clk_put(hsudc->uclk);
|
||||
err_clk:
|
||||
free_irq(hsudc->irq, hsudc);
|
||||
err_irq:
|
||||
@ -1333,6 +1341,7 @@ static struct platform_driver s3c_hsudc_driver = {
|
||||
},
|
||||
.probe = s3c_hsudc_probe,
|
||||
};
|
||||
MODULE_ALIAS("platform:s3c-hsudc");
|
||||
|
||||
static int __init s3c_hsudc_modinit(void)
|
||||
{
|
||||
|
@ -1552,6 +1552,10 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int s3c2410_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *));
|
||||
static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
|
||||
|
||||
static const struct usb_gadget_ops s3c2410_ops = {
|
||||
.get_frame = s3c2410_udc_get_frame,
|
||||
.wakeup = s3c2410_udc_wakeup,
|
||||
@ -1559,6 +1563,8 @@ static const struct usb_gadget_ops s3c2410_ops = {
|
||||
.pullup = s3c2410_udc_pullup,
|
||||
.vbus_session = s3c2410_udc_vbus_session,
|
||||
.vbus_draw = s3c2410_vbus_draw,
|
||||
.start = s3c2410_udc_start,
|
||||
.stop = s3c2410_udc_stop,
|
||||
};
|
||||
|
||||
static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
|
||||
@ -1567,7 +1573,7 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
|
||||
return;
|
||||
|
||||
if (udc_info->udc_command) {
|
||||
udc_info->udc_command(S3C2410_UDC_P_DISABLE);
|
||||
udc_info->udc_command(cmd);
|
||||
} else if (gpio_is_valid(udc_info->pullup_pin)) {
|
||||
int value;
|
||||
|
||||
@ -1672,10 +1678,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
|
||||
s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_gadget_probe_driver
|
||||
*/
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
static int s3c2410_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct s3c2410_udc *udc = the_controller;
|
||||
@ -1730,12 +1733,8 @@ register_error:
|
||||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/*
|
||||
* usb_gadget_unregister_driver
|
||||
*/
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
static int s3c2410_udc_stop(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct s3c2410_udc *udc = the_controller;
|
||||
|
||||
@ -1955,6 +1954,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
|
||||
goto err_vbus_irq;
|
||||
}
|
||||
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (retval)
|
||||
goto err_add_udc;
|
||||
|
||||
if (s3c2410_udc_debugfs_root) {
|
||||
udc->regs_info = debugfs_create_file("registers", S_IRUGO,
|
||||
s3c2410_udc_debugfs_root,
|
||||
@ -1967,6 +1970,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
if (udc_info && !udc_info->udc_command &&
|
||||
gpio_is_valid(udc_info->pullup_pin))
|
||||
gpio_free(udc_info->pullup_pin);
|
||||
err_vbus_irq:
|
||||
if (udc_info && udc_info->vbus_pin > 0)
|
||||
free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
|
||||
@ -1992,6 +1999,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
|
||||
unsigned int irq;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s()\n", __func__);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
@ -2048,26 +2057,22 @@ static int s3c2410_udc_resume(struct platform_device *pdev)
|
||||
#define s3c2410_udc_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver udc_driver_2410 = {
|
||||
.driver = {
|
||||
.name = "s3c2410-usbgadget",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = s3c2410_udc_probe,
|
||||
.remove = s3c2410_udc_remove,
|
||||
.suspend = s3c2410_udc_suspend,
|
||||
.resume = s3c2410_udc_resume,
|
||||
static const struct platform_device_id s3c_udc_ids[] = {
|
||||
{ "s3c2410-usbgadget", },
|
||||
{ "s3c2440-usbgadget", },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, s3c_udc_ids);
|
||||
|
||||
static struct platform_driver udc_driver_2440 = {
|
||||
static struct platform_driver udc_driver_24x0 = {
|
||||
.driver = {
|
||||
.name = "s3c2440-usbgadget",
|
||||
.name = "s3c24x0-usbgadget",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = s3c2410_udc_probe,
|
||||
.remove = s3c2410_udc_remove,
|
||||
.suspend = s3c2410_udc_suspend,
|
||||
.resume = s3c2410_udc_resume,
|
||||
.id_table = s3c_udc_ids,
|
||||
};
|
||||
|
||||
static int __init udc_init(void)
|
||||
@ -2083,11 +2088,7 @@ static int __init udc_init(void)
|
||||
s3c2410_udc_debugfs_root = NULL;
|
||||
}
|
||||
|
||||
retval = platform_driver_register(&udc_driver_2410);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
retval = platform_driver_register(&udc_driver_2440);
|
||||
retval = platform_driver_register(&udc_driver_24x0);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
@ -2100,13 +2101,10 @@ err:
|
||||
|
||||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver_2410);
|
||||
platform_driver_unregister(&udc_driver_2440);
|
||||
platform_driver_unregister(&udc_driver_24x0);
|
||||
debugfs_remove(s3c2410_udc_debugfs_root);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
||||
module_init(udc_init);
|
||||
module_exit(udc_exit);
|
||||
|
||||
@ -2114,5 +2112,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:s3c2410-usbgadget");
|
||||
MODULE_ALIAS("platform:s3c2440-usbgadget");
|
||||
|
@ -242,6 +242,7 @@ static struct usb_composite_driver gserial_driver = {
|
||||
.name = "g_serial",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
|
@ -494,7 +494,7 @@ static struct usb_descriptor_header *fsg_hs_function[] = {
|
||||
};
|
||||
|
||||
/* Maxpacket and other transfer characteristics vary by speed. */
|
||||
static struct usb_endpoint_descriptor *
|
||||
static __maybe_unused struct usb_endpoint_descriptor *
|
||||
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
|
||||
struct usb_endpoint_descriptor *hs)
|
||||
{
|
||||
|
@ -97,16 +97,17 @@ struct eth_dev {
|
||||
|
||||
static unsigned qmult = 5;
|
||||
module_param(qmult, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(qmult, "queue length multiplier at high speed");
|
||||
MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
|
||||
|
||||
#else /* full speed (low speed doesn't do bulk) */
|
||||
#define qmult 1
|
||||
#endif
|
||||
|
||||
/* for dual-speed hardware, use deeper queues at highspeed */
|
||||
/* for dual-speed hardware, use deeper queues at high/super speed */
|
||||
static inline int qlen(struct usb_gadget *gadget)
|
||||
{
|
||||
if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH)
|
||||
if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
|
||||
gadget->speed == USB_SPEED_SUPER))
|
||||
return qmult * DEFAULT_QLEN;
|
||||
else
|
||||
return DEFAULT_QLEN;
|
||||
@ -598,9 +599,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
||||
|
||||
req->length = length;
|
||||
|
||||
/* throttle highspeed IRQ rate back slightly */
|
||||
/* throttle high/super speed IRQ rate back slightly */
|
||||
if (gadget_is_dualspeed(dev->gadget))
|
||||
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
|
||||
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
|
||||
dev->gadget->speed == USB_SPEED_SUPER)
|
||||
? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
|
||||
: 0;
|
||||
|
||||
@ -693,8 +695,8 @@ static int eth_stop(struct net_device *net)
|
||||
usb_ep_disable(link->out_ep);
|
||||
if (netif_carrier_ok(net)) {
|
||||
DBG(dev, "host still using in/out endpoints\n");
|
||||
usb_ep_enable(link->in_ep, link->in);
|
||||
usb_ep_enable(link->out_ep, link->out);
|
||||
usb_ep_enable(link->in_ep);
|
||||
usb_ep_enable(link->out_ep);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
@ -871,7 +873,7 @@ struct net_device *gether_connect(struct gether *link)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
link->in_ep->driver_data = dev;
|
||||
result = usb_ep_enable(link->in_ep, link->in);
|
||||
result = usb_ep_enable(link->in_ep);
|
||||
if (result != 0) {
|
||||
DBG(dev, "enable %s --> %d\n",
|
||||
link->in_ep->name, result);
|
||||
@ -879,7 +881,7 @@ struct net_device *gether_connect(struct gether *link)
|
||||
}
|
||||
|
||||
link->out_ep->driver_data = dev;
|
||||
result = usb_ep_enable(link->out_ep, link->out);
|
||||
result = usb_ep_enable(link->out_ep);
|
||||
if (result != 0) {
|
||||
DBG(dev, "enable %s --> %d\n",
|
||||
link->out_ep->name, result);
|
||||
@ -969,7 +971,7 @@ void gether_disconnect(struct gether *link)
|
||||
}
|
||||
spin_unlock(&dev->req_lock);
|
||||
link->in_ep->driver_data = NULL;
|
||||
link->in = NULL;
|
||||
link->in_ep->desc = NULL;
|
||||
|
||||
usb_ep_disable(link->out_ep);
|
||||
spin_lock(&dev->req_lock);
|
||||
@ -984,7 +986,7 @@ void gether_disconnect(struct gether *link)
|
||||
}
|
||||
spin_unlock(&dev->req_lock);
|
||||
link->out_ep->driver_data = NULL;
|
||||
link->out = NULL;
|
||||
link->out_ep->desc = NULL;
|
||||
|
||||
/* finish forgetting about this USB link episode */
|
||||
dev->header_len = 0;
|
||||
|
@ -52,10 +52,6 @@ struct gether {
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_ep *out_ep;
|
||||
|
||||
/* descriptors match device speed at gether_connect() time */
|
||||
struct usb_endpoint_descriptor *in;
|
||||
struct usb_endpoint_descriptor *out;
|
||||
|
||||
bool is_zlp_ok;
|
||||
|
||||
u16 cdc_filter;
|
||||
|
@ -1247,12 +1247,12 @@ int gserial_connect(struct gserial *gser, u8 port_num)
|
||||
port = ports[port_num].port;
|
||||
|
||||
/* activate the endpoints */
|
||||
status = usb_ep_enable(gser->in, gser->in_desc);
|
||||
status = usb_ep_enable(gser->in);
|
||||
if (status < 0)
|
||||
return status;
|
||||
gser->in->driver_data = port;
|
||||
|
||||
status = usb_ep_enable(gser->out, gser->out_desc);
|
||||
status = usb_ep_enable(gser->out);
|
||||
if (status < 0)
|
||||
goto fail_out;
|
||||
gser->out->driver_data = port;
|
||||
|
@ -35,8 +35,6 @@ struct gserial {
|
||||
|
||||
struct usb_ep *in;
|
||||
struct usb_ep *out;
|
||||
struct usb_endpoint_descriptor *in_desc;
|
||||
struct usb_endpoint_descriptor *out_desc;
|
||||
|
||||
/* REVISIT avoid this CDC-ACM support harder ... */
|
||||
struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */
|
||||
|
484
drivers/usb/gadget/udc-core.c
Normal file
484
drivers/usb/gadget/udc-core.c
Normal file
@ -0,0 +1,484 @@
|
||||
/**
|
||||
* udc.c - Core UDC Framework
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
* Author: Felipe Balbi <balbi@ti.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
/**
|
||||
* struct usb_udc - describes one usb device controller
|
||||
* @driver - the gadget driver pointer. For use by the class code
|
||||
* @dev - the child device to the actual controller
|
||||
* @gadget - the gadget. For use by the class code
|
||||
* @list - for use by the udc class driver
|
||||
*
|
||||
* This represents the internal data structure which is used by the UDC-class
|
||||
* to hold information about udc driver and gadget together.
|
||||
*/
|
||||
struct usb_udc {
|
||||
struct usb_gadget_driver *driver;
|
||||
struct usb_gadget *gadget;
|
||||
struct device dev;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static struct class *udc_class;
|
||||
static LIST_HEAD(udc_list);
|
||||
static DEFINE_MUTEX(udc_lock);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* usb_gadget_start - tells usb device controller to start up
|
||||
* @gadget: The gadget we want to get started
|
||||
* @driver: The driver we want to bind to @gadget
|
||||
* @bind: The bind function for @driver
|
||||
*
|
||||
* This call is issued by the UDC Class driver when it's about
|
||||
* to register a gadget driver to the device controller, before
|
||||
* calling gadget driver's bind() method.
|
||||
*
|
||||
* It allows the controller to be powered off until strictly
|
||||
* necessary to have it powered on.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
static inline int usb_gadget_start(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
return gadget->ops->start(driver, bind);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_start - tells usb device controller to start up
|
||||
* @gadget: The gadget we want to get started
|
||||
* @driver: The driver we want to bind to @gadget
|
||||
*
|
||||
* This call is issued by the UDC Class driver when it's about
|
||||
* to register a gadget driver to the device controller, before
|
||||
* calling gadget driver's bind() method.
|
||||
*
|
||||
* It allows the controller to be powered off until strictly
|
||||
* necessary to have it powered on.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
return gadget->ops->udc_start(gadget, driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_stop - tells usb device controller we don't need it anymore
|
||||
* @gadget: The device we want to stop activity
|
||||
* @driver: The driver to unbind from @gadget
|
||||
*
|
||||
* This call is issued by the UDC Class driver after calling
|
||||
* gadget driver's unbind() method.
|
||||
*
|
||||
* The details are implementation specific, but it can go as
|
||||
* far as powering off UDC completely and disable its data
|
||||
* line pullups.
|
||||
*/
|
||||
static inline void usb_gadget_stop(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
gadget->ops->stop(driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_stop - tells usb device controller we don't need it anymore
|
||||
* @gadget: The device we want to stop activity
|
||||
* @driver: The driver to unbind from @gadget
|
||||
*
|
||||
* This call is issued by the UDC Class driver after calling
|
||||
* gadget driver's unbind() method.
|
||||
*
|
||||
* The details are implementation specific, but it can go as
|
||||
* far as powering off UDC completely and disable its data
|
||||
* line pullups.
|
||||
*/
|
||||
static inline void usb_gadget_udc_stop(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
gadget->ops->udc_stop(gadget, driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_udc_release - release the usb_udc struct
|
||||
* @dev: the dev member within usb_udc
|
||||
*
|
||||
* This is called by driver's core in order to free memory once the last
|
||||
* reference is released.
|
||||
*/
|
||||
static void usb_udc_release(struct device *dev)
|
||||
{
|
||||
struct usb_udc *udc;
|
||||
|
||||
udc = container_of(dev, struct usb_udc, dev);
|
||||
dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
|
||||
kfree(udc);
|
||||
}
|
||||
|
||||
static const struct attribute_group *usb_udc_attr_groups[];
|
||||
/**
|
||||
* usb_add_gadget_udc - adds a new gadget to the udc class driver list
|
||||
* @parent: the parent device to this udc. Usually the controller
|
||||
* driver's device.
|
||||
* @gadget: the gadget to be added to the list
|
||||
*
|
||||
* Returns zero on success, negative errno otherwise.
|
||||
*/
|
||||
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_udc *udc;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
|
||||
if (!udc)
|
||||
goto err1;
|
||||
|
||||
device_initialize(&udc->dev);
|
||||
udc->dev.release = usb_udc_release;
|
||||
udc->dev.class = udc_class;
|
||||
udc->dev.groups = usb_udc_attr_groups;
|
||||
udc->dev.parent = parent;
|
||||
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
udc->gadget = gadget;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_add_tail(&udc->list, &udc_list);
|
||||
|
||||
ret = device_add(&udc->dev);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
return 0;
|
||||
err3:
|
||||
list_del(&udc->list);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
err2:
|
||||
put_device(&udc->dev);
|
||||
|
||||
err1:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
|
||||
|
||||
static int udc_is_newstyle(struct usb_udc *udc)
|
||||
{
|
||||
if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void usb_gadget_remove_driver(struct usb_udc *udc)
|
||||
{
|
||||
dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
|
||||
udc->gadget->name);
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
|
||||
if (udc_is_newstyle(udc)) {
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
udc->driver->unbind(udc->gadget);
|
||||
usb_gadget_udc_stop(udc->gadget, udc->driver);
|
||||
|
||||
} else {
|
||||
usb_gadget_stop(udc->gadget, udc->driver);
|
||||
}
|
||||
|
||||
udc->driver = NULL;
|
||||
udc->dev.driver = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_del_gadget_udc - deletes @udc from udc_list
|
||||
* @gadget: the gadget to be removed.
|
||||
*
|
||||
* This, will call usb_gadget_unregister_driver() if
|
||||
* the @udc is still busy.
|
||||
*/
|
||||
void usb_del_gadget_udc(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_udc *udc = NULL;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_for_each_entry(udc, &udc_list, list)
|
||||
if (udc->gadget == gadget)
|
||||
goto found;
|
||||
|
||||
dev_err(gadget->dev.parent, "gadget not registered.\n");
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
return;
|
||||
|
||||
found:
|
||||
dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
|
||||
|
||||
list_del(&udc->list);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
if (udc->driver)
|
||||
usb_gadget_remove_driver(udc);
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
|
||||
device_unregister(&udc->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct usb_udc *udc = NULL;
|
||||
int ret;
|
||||
|
||||
if (!driver || !bind || !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_for_each_entry(udc, &udc_list, list) {
|
||||
/* For now we take the first one */
|
||||
if (!udc->driver)
|
||||
goto found;
|
||||
}
|
||||
|
||||
pr_debug("couldn't find an available UDC\n");
|
||||
mutex_unlock(&udc_lock);
|
||||
return -ENODEV;
|
||||
|
||||
found:
|
||||
dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
|
||||
driver->function);
|
||||
|
||||
udc->driver = driver;
|
||||
udc->dev.driver = &driver->driver;
|
||||
|
||||
if (udc_is_newstyle(udc)) {
|
||||
ret = bind(udc->gadget);
|
||||
if (ret)
|
||||
goto err1;
|
||||
ret = usb_gadget_udc_start(udc->gadget, driver);
|
||||
if (ret) {
|
||||
driver->unbind(udc->gadget);
|
||||
goto err1;
|
||||
}
|
||||
usb_gadget_connect(udc->gadget);
|
||||
} else {
|
||||
|
||||
ret = usb_gadget_start(udc->gadget, driver, bind);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
}
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
mutex_unlock(&udc_lock);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dev_err(&udc->dev, "failed to start %s: %d\n",
|
||||
udc->driver->function, ret);
|
||||
udc->driver = NULL;
|
||||
udc->dev.driver = NULL;
|
||||
mutex_unlock(&udc_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct usb_udc *udc = NULL;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (!driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_for_each_entry(udc, &udc_list, list)
|
||||
if (udc->driver == driver) {
|
||||
usb_gadget_remove_driver(udc);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&udc_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static ssize_t usb_udc_srp_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct usb_udc *udc = dev_get_drvdata(dev);
|
||||
|
||||
if (sysfs_streq(buf, "1"))
|
||||
usb_gadget_wakeup(udc->gadget);
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
|
||||
|
||||
static ssize_t usb_udc_softconn_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct usb_udc *udc = dev_get_drvdata(dev);
|
||||
|
||||
if (sysfs_streq(buf, "connect")) {
|
||||
usb_gadget_connect(udc->gadget);
|
||||
} else if (sysfs_streq(buf, "disconnect")) {
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
} else {
|
||||
dev_err(dev, "unsupported command '%s'\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
|
||||
|
||||
static ssize_t usb_udc_speed_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
|
||||
struct usb_gadget *gadget = udc->gadget;
|
||||
|
||||
switch (gadget->speed) {
|
||||
case USB_SPEED_LOW:
|
||||
return snprintf(buf, PAGE_SIZE, "low-speed\n");
|
||||
case USB_SPEED_FULL:
|
||||
return snprintf(buf, PAGE_SIZE, "full-speed\n");
|
||||
case USB_SPEED_HIGH:
|
||||
return snprintf(buf, PAGE_SIZE, "high-speed\n");
|
||||
case USB_SPEED_WIRELESS:
|
||||
return snprintf(buf, PAGE_SIZE, "wireless\n");
|
||||
case USB_SPEED_SUPER:
|
||||
return snprintf(buf, PAGE_SIZE, "super-speed\n");
|
||||
case USB_SPEED_UNKNOWN: /* FALLTHROUGH */
|
||||
default:
|
||||
return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
|
||||
}
|
||||
}
|
||||
static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL);
|
||||
|
||||
#define USB_UDC_ATTR(name) \
|
||||
ssize_t usb_udc_##name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
|
||||
struct usb_gadget *gadget = udc->gadget; \
|
||||
\
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \
|
||||
} \
|
||||
static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL)
|
||||
|
||||
static USB_UDC_ATTR(is_dualspeed);
|
||||
static USB_UDC_ATTR(is_otg);
|
||||
static USB_UDC_ATTR(is_a_peripheral);
|
||||
static USB_UDC_ATTR(b_hnp_enable);
|
||||
static USB_UDC_ATTR(a_hnp_support);
|
||||
static USB_UDC_ATTR(a_alt_hnp_support);
|
||||
|
||||
static struct attribute *usb_udc_attrs[] = {
|
||||
&dev_attr_srp.attr,
|
||||
&dev_attr_soft_connect.attr,
|
||||
&dev_attr_speed.attr,
|
||||
|
||||
&dev_attr_is_dualspeed.attr,
|
||||
&dev_attr_is_otg.attr,
|
||||
&dev_attr_is_a_peripheral.attr,
|
||||
&dev_attr_b_hnp_enable.attr,
|
||||
&dev_attr_a_hnp_support.attr,
|
||||
&dev_attr_a_alt_hnp_support.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group usb_udc_attr_group = {
|
||||
.attrs = usb_udc_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *usb_udc_attr_groups[] = {
|
||||
&usb_udc_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
|
||||
int ret;
|
||||
|
||||
ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (udc->driver) {
|
||||
ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
|
||||
udc->driver->function);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init usb_udc_init(void)
|
||||
{
|
||||
udc_class = class_create(THIS_MODULE, "udc");
|
||||
if (IS_ERR(udc_class)) {
|
||||
pr_err("failed to create udc class --> %ld\n",
|
||||
PTR_ERR(udc_class));
|
||||
return PTR_ERR(udc_class);
|
||||
}
|
||||
|
||||
udc_class->dev_uevent = usb_udc_uevent;
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(usb_udc_init);
|
||||
|
||||
static void __exit usb_udc_exit(void)
|
||||
{
|
||||
class_destroy(udc_class);
|
||||
}
|
||||
module_exit(usb_udc_exit);
|
||||
|
||||
MODULE_DESCRIPTION("UDC Framework");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -373,6 +373,7 @@ static struct usb_composite_driver webcam_driver = {
|
||||
.name = "g_webcam",
|
||||
.dev = &webcam_device_descriptor,
|
||||
.strings = webcam_device_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.unbind = webcam_unbind,
|
||||
};
|
||||
|
||||
|
@ -340,6 +340,7 @@ static struct usb_composite_driver zero_driver = {
|
||||
.name = "zero",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.max_speed = USB_SPEED_SUPER,
|
||||
.unbind = zero_unbind,
|
||||
.suspend = zero_suspend,
|
||||
.resume = zero_resume,
|
||||
|
@ -94,7 +94,8 @@ static const char hcd_name [] = "ehci_hcd";
|
||||
#define EHCI_IAA_MSECS 10 /* arbitrary */
|
||||
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
||||
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
||||
#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */
|
||||
#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
|
||||
/* 200-ms async qh unlink delay */
|
||||
|
||||
/* Initial IRQ latency: faster than hw default */
|
||||
static int log2_irq_thresh = 0; // 0 to 6
|
||||
@ -114,7 +115,7 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
|
||||
/* for link power management(LPM) feature */
|
||||
static unsigned int hird;
|
||||
module_param(hird, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
|
||||
MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
|
||||
|
||||
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
|
||||
|
||||
@ -152,10 +153,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||
break;
|
||||
/* case TIMER_ASYNC_SHRINK: */
|
||||
default:
|
||||
/* add a jiffie since we synch against the
|
||||
* 8 KHz uframe counter.
|
||||
*/
|
||||
t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
|
||||
t = EHCI_SHRINK_JIFFIES;
|
||||
break;
|
||||
}
|
||||
mod_timer(&ehci->watchdog, t + jiffies);
|
||||
@ -340,6 +338,7 @@ static void ehci_work(struct ehci_hcd *ehci);
|
||||
#include "ehci-mem.c"
|
||||
#include "ehci-q.c"
|
||||
#include "ehci-sched.c"
|
||||
#include "ehci-sysfs.c"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -524,7 +523,7 @@ static void ehci_stop (struct usb_hcd *hcd)
|
||||
ehci_reset (ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
remove_companion_file(ehci);
|
||||
remove_sysfs_files(ehci);
|
||||
remove_debug_files (ehci);
|
||||
|
||||
/* root hub is shut down separately (first, when possible) */
|
||||
@ -574,6 +573,12 @@ static int ehci_init(struct usb_hcd *hcd)
|
||||
|
||||
hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
|
||||
|
||||
/*
|
||||
* by default set standard 80% (== 100 usec/uframe) max periodic
|
||||
* bandwidth as required by USB 2.0
|
||||
*/
|
||||
ehci->uframe_periodic_max = 100;
|
||||
|
||||
/*
|
||||
* hw default: 1K periodic list heads, one per frame.
|
||||
* periodic_size can shrink by USBCMD update if hcc_params allows.
|
||||
@ -758,7 +763,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
||||
* since the class device isn't created that early.
|
||||
*/
|
||||
create_debug_files(ehci);
|
||||
create_companion_file(ehci);
|
||||
create_sysfs_files(ehci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -471,29 +471,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Display the ports dedicated to the companion controller */
|
||||
static ssize_t show_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int nports, index, n;
|
||||
int count = PAGE_SIZE;
|
||||
char *ptr = buf;
|
||||
|
||||
ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
|
||||
nports = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
for (index = 0; index < nports; ++index) {
|
||||
if (test_bit(index, &ehci->companion_ports)) {
|
||||
n = scnprintf(ptr, count, "%d\n", index + 1);
|
||||
ptr += n;
|
||||
count -= n;
|
||||
}
|
||||
}
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the owner of a port
|
||||
*/
|
||||
@ -528,58 +505,6 @@ static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dedicate or undedicate a port to the companion controller.
|
||||
* Syntax is "[-]portnum", where a leading '-' sign means
|
||||
* return control of the port to the EHCI controller.
|
||||
*/
|
||||
static ssize_t store_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int portnum, new_owner;
|
||||
|
||||
ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
|
||||
new_owner = PORT_OWNER; /* Owned by companion */
|
||||
if (sscanf(buf, "%d", &portnum) != 1)
|
||||
return -EINVAL;
|
||||
if (portnum < 0) {
|
||||
portnum = - portnum;
|
||||
new_owner = 0; /* Owned by EHCI */
|
||||
}
|
||||
if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
|
||||
return -ENOENT;
|
||||
portnum--;
|
||||
if (new_owner)
|
||||
set_bit(portnum, &ehci->companion_ports);
|
||||
else
|
||||
clear_bit(portnum, &ehci->companion_ports);
|
||||
set_owner(ehci, portnum, new_owner);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
|
||||
|
||||
static inline int create_companion_file(struct ehci_hcd *ehci)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
i = device_create_file(ehci_to_hcd(ehci)->self.controller,
|
||||
&dev_attr_companion);
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void remove_companion_file(struct ehci_hcd *ehci)
|
||||
{
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
device_remove_file(ehci_to_hcd(ehci)->self.controller,
|
||||
&dev_attr_companion);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int check_reset_complete (
|
||||
@ -891,10 +816,11 @@ static int ehci_hub_control (
|
||||
* power switching; they're allowed to just limit the
|
||||
* current. khubd will turn the power back on.
|
||||
*/
|
||||
if (HCS_PPC (ehci->hcs_params)){
|
||||
if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) {
|
||||
ehci_writel(ehci,
|
||||
temp & ~(PORT_RWC_BITS | PORT_POWER),
|
||||
status_reg);
|
||||
temp = ehci_readl(ehci, status_reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,27 +40,9 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
|
||||
int retval;
|
||||
|
||||
ehci->caps = USB_CAPLENGTH;
|
||||
ehci->regs = USB_CAPLENGTH +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache the data to minimize the chip reads*/
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = HCD_USB2;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_reset(ehci);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
|
||||
if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
|
||||
unsigned is_out, epnum;
|
||||
|
||||
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
|
||||
is_out = qh->is_out;
|
||||
epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
|
||||
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
|
||||
hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
|
||||
@ -946,6 +946,7 @@ done:
|
||||
hw = qh->hw;
|
||||
hw->hw_info1 = cpu_to_hc32(ehci, info1);
|
||||
hw->hw_info2 = cpu_to_hc32(ehci, info2);
|
||||
qh->is_out = !is_input;
|
||||
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
|
||||
qh_refresh (ehci, qh);
|
||||
return qh;
|
||||
@ -1231,6 +1232,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
|
||||
prev->hw->hw_next = qh->hw->hw_next;
|
||||
prev->qh_next = qh->qh_next;
|
||||
if (ehci->qh_scan_next == qh)
|
||||
ehci->qh_scan_next = qh->qh_next.qh;
|
||||
wmb ();
|
||||
|
||||
/* If the controller isn't running, we don't have to wait for it */
|
||||
@ -1256,53 +1259,49 @@ static void scan_async (struct ehci_hcd *ehci)
|
||||
struct ehci_qh *qh;
|
||||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||
|
||||
ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||
rescan:
|
||||
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||
qh = ehci->async->qh_next.qh;
|
||||
if (likely (qh != NULL)) {
|
||||
do {
|
||||
/* clean any finished work for this qh */
|
||||
if (!list_empty(&qh->qtd_list) && (stopped ||
|
||||
qh->stamp != ehci->stamp)) {
|
||||
int temp;
|
||||
|
||||
/* unlinks could happen here; completion
|
||||
* reporting drops the lock. rescan using
|
||||
* the latest schedule, but don't rescan
|
||||
* qhs we already finished (no looping)
|
||||
* unless the controller is stopped.
|
||||
*/
|
||||
qh = qh_get (qh);
|
||||
qh->stamp = ehci->stamp;
|
||||
temp = qh_completions (ehci, qh);
|
||||
if (qh->needs_rescan)
|
||||
unlink_async(ehci, qh);
|
||||
qh_put (qh);
|
||||
if (temp != 0) {
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
ehci->qh_scan_next = ehci->async->qh_next.qh;
|
||||
while (ehci->qh_scan_next) {
|
||||
qh = ehci->qh_scan_next;
|
||||
ehci->qh_scan_next = qh->qh_next.qh;
|
||||
rescan:
|
||||
/* clean any finished work for this qh */
|
||||
if (!list_empty(&qh->qtd_list)) {
|
||||
int temp;
|
||||
|
||||
/* unlink idle entries, reducing DMA usage as well
|
||||
* as HCD schedule-scanning costs. delay for any qh
|
||||
* we just scanned, there's a not-unusual case that it
|
||||
* doesn't stay idle for long.
|
||||
* (plus, avoids some kind of re-activation race.)
|
||||
/*
|
||||
* Unlinks could happen here; completion reporting
|
||||
* drops the lock. That's why ehci->qh_scan_next
|
||||
* always holds the next qh to scan; if the next qh
|
||||
* gets unlinked then ehci->qh_scan_next is adjusted
|
||||
* in start_unlink_async().
|
||||
*/
|
||||
if (list_empty(&qh->qtd_list)
|
||||
&& qh->qh_state == QH_STATE_LINKED) {
|
||||
if (!ehci->reclaim && (stopped ||
|
||||
((ehci->stamp - qh->stamp) & 0x1fff)
|
||||
>= EHCI_SHRINK_FRAMES * 8))
|
||||
start_unlink_async(ehci, qh);
|
||||
else
|
||||
action = TIMER_ASYNC_SHRINK;
|
||||
}
|
||||
qh = qh_get(qh);
|
||||
temp = qh_completions(ehci, qh);
|
||||
if (qh->needs_rescan)
|
||||
unlink_async(ehci, qh);
|
||||
qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
|
||||
qh_put(qh);
|
||||
if (temp != 0)
|
||||
goto rescan;
|
||||
}
|
||||
|
||||
qh = qh->qh_next.qh;
|
||||
} while (qh);
|
||||
/* unlink idle entries, reducing DMA usage as well
|
||||
* as HCD schedule-scanning costs. delay for any qh
|
||||
* we just scanned, there's a not-unusual case that it
|
||||
* doesn't stay idle for long.
|
||||
* (plus, avoids some kind of re-activation race.)
|
||||
*/
|
||||
if (list_empty(&qh->qtd_list)
|
||||
&& qh->qh_state == QH_STATE_LINKED) {
|
||||
if (!ehci->reclaim && (stopped ||
|
||||
time_after_eq(jiffies, qh->unlink_time)))
|
||||
start_unlink_async(ehci, qh);
|
||||
else
|
||||
action = TIMER_ASYNC_SHRINK;
|
||||
}
|
||||
}
|
||||
if (action == TIMER_ASYNC_SHRINK)
|
||||
timer_action (ehci, TIMER_ASYNC_SHRINK);
|
||||
|
@ -189,6 +189,100 @@ static void s5p_ehci_shutdown(struct platform_device *pdev)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int s5p_ehci_suspend(struct device *dev)
|
||||
{
|
||||
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(20);
|
||||
|
||||
/*
|
||||
* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int s5p_ehci_resume(struct device *dev)
|
||||
{
|
||||
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (pdata && pdata->phy_init)
|
||||
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
(void) ehci_halt(ehci);
|
||||
(void) ehci_reset(ehci);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define s5p_ehci_suspend NULL
|
||||
#define s5p_ehci_resume NULL
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops s5p_ehci_pm_ops = {
|
||||
.suspend = s5p_ehci_suspend,
|
||||
.resume = s5p_ehci_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver s5p_ehci_driver = {
|
||||
.probe = s5p_ehci_probe,
|
||||
.remove = __devexit_p(s5p_ehci_remove),
|
||||
@ -196,6 +290,7 @@ static struct platform_driver s5p_ehci_driver = {
|
||||
.driver = {
|
||||
.name = "s5p-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &s5p_ehci_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -172,7 +172,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (usecs > 100)
|
||||
if (usecs > ehci->uframe_periodic_max)
|
||||
ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
|
||||
frame * 8 + uframe, usecs);
|
||||
#endif
|
||||
@ -709,11 +709,8 @@ static int check_period (
|
||||
if (uframe >= 8)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 80% periodic == 100 usec/uframe available
|
||||
* convert "usecs we need" to "max already claimed"
|
||||
*/
|
||||
usecs = 100 - usecs;
|
||||
/* convert "usecs we need" to "max already claimed" */
|
||||
usecs = ehci->uframe_periodic_max - usecs;
|
||||
|
||||
/* we "know" 2 and 4 uframe intervals were rejected; so
|
||||
* for period 0, check _every_ microframe in the schedule.
|
||||
@ -1286,9 +1283,9 @@ itd_slot_ok (
|
||||
{
|
||||
uframe %= period;
|
||||
do {
|
||||
/* can't commit more than 80% periodic == 100 usec */
|
||||
/* can't commit more than uframe_periodic_max usec */
|
||||
if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
|
||||
> (100 - usecs))
|
||||
> (ehci->uframe_periodic_max - usecs))
|
||||
return 0;
|
||||
|
||||
/* we know urb->interval is 2^N uframes */
|
||||
@ -1345,7 +1342,7 @@ sitd_slot_ok (
|
||||
#endif
|
||||
|
||||
/* check starts (OUT uses more than one) */
|
||||
max_used = 100 - stream->usecs;
|
||||
max_used = ehci->uframe_periodic_max - stream->usecs;
|
||||
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
|
||||
if (periodic_usecs (ehci, frame, uf) > max_used)
|
||||
return 0;
|
||||
@ -1354,7 +1351,7 @@ sitd_slot_ok (
|
||||
/* for IN, check CSPLIT */
|
||||
if (stream->c_usecs) {
|
||||
uf = uframe & 7;
|
||||
max_used = 100 - stream->c_usecs;
|
||||
max_used = ehci->uframe_periodic_max - stream->c_usecs;
|
||||
do {
|
||||
tmp = 1 << uf;
|
||||
tmp <<= 8;
|
||||
|
190
drivers/usb/host/ehci-sysfs.c
Normal file
190
drivers/usb/host/ehci-sysfs.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2007 by Alan Stern
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* this file is part of ehci-hcd.c */
|
||||
|
||||
|
||||
/* Display the ports dedicated to the companion controller */
|
||||
static ssize_t show_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int nports, index, n;
|
||||
int count = PAGE_SIZE;
|
||||
char *ptr = buf;
|
||||
|
||||
ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
|
||||
nports = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
for (index = 0; index < nports; ++index) {
|
||||
if (test_bit(index, &ehci->companion_ports)) {
|
||||
n = scnprintf(ptr, count, "%d\n", index + 1);
|
||||
ptr += n;
|
||||
count -= n;
|
||||
}
|
||||
}
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dedicate or undedicate a port to the companion controller.
|
||||
* Syntax is "[-]portnum", where a leading '-' sign means
|
||||
* return control of the port to the EHCI controller.
|
||||
*/
|
||||
static ssize_t store_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int portnum, new_owner;
|
||||
|
||||
ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
|
||||
new_owner = PORT_OWNER; /* Owned by companion */
|
||||
if (sscanf(buf, "%d", &portnum) != 1)
|
||||
return -EINVAL;
|
||||
if (portnum < 0) {
|
||||
portnum = - portnum;
|
||||
new_owner = 0; /* Owned by EHCI */
|
||||
}
|
||||
if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
|
||||
return -ENOENT;
|
||||
portnum--;
|
||||
if (new_owner)
|
||||
set_bit(portnum, &ehci->companion_ports);
|
||||
else
|
||||
clear_bit(portnum, &ehci->companion_ports);
|
||||
set_owner(ehci, portnum, new_owner);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
|
||||
|
||||
|
||||
/*
|
||||
* Display / Set uframe_periodic_max
|
||||
*/
|
||||
static ssize_t show_uframe_periodic_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int n;
|
||||
|
||||
ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
|
||||
n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t store_uframe_periodic_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned uframe_periodic_max;
|
||||
unsigned frame, uframe;
|
||||
unsigned short allocated_max;
|
||||
unsigned long flags;
|
||||
ssize_t ret;
|
||||
|
||||
ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
|
||||
if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
|
||||
ehci_info(ehci, "rejecting invalid request for "
|
||||
"uframe_periodic_max=%u\n", uframe_periodic_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
/*
|
||||
* lock, so that our checking does not race with possible periodic
|
||||
* bandwidth allocation through submitting new urbs.
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
|
||||
/*
|
||||
* for request to decrease max periodic bandwidth, we have to check
|
||||
* every microframe in the schedule to see whether the decrease is
|
||||
* possible.
|
||||
*/
|
||||
if (uframe_periodic_max < ehci->uframe_periodic_max) {
|
||||
allocated_max = 0;
|
||||
|
||||
for (frame = 0; frame < ehci->periodic_size; ++frame)
|
||||
for (uframe = 0; uframe < 7; ++uframe)
|
||||
allocated_max = max(allocated_max,
|
||||
periodic_usecs (ehci, frame, uframe));
|
||||
|
||||
if (allocated_max > uframe_periodic_max) {
|
||||
ehci_info(ehci,
|
||||
"cannot decrease uframe_periodic_max becase "
|
||||
"periodic bandwidth is already allocated "
|
||||
"(%u > %u)\n",
|
||||
allocated_max, uframe_periodic_max);
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* increasing is always ok */
|
||||
|
||||
ehci_info(ehci, "setting max periodic bandwidth to %u%% "
|
||||
"(== %u usec/uframe)\n",
|
||||
100*uframe_periodic_max/125, uframe_periodic_max);
|
||||
|
||||
if (uframe_periodic_max != 100)
|
||||
ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
|
||||
|
||||
ehci->uframe_periodic_max = uframe_periodic_max;
|
||||
ret = count;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max);
|
||||
|
||||
|
||||
static inline int create_sysfs_files(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct device *controller = ehci_to_hcd(ehci)->self.controller;
|
||||
int i = 0;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
i = device_create_file(controller, &dev_attr_companion);
|
||||
if (i)
|
||||
goto out;
|
||||
|
||||
i = device_create_file(controller, &dev_attr_uframe_periodic_max);
|
||||
out:
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void remove_sysfs_files(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct device *controller = ehci_to_hcd(ehci)->self.controller;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
device_remove_file(controller, &dev_attr_companion);
|
||||
|
||||
device_remove_file(controller, &dev_attr_uframe_periodic_max);
|
||||
}
|
@ -75,6 +75,7 @@ struct ehci_hcd { /* one per controller */
|
||||
struct ehci_qh *async;
|
||||
struct ehci_qh *dummy; /* For AMD quirk use */
|
||||
struct ehci_qh *reclaim;
|
||||
struct ehci_qh *qh_scan_next;
|
||||
unsigned scanning : 1;
|
||||
|
||||
/* periodic schedule support */
|
||||
@ -87,6 +88,8 @@ struct ehci_hcd { /* one per controller */
|
||||
union ehci_shadow *pshadow; /* mirror hw periodic table */
|
||||
int next_uframe; /* scan periodic, start here */
|
||||
unsigned periodic_sched; /* periodic activity count */
|
||||
unsigned uframe_periodic_max; /* max periodic time per uframe */
|
||||
|
||||
|
||||
/* list of itds & sitds completed while clock_frame was still active */
|
||||
struct list_head cached_itd_list;
|
||||
@ -117,7 +120,6 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list iaa_watchdog;
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
@ -343,6 +345,7 @@ struct ehci_qh {
|
||||
struct ehci_qh *reclaim; /* next to reclaim */
|
||||
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned long unlink_time;
|
||||
|
||||
/*
|
||||
* Do NOT use atomic operations for QH refcounting. On some CPUs
|
||||
@ -374,6 +377,7 @@ struct ehci_qh {
|
||||
#define NO_FRAME ((unsigned short)~0) /* pick new start */
|
||||
|
||||
struct usb_device *dev; /* access to TT */
|
||||
unsigned is_out:1; /* bulk or intr OUT */
|
||||
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2008 Renesas Solutions Corp.
|
||||
*
|
||||
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
|
||||
* Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -35,6 +35,8 @@
|
||||
#define OHCI_INTRSTATUS 0x0c
|
||||
#define OHCI_INTRENABLE 0x10
|
||||
#define OHCI_INTRDISABLE 0x14
|
||||
#define OHCI_FMINTERVAL 0x34
|
||||
#define OHCI_HCR (1 << 0) /* host controller reset */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
|
||||
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
|
||||
@ -497,6 +499,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
||||
|
||||
/* reset controller, preserving RWC (and possibly IR) */
|
||||
writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
|
||||
readl(base + OHCI_CONTROL);
|
||||
|
||||
/* Some NVIDIA controllers stop working if kept in RESET for too long */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
|
||||
u32 fminterval;
|
||||
int cnt;
|
||||
|
||||
/* drive reset for at least 50 ms (7.1.7.5) */
|
||||
msleep(50);
|
||||
|
||||
/* software reset of the controller, preserving HcFmInterval */
|
||||
fminterval = readl(base + OHCI_FMINTERVAL);
|
||||
writel(OHCI_HCR, base + OHCI_CMDSTATUS);
|
||||
|
||||
/* reset requires max 10 us delay */
|
||||
for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
|
||||
if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
writel(fminterval, base + OHCI_FMINTERVAL);
|
||||
|
||||
/* Now we're in the SUSPEND state with all devices reset
|
||||
* and wakeups and interrupts disabled
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* disable interrupts
|
||||
@ -507,20 +535,34 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
||||
iounmap(base);
|
||||
}
|
||||
|
||||
static const struct dmi_system_id __initconst ehci_dmi_nohandoff_table[] = {
|
||||
{
|
||||
/* Pegatron Lucid (ExoPC) */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Pegatron Lucid (Ordissimo AIRIS) */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "M11JB"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
|
||||
void __iomem *op_reg_base,
|
||||
u32 cap, u8 offset)
|
||||
{
|
||||
int try_handoff = 1, tried_handoff = 0;
|
||||
|
||||
/* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90
|
||||
* seconds trying the handoff on its unused controller. Skip
|
||||
* it. */
|
||||
/* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
|
||||
* the handoff on its unused controller. Skip it. */
|
||||
if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
|
||||
const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION);
|
||||
if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") &&
|
||||
dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133"))
|
||||
if (dmi_check_system(ehci_dmi_nohandoff_table))
|
||||
try_handoff = 0;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (C) 2004-2005 David Brownell
|
||||
* Portions Copyright (C) 1999 Roman Weissgaerber
|
||||
*
|
||||
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
|
||||
* Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -1438,7 +1438,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
if (pipenum > 0)
|
||||
r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
|
||||
if (urb->transfer_buffer) {
|
||||
r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
|
||||
r8a66597_write_fifo(r8a66597, td->pipe, buf, size);
|
||||
if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
|
||||
r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr);
|
||||
}
|
||||
@ -2306,7 +2306,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
|
||||
|
||||
dbg("resume port = %d", port);
|
||||
rh->port &= ~USB_PORT_STAT_SUSPEND;
|
||||
rh->port |= USB_PORT_STAT_C_SUSPEND < 16;
|
||||
rh->port |= USB_PORT_STAT_C_SUSPEND << 16;
|
||||
r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
|
||||
msleep(50);
|
||||
r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
|
||||
|
@ -201,11 +201,26 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
|
||||
iowrite16(val, r8a66597->reg + offset);
|
||||
}
|
||||
|
||||
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
|
||||
u16 val, u16 pat, unsigned long offset)
|
||||
{
|
||||
u16 tmp;
|
||||
tmp = r8a66597_read(r8a66597, offset);
|
||||
tmp = tmp & (~pat);
|
||||
tmp = tmp | val;
|
||||
r8a66597_write(r8a66597, tmp, offset);
|
||||
}
|
||||
|
||||
#define r8a66597_bclr(r8a66597, val, offset) \
|
||||
r8a66597_mdfy(r8a66597, 0, val, offset)
|
||||
#define r8a66597_bset(r8a66597, val, offset) \
|
||||
r8a66597_mdfy(r8a66597, val, 0, offset)
|
||||
|
||||
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
|
||||
unsigned long offset, u16 *buf,
|
||||
struct r8a66597_pipe *pipe, u16 *buf,
|
||||
int len)
|
||||
{
|
||||
void __iomem *fifoaddr = r8a66597->reg + offset;
|
||||
void __iomem *fifoaddr = r8a66597->reg + pipe->fifoaddr;
|
||||
unsigned long count;
|
||||
unsigned char *pb;
|
||||
int i;
|
||||
@ -230,26 +245,15 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
|
||||
iowrite16_rep(fifoaddr, buf, len);
|
||||
if (unlikely(odd)) {
|
||||
buf = &buf[len];
|
||||
if (r8a66597->pdata->wr0_shorted_to_wr1)
|
||||
r8a66597_bclr(r8a66597, MBW_16, pipe->fifosel);
|
||||
iowrite8((unsigned char)*buf, fifoaddr);
|
||||
if (r8a66597->pdata->wr0_shorted_to_wr1)
|
||||
r8a66597_bset(r8a66597, MBW_16, pipe->fifosel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
|
||||
u16 val, u16 pat, unsigned long offset)
|
||||
{
|
||||
u16 tmp;
|
||||
tmp = r8a66597_read(r8a66597, offset);
|
||||
tmp = tmp & (~pat);
|
||||
tmp = tmp | val;
|
||||
r8a66597_write(r8a66597, tmp, offset);
|
||||
}
|
||||
|
||||
#define r8a66597_bclr(r8a66597, val, offset) \
|
||||
r8a66597_mdfy(r8a66597, 0, val, offset)
|
||||
#define r8a66597_bset(r8a66597, val, offset) \
|
||||
r8a66597_mdfy(r8a66597, val, 0, offset)
|
||||
|
||||
static inline unsigned long get_syscfg_reg(int port)
|
||||
{
|
||||
return port == 0 ? SYSCFG0 : SYSCFG1;
|
||||
|
@ -266,11 +266,11 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
|
||||
GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
|
||||
xhci_dbg(xhci, "Cycle bit = %u\n",
|
||||
(unsigned int) (le32_to_cpu(trb->link.control) & TRB_CYCLE));
|
||||
le32_to_cpu(trb->link.control) & TRB_CYCLE);
|
||||
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
|
||||
(unsigned int) (le32_to_cpu(trb->link.control) & LINK_TOGGLE));
|
||||
le32_to_cpu(trb->link.control) & LINK_TOGGLE);
|
||||
xhci_dbg(xhci, "No Snoop bit = %u\n",
|
||||
(unsigned int) (le32_to_cpu(trb->link.control) & TRB_NO_SNOOP));
|
||||
le32_to_cpu(trb->link.control) & TRB_NO_SNOOP);
|
||||
break;
|
||||
case TRB_TYPE(TRB_TRANSFER):
|
||||
address = le64_to_cpu(trb->trans_event.buffer);
|
||||
@ -284,9 +284,9 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
address = le64_to_cpu(trb->event_cmd.cmd_trb);
|
||||
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
|
||||
xhci_dbg(xhci, "Completion status = %u\n",
|
||||
(unsigned int) GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
|
||||
GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
|
||||
xhci_dbg(xhci, "Flags = 0x%x\n",
|
||||
(unsigned int) le32_to_cpu(trb->event_cmd.flags));
|
||||
le32_to_cpu(trb->event_cmd.flags));
|
||||
break;
|
||||
default:
|
||||
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
|
||||
@ -318,10 +318,10 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
|
||||
trb = &seg->trbs[i];
|
||||
xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
|
||||
(u32)lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
(u32)upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
(unsigned int) le32_to_cpu(trb->link.intr_target),
|
||||
(unsigned int) le32_to_cpu(trb->link.control));
|
||||
lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
le32_to_cpu(trb->link.intr_target),
|
||||
le32_to_cpu(trb->link.control));
|
||||
addr += sizeof(*trb);
|
||||
}
|
||||
}
|
||||
@ -402,8 +402,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
|
||||
addr,
|
||||
lower_32_bits(le64_to_cpu(entry->seg_addr)),
|
||||
upper_32_bits(le64_to_cpu(entry->seg_addr)),
|
||||
(unsigned int) le32_to_cpu(entry->seg_size),
|
||||
(unsigned int) le32_to_cpu(entry->rsvd));
|
||||
le32_to_cpu(entry->seg_size),
|
||||
le32_to_cpu(entry->rsvd));
|
||||
addr += sizeof(*entry);
|
||||
}
|
||||
}
|
||||
|
@ -89,8 +89,8 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
|
||||
return;
|
||||
prev->next = next;
|
||||
if (link_trbs) {
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.
|
||||
segment_ptr = cpu_to_le64(next->dma);
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
|
||||
cpu_to_le64(next->dma);
|
||||
|
||||
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
|
||||
val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
|
||||
@ -187,8 +187,8 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
|
||||
|
||||
if (link_trbs) {
|
||||
/* See section 4.9.2.1 and 6.4.4.1 */
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.
|
||||
control |= cpu_to_le32(LINK_TOGGLE);
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
|
||||
cpu_to_le32(LINK_TOGGLE);
|
||||
xhci_dbg(xhci, "Wrote link toggle flag to"
|
||||
" segment %p (virtual), 0x%llx (DMA)\n",
|
||||
prev, (unsigned long long)prev->dma);
|
||||
@ -549,8 +549,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
|
||||
addr = cur_ring->first_seg->dma |
|
||||
SCT_FOR_CTX(SCT_PRI_TR) |
|
||||
cur_ring->cycle_state;
|
||||
stream_info->stream_ctx_array[cur_stream].
|
||||
stream_ring = cpu_to_le64(addr);
|
||||
stream_info->stream_ctx_array[cur_stream].stream_ring =
|
||||
cpu_to_le64(addr);
|
||||
xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
|
||||
cur_stream, (unsigned long long) addr);
|
||||
|
||||
@ -786,7 +786,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
||||
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
|
||||
slot_id,
|
||||
&xhci->dcbaa->dev_context_ptrs[slot_id],
|
||||
(unsigned long long) le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
|
||||
le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
@ -890,19 +890,19 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
||||
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
|
||||
|
||||
/* 3) Only the control endpoint is valid - one endpoint context */
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route);
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route);
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_SS);
|
||||
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_HS);
|
||||
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS);
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_FS);
|
||||
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS);
|
||||
break;
|
||||
case USB_SPEED_LOW:
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_LS);
|
||||
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS);
|
||||
break;
|
||||
case USB_SPEED_WIRELESS:
|
||||
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
|
||||
@ -916,7 +916,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
||||
port_num = xhci_find_real_port_number(xhci, udev);
|
||||
if (!port_num)
|
||||
return -EINVAL;
|
||||
slot_ctx->dev_info2 |= cpu_to_le32((u32) ROOT_HUB_PORT(port_num));
|
||||
slot_ctx->dev_info2 |= cpu_to_le32(ROOT_HUB_PORT(port_num));
|
||||
/* Set the port number in the virtual_device to the faked port number */
|
||||
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
|
||||
top_dev = top_dev->parent)
|
||||
|
@ -113,15 +113,13 @@ static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
if (ring == xhci->event_ring)
|
||||
return trb == &seg->trbs[TRBS_PER_SEGMENT];
|
||||
else
|
||||
return (le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK)
|
||||
== TRB_TYPE(TRB_LINK);
|
||||
return TRB_TYPE_LINK_LE32(trb->link.control);
|
||||
}
|
||||
|
||||
static int enqueue_is_link_trb(struct xhci_ring *ring)
|
||||
{
|
||||
struct xhci_link_trb *link = &ring->enqueue->link;
|
||||
return ((le32_to_cpu(link->control) & TRB_TYPE_BITMASK) ==
|
||||
TRB_TYPE(TRB_LINK));
|
||||
return TRB_TYPE_LINK_LE32(link->control);
|
||||
}
|
||||
|
||||
/* Updates trb to point to the next TRB in the ring, and updates seg if the next
|
||||
@ -372,7 +370,7 @@ static struct xhci_segment *find_trb_seg(
|
||||
while (cur_seg->trbs > trb ||
|
||||
&cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
|
||||
generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
|
||||
if (le32_to_cpu(generic_trb->field[3]) & LINK_TOGGLE)
|
||||
if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE))
|
||||
*cycle_state ^= 0x1;
|
||||
cur_seg = cur_seg->next;
|
||||
if (cur_seg == start_seg)
|
||||
@ -489,8 +487,8 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
|
||||
}
|
||||
|
||||
trb = &state->new_deq_ptr->generic;
|
||||
if ((le32_to_cpu(trb->field[3]) & TRB_TYPE_BITMASK) ==
|
||||
TRB_TYPE(TRB_LINK) && (le32_to_cpu(trb->field[3]) & LINK_TOGGLE))
|
||||
if (TRB_TYPE_LINK_LE32(trb->field[3]) &&
|
||||
(trb->field[3] & cpu_to_le32(LINK_TOGGLE)))
|
||||
state->new_cycle_state ^= 0x1;
|
||||
next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
|
||||
|
||||
@ -525,8 +523,7 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb;
|
||||
true;
|
||||
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
|
||||
if ((le32_to_cpu(cur_trb->generic.field[3]) & TRB_TYPE_BITMASK)
|
||||
== TRB_TYPE(TRB_LINK)) {
|
||||
if (TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) {
|
||||
/* Unchain any chained Link TRBs, but
|
||||
* leave the pointers intact.
|
||||
*/
|
||||
@ -1000,7 +997,7 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
|
||||
* but we don't care.
|
||||
*/
|
||||
xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
|
||||
(unsigned int) GET_COMP_CODE(le32_to_cpu(event->status)));
|
||||
GET_COMP_CODE(le32_to_cpu(event->status)));
|
||||
|
||||
/* HW with the reset endpoint quirk needs to have a configure endpoint
|
||||
* command complete before the endpoint can be used. Queue that here
|
||||
@ -1458,7 +1455,8 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
|
||||
* endpoint anyway. Check if a babble halted the
|
||||
* endpoint.
|
||||
*/
|
||||
if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED)
|
||||
if ((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) ==
|
||||
cpu_to_le32(EP_STATE_HALTED))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -1753,10 +1751,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||
for (cur_trb = ep_ring->dequeue,
|
||||
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
|
||||
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
|
||||
if ((le32_to_cpu(cur_trb->generic.field[3]) &
|
||||
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
|
||||
(le32_to_cpu(cur_trb->generic.field[3]) &
|
||||
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
|
||||
if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) &&
|
||||
!TRB_TYPE_LINK_LE32(cur_trb->generic.field[3]))
|
||||
len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
|
||||
}
|
||||
len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
|
||||
@ -1885,10 +1881,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||
for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
|
||||
cur_trb != event_trb;
|
||||
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
|
||||
if ((le32_to_cpu(cur_trb->generic.field[3]) &
|
||||
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
|
||||
(le32_to_cpu(cur_trb->generic.field[3]) &
|
||||
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
|
||||
if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) &&
|
||||
!TRB_TYPE_LINK_LE32(cur_trb->generic.field[3]))
|
||||
td->urb->actual_length +=
|
||||
TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
|
||||
}
|
||||
@ -2047,8 +2041,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
|
||||
ep_index);
|
||||
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
|
||||
(unsigned int) (le32_to_cpu(event->flags)
|
||||
& TRB_TYPE_BITMASK)>>10);
|
||||
(le32_to_cpu(event->flags) &
|
||||
TRB_TYPE_BITMASK)>>10);
|
||||
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
|
||||
if (ep->skip) {
|
||||
ep->skip = false;
|
||||
@ -2119,9 +2113,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
* corresponding TD has been cancelled. Just ignore
|
||||
* the TD.
|
||||
*/
|
||||
if ((le32_to_cpu(event_trb->generic.field[3])
|
||||
& TRB_TYPE_BITMASK)
|
||||
== TRB_TYPE(TRB_TR_NOOP)) {
|
||||
if (TRB_TYPE_NOOP_LE32(event_trb->generic.field[3])) {
|
||||
xhci_dbg(xhci,
|
||||
"event_trb is a no-op TRB. Skip it\n");
|
||||
goto cleanup;
|
||||
@ -2452,7 +2444,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
next->link.control |= cpu_to_le32(TRB_CHAIN);
|
||||
|
||||
wmb();
|
||||
next->link.control ^= cpu_to_le32((u32) TRB_CYCLE);
|
||||
next->link.control ^= cpu_to_le32(TRB_CYCLE);
|
||||
|
||||
/* Toggle the cycle bit after the last ring segment. */
|
||||
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
|
||||
|
@ -1342,8 +1342,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
/* If the HC already knows the endpoint is disabled,
|
||||
* or the HCD has noted it is disabled, ignore this request
|
||||
*/
|
||||
if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
|
||||
EP_STATE_DISABLED ||
|
||||
if (((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) ==
|
||||
cpu_to_le32(EP_STATE_DISABLED)) ||
|
||||
le32_to_cpu(ctrl_ctx->drop_flags) &
|
||||
xhci_get_endpoint_flag(&ep->desc)) {
|
||||
xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
|
||||
@ -1758,8 +1758,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||
/* Enqueue pointer can be left pointing to the link TRB,
|
||||
* we must handle that
|
||||
*/
|
||||
if ((le32_to_cpu(command->command_trb->link.control)
|
||||
& TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
|
||||
if (TRB_TYPE_LINK_LE32(command->command_trb->link.control))
|
||||
command->command_trb =
|
||||
xhci->cmd_ring->enq_seg->next->trbs;
|
||||
|
||||
@ -2559,8 +2558,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
/* Enqueue pointer can be left pointing to the link TRB,
|
||||
* we must handle that
|
||||
*/
|
||||
if ((le32_to_cpu(reset_device_cmd->command_trb->link.control)
|
||||
& TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
|
||||
if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control))
|
||||
reset_device_cmd->command_trb =
|
||||
xhci->cmd_ring->enq_seg->next->trbs;
|
||||
|
||||
|
@ -1072,6 +1072,13 @@ union xhci_trb {
|
||||
/* Get NEC firmware revision. */
|
||||
#define TRB_NEC_GET_FW 49
|
||||
|
||||
#define TRB_TYPE_LINK(x) (((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
|
||||
/* Above, but for __le32 types -- can avoid work by swapping constants: */
|
||||
#define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
|
||||
cpu_to_le32(TRB_TYPE(TRB_LINK)))
|
||||
#define TRB_TYPE_NOOP_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
|
||||
cpu_to_le32(TRB_TYPE(TRB_TR_NOOP)))
|
||||
|
||||
#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff)
|
||||
#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff)
|
||||
|
||||
|
@ -670,6 +670,9 @@ int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
|
||||
int busnum = ubus? ubus->busnum: 0;
|
||||
int rc;
|
||||
|
||||
if (mon_dir == NULL)
|
||||
return 0;
|
||||
|
||||
if (ubus != NULL) {
|
||||
rc = snprintf(name, NAMESZ, "%dt", busnum);
|
||||
if (rc <= 0 || rc >= NAMESZ)
|
||||
@ -740,12 +743,12 @@ int __init mon_text_init(void)
|
||||
|
||||
mondir = debugfs_create_dir("usbmon", usb_debug_root);
|
||||
if (IS_ERR(mondir)) {
|
||||
printk(KERN_NOTICE TAG ": debugfs is not available\n");
|
||||
return -ENODEV;
|
||||
/* debugfs not available, but we can use usbmon without it */
|
||||
return 0;
|
||||
}
|
||||
if (mondir == NULL) {
|
||||
printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
|
||||
return -ENODEV;
|
||||
return -ENOMEM;
|
||||
}
|
||||
mon_dir = mondir;
|
||||
return 0;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user