Merge tag 'usb-for-v3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

usb: patches for v3.16 merge window

Not a lot here during this merge window. Mostly we just have
the usual miscellaneous patches (removal of unnecessary prints,
proper dependencies being added to Kconfig, build warning fixes,
new device ID, etc.

Other than those, the only important new features are the
new support for OS Strings which should help Linux Gadget
Drivers behave better under MS Windows. Also Babble Recovery
implementation for MUSB on AM335x. Lastly, we also have
ARCH_QCOM PHY support though phy-msm.

Signed-of-by: Felipe Balbi <balbi@ti.com>

Conflicts:
	drivers/usb/phy/phy-mv-u3d-usb.c
This commit is contained in:
Greg Kroah-Hartman
2014-05-23 11:28:21 +09:00
72 changed files with 4124 additions and 789 deletions
@@ -62,6 +62,40 @@ KernelVersion: 3.11
Description:
This group contains functions available to this USB gadget.
What: /config/usb-gadget/gadget/functions/<func>.<inst>/interface.<n>
Date: May 2014
KernelVersion: 3.16
Description:
This group contains "Feature Descriptors" specific for one
gadget's USB interface or one interface group described
by an IAD.
The attributes:
compatible_id - 8-byte string for "Compatible ID"
sub_compatible_id - 8-byte string for "Sub Compatible ID"
What: /config/usb-gadget/gadget/functions/<func>.<inst>/interface.<n>/<property>
Date: May 2014
KernelVersion: 3.16
Description:
This group contains "Extended Property Descriptors" specific for one
gadget's USB interface or one interface group described
by an IAD.
The attributes:
type - value 1..7 for interpreting the data
1: unicode string
2: unicode string with environment variable
3: binary
4: little-endian 32-bit
5: big-endian 32-bit
6: unicode string with a symbolic link
7: multiple unicode strings
data - blob of data to be interpreted depending on
type
What: /config/usb-gadget/gadget/strings
Date: Jun 2013
KernelVersion: 3.11
@@ -79,3 +113,14 @@ Description:
product - gadget's product description
manufacturer - gadget's manufacturer description
What: /config/usb-gadget/gadget/os_desc
Date: May 2014
KernelVersion: 3.16
Description:
This group contains "OS String" extension handling attributes.
use - flag turning "OS Desctiptors" support on/off
b_vendor_code - one-byte value used for custom per-device and
per-interface requests
qw_sign - an identifier to be reported as "OS String"
proper
+2 -1
View File
@@ -14,7 +14,8 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
tracepoint.xml drm.xml media_api.xml w1.xml
tracepoint.xml drm.xml media_api.xml w1.xml \
writing_musb_glue_layer.xml
include Documentation/DocBook/media/Makefile
File diff suppressed because it is too large Load Diff
@@ -12,17 +12,23 @@ Required properties:
- reg : Address and length of the register set for the device
- interrupts : Interrupt numbers for this device
- interrupts : Interrupt numbers for this device. Either one interrupt number
for all interrupts, or one for status related interrupts, one for IN
endpoint related interrupts and one for OUT endpoint related interrupts.
Optional properties:
- epobufsizes : An array of buffer sizes for OUT endpoints. If the property is
not present, or for endpoints outside of the array, 1024 is assumed by
the driver.
- epobufsizes : Array of buffer sizes for OUT endpoints when they differ
from the default size of 1024. The array is indexed by the OUT endpoint
number. If the property is present it typically contains one entry for
each OUT endpoint of the core. Fewer entries overrides the default sizes
only for as many endpoints as the array contains.
- epibufsizes : An array of buffer sizes for IN endpoints. If the property is
not present, or for endpoints outside of the array, 1024 is assumed by
the driver.
- epibufsizes : Array of buffer sizes for IN endpoints when they differ
from the default size of 1024. The array is indexed by the IN endpoint
number. If the property is present it typically contains one entry for
each IN endpoint of the core. Fewer entries overrides the default sizes
only for as many endpoints as the array contains.
For further information look in the documentation for the GLIB IP core library:
http://www.gaisler.com/products/grlib/grip.pdf
@@ -15,3 +15,81 @@ Example EHCI controller device node:
usb-phy = <&usb_otg>;
};
USB PHY with optional OTG:
Required properties:
- compatible: Should contain:
"qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY
"qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY
- regs: Offset and length of the register set in the memory map
- interrupts: interrupt-specifier for the OTG interrupt.
- clocks: A list of phandle + clock-specifier pairs for the
clocks listed in clock-names
- clock-names: Should contain the following:
"phy" USB PHY reference clock
"core" Protocol engine clock
"iface" Interface bus clock
"alt_core" Protocol engine clock for targets with asynchronous
reset methodology. (optional)
- vdccx-supply: phandle to the regulator for the vdd supply for
digital circuit operation.
- v1p8-supply: phandle to the regulator for the 1.8V supply
- v3p3-supply: phandle to the regulator for the 3.3V supply
- resets: A list of phandle + reset-specifier pairs for the
resets listed in reset-names
- reset-names: Should contain the following:
"phy" USB PHY controller reset
"link" USB LINK controller reset
- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of
1 - PHY control
2 - PMIC control
Optional properties:
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
Mode Eye Diagram test. Start address at which these values will be
written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
"do not overwrite default value at this address".
For example: qcom,phy-init-sequence = < -1 0x63 >;
Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1.
- qcom,phy-num: Select number of pyco-phy to use, can be one of
0 - PHY one, default
1 - Second PHY
Some platforms may have configuration to allow USB
controller work with any of the two HSPHYs present.
- qcom,vdd-levels: This property must be a list of three integer values
(no, min, max) where each value represents either a voltage
in microvolts or a value corresponding to voltage corner.
Example HSUSB OTG controller device node:
usb@f9a55000 {
compatible = "qcom,usb-otg-snps";
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>;
dr_mode = "peripheral";
clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>,
<&gcc GCC_USB_HS_AHB_CLK>;
clock-names = "phy", "core", "iface";
vddcx-supply = <&pm8841_s2_corner>;
v1p8-supply = <&pm8941_l6>;
v3p3-supply = <&pm8941_l24>;
resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>;
reset-names = "phy", "link";
qcom,otg-control = <1>;
qcom,phy-init-sequence = < -1 0x63 >;
qcom,vdd-levels = <1 5 7>;
};
+1 -1
View File
@@ -95,7 +95,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk)
static struct msm_otg_platform_data msm_otg_pdata = {
.phy_init_seq = hsusb_phy_init_seq,
.mode = USB_PERIPHERAL,
.mode = USB_DR_MODE_PERIPHERAL,
.otg_control = OTG_PHY_CONTROL,
.link_clk_reset = hsusb_link_clk_reset,
.phy_clk_reset = hsusb_phy_clk_reset,
+1 -1
View File
@@ -116,7 +116,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk)
static struct msm_otg_platform_data msm_otg_pdata = {
.phy_init_seq = hsusb_phy_init_seq,
.mode = USB_PERIPHERAL,
.mode = USB_DR_MODE_PERIPHERAL,
.otg_control = OTG_PHY_CONTROL,
.link_clk_reset = hsusb_link_clk_reset,
.phy_clk_reset = hsusb_phy_clk_reset,
-1
View File
@@ -33,7 +33,6 @@
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
+5 -5
View File
@@ -28,7 +28,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/usb/phy.h>
#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/usb/usb_phy_generic.h>
#include "soc.h"
#include "omap_device.h"
@@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = {
/* .init_data filled later */
};
static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */
static const char *nop_name = "usb_phy_generic"; /* NOP PHY driver */
static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */
/**
@@ -435,7 +435,7 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys)
struct platform_device *pdev;
char *phy_id;
struct platform_device_info pdevinfo;
struct usb_phy_gen_xceiv_platform_data nop_pdata;
struct usb_phy_generic_platform_data nop_pdata;
for (i = 0; i < num_phys; i++) {
@@ -469,8 +469,8 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys)
pdevinfo.id = phy->port;
pdevinfo.data = &nop_pdata;
pdevinfo.size_data =
sizeof(struct usb_phy_gen_xceiv_platform_data);
scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d",
sizeof(struct usb_phy_generic_platform_data);
scnprintf(phy_id, MAX_STR, "usb_phy_generic.%d",
phy->port);
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) {
+3 -1
View File
@@ -44,7 +44,7 @@ comment "Platform Glue Driver Support"
config USB_DWC3_OMAP
tristate "Texas Instruments OMAP5 and similar Platforms"
depends on EXTCON
depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST)
default USB_DWC3
help
Some platforms from Texas Instruments like OMAP5, DRA7xxx and
@@ -54,6 +54,7 @@ config USB_DWC3_OMAP
config USB_DWC3_EXYNOS
tristate "Samsung Exynos Platform"
depends on ARCH_EXYNOS || COMPILE_TEST
default USB_DWC3
help
Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
@@ -72,6 +73,7 @@ config USB_DWC3_PCI
config USB_DWC3_KEYSTONE
tristate "Texas Instruments Keystone2 Platforms"
depends on ARCH_KEYSTONE || COMPILE_TEST
default USB_DWC3
help
Support of USB2/3 functionality in TI Keystone2 platforms.
+133 -120
View File
@@ -486,70 +486,20 @@ static void dwc3_core_exit(struct dwc3 *dwc)
phy_exit(dwc->usb3_generic_phy);
}
#define DWC3_ALIGN_MASK (16 - 1)
static int dwc3_probe(struct platform_device *pdev)
static int dwc3_core_get_phy(struct dwc3 *dwc)
{
struct device *dev = &pdev->dev;
struct dwc3_platform_data *pdata = dev_get_platdata(dev);
struct device *dev = dwc->dev;
struct device_node *node = dev->of_node;
struct resource *res;
struct dwc3 *dwc;
int ret = -ENOMEM;
void __iomem *regs;
void *mem;
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem) {
dev_err(dev, "not enough memory\n");
return -ENOMEM;
}
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
dwc->xhci_resources[1].start = res->start;
dwc->xhci_resources[1].end = res->end;
dwc->xhci_resources[1].flags = res->flags;
dwc->xhci_resources[1].name = res->name;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
return -ENODEV;
}
int ret;
if (node) {
dwc->maximum_speed = of_usb_get_maximum_speed(node);
dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
dwc->dr_mode = of_usb_get_dr_mode(node);
} else if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
dwc->dr_mode = pdata->dr_mode;
} else {
dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
}
/* default to superspeed if no maximum_speed passed */
if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
dwc->maximum_speed = USB_SPEED_SUPER;
if (IS_ERR(dwc->usb2_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
if (ret == -ENXIO || ret == -ENODEV) {
@@ -600,6 +550,132 @@ static int dwc3_probe(struct platform_device *pdev)
}
}
return 0;
}
static int dwc3_core_init_mode(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
int ret;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
case USB_DR_MODE_HOST:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
break;
case USB_DR_MODE_OTG:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
return 0;
}
static void dwc3_core_exit_mode(struct dwc3 *dwc)
{
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_gadget_exit(dwc);
break;
case USB_DR_MODE_HOST:
dwc3_host_exit(dwc);
break;
case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
default:
/* do nothing */
break;
}
}
#define DWC3_ALIGN_MASK (16 - 1)
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dwc3_platform_data *pdata = dev_get_platdata(dev);
struct device_node *node = dev->of_node;
struct resource *res;
struct dwc3 *dwc;
int ret;
void __iomem *regs;
void *mem;
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem) {
dev_err(dev, "not enough memory\n");
return -ENOMEM;
}
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
dwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
dwc->xhci_resources[1].start = res->start;
dwc->xhci_resources[1].end = res->end;
dwc->xhci_resources[1].flags = res->flags;
dwc->xhci_resources[1].name = res->name;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
return -ENODEV;
}
if (node) {
dwc->maximum_speed = of_usb_get_maximum_speed(node);
dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
dwc->dr_mode = of_usb_get_dr_mode(node);
} else if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
dwc->dr_mode = pdata->dr_mode;
}
/* default to superspeed if no maximum_speed passed */
if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
dwc->maximum_speed = USB_SPEED_SUPER;
ret = dwc3_core_get_phy(dwc);
if (ret)
return ret;
dwc->xhci_resources[0].start = res->start;
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
DWC3_XHCI_REGS_END;
@@ -621,7 +697,6 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = dev;
dev->dma_mask = dev->parent->dma_mask;
dev->dma_parms = dev->parent->dma_parms;
@@ -670,41 +745,9 @@ static int dwc3_probe(struct platform_device *pdev)
goto err_usb3phy_power;
}
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
goto err2;
}
break;
case USB_DR_MODE_HOST:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
goto err2;
}
break;
case USB_DR_MODE_OTG:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
goto err2;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
goto err2;
}
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
ret = dwc3_core_init_mode(dwc);
if (ret)
goto err2;
}
ret = dwc3_debugfs_init(dwc);
if (ret) {
@@ -717,21 +760,7 @@ static int dwc3_probe(struct platform_device *pdev)
return 0;
err3:
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_gadget_exit(dwc);
break;
case USB_DR_MODE_HOST:
dwc3_host_exit(dwc);
break;
case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
default:
/* do nothing */
break;
}
dwc3_core_exit_mode(dwc);
err2:
dwc3_event_buffers_cleanup(dwc);
@@ -766,23 +795,7 @@ static int dwc3_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
dwc3_debugfs_exit(dwc);
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_gadget_exit(dwc);
break;
case USB_DR_MODE_HOST:
dwc3_host_exit(dwc);
break;
case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
default:
/* do nothing */
break;
}
dwc3_core_exit_mode(dwc);
dwc3_event_buffers_cleanup(dwc);
dwc3_free_event_buffers(dwc);
dwc3_core_exit(dwc);
+58 -13
View File
@@ -24,9 +24,10 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/usb/usb_phy_generic.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/regulator/consumer.h>
struct dwc3_exynos {
struct platform_device *usb2_phy;
@@ -34,17 +35,19 @@ struct dwc3_exynos {
struct device *dev;
struct clk *clk;
struct regulator *vdd33;
struct regulator *vdd10;
};
static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
{
struct usb_phy_gen_xceiv_platform_data pdata;
struct usb_phy_generic_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;
@@ -56,7 +59,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
if (ret)
goto err1;
pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);
if (!pdev) {
ret = -ENOMEM;
goto err1;
@@ -107,12 +110,12 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
int ret = -ENOMEM;
int ret;
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
if (!exynos) {
dev_err(dev, "not enough memory\n");
goto err1;
return -ENOMEM;
}
/*
@@ -122,21 +125,20 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
*/
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
goto err1;
return ret;
platform_set_drvdata(pdev, exynos);
ret = dwc3_exynos_register_phys(exynos);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
goto err1;
return ret;
}
clk = devm_clk_get(dev, "usbdrd30");
if (IS_ERR(clk)) {
dev_err(dev, "couldn't get clock\n");
ret = -EINVAL;
goto err1;
return -EINVAL;
}
exynos->dev = dev;
@@ -144,23 +146,48 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
clk_prepare_enable(exynos->clk);
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
if (IS_ERR(exynos->vdd33)) {
ret = PTR_ERR(exynos->vdd33);
goto err2;
}
ret = regulator_enable(exynos->vdd33);
if (ret) {
dev_err(dev, "Failed to enable VDD33 supply\n");
goto err2;
}
exynos->vdd10 = devm_regulator_get(dev, "vdd10");
if (IS_ERR(exynos->vdd10)) {
ret = PTR_ERR(exynos->vdd10);
goto err3;
}
ret = regulator_enable(exynos->vdd10);
if (ret) {
dev_err(dev, "Failed to enable VDD10 supply\n");
goto err3;
}
if (node) {
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to add dwc3 core\n");
goto err2;
goto err4;
}
} else {
dev_err(dev, "no device node, failed to add dwc3 core\n");
ret = -ENODEV;
goto err2;
goto err4;
}
return 0;
err4:
regulator_disable(exynos->vdd10);
err3:
regulator_disable(exynos->vdd33);
err2:
clk_disable_unprepare(clk);
err1:
return ret;
}
@@ -174,6 +201,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
clk_disable_unprepare(exynos->clk);
regulator_disable(exynos->vdd33);
regulator_disable(exynos->vdd10);
return 0;
}
@@ -192,12 +222,27 @@ static int dwc3_exynos_suspend(struct device *dev)
clk_disable(exynos->clk);
regulator_disable(exynos->vdd33);
regulator_disable(exynos->vdd10);
return 0;
}
static int dwc3_exynos_resume(struct device *dev)
{
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
int ret;
ret = regulator_enable(exynos->vdd33);
if (ret) {
dev_err(dev, "Failed to enable VDD33 supply\n");
return ret;
}
ret = regulator_enable(exynos->vdd10);
if (ret) {
dev_err(dev, "Failed to enable VDD10 supply\n");
return ret;
}
clk_enable(exynos->clk);
+1 -1
View File
@@ -393,7 +393,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
struct extcon_dev *edev;
struct regulator *vbus_reg = NULL;
int ret = -ENOMEM;
int ret;
int irq;
int utmi_mode = 0;
+8 -13
View File
@@ -23,7 +23,7 @@
#include <linux/platform_device.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/usb/usb_phy_generic.h>
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
@@ -40,13 +40,13 @@ struct dwc3_pci {
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
{
struct usb_phy_gen_xceiv_platform_data pdata;
struct usb_phy_generic_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
pdev = platform_device_alloc("usb_phy_gen_xceiv", 0);
pdev = platform_device_alloc("usb_phy_generic", 0);
if (!pdev)
return -ENOMEM;
@@ -58,7 +58,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue)
if (ret)
goto err1;
pdev = platform_device_alloc("usb_phy_gen_xceiv", 1);
pdev = platform_device_alloc("usb_phy_generic", 1);
if (!pdev) {
ret = -ENOMEM;
goto err1;
@@ -99,7 +99,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
struct resource res[2];
struct platform_device *dwc3;
struct dwc3_pci *glue;
int ret = -ENOMEM;
int ret;
struct device *dev = &pci->dev;
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
@@ -110,7 +110,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
glue->dev = dev;
ret = pci_enable_device(pci);
ret = pcim_enable_device(pci);
if (ret) {
dev_err(dev, "failed to enable pci device\n");
return -ENODEV;
@@ -127,8 +127,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!dwc3) {
dev_err(dev, "couldn't allocate dwc3 device\n");
ret = -ENOMEM;
goto err1;
return -ENOMEM;
}
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@@ -145,7 +144,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
goto err1;
return ret;
}
pci_set_drvdata(pci, glue);
@@ -167,9 +166,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
err3:
platform_device_put(dwc3);
err1:
pci_disable_device(pci);
return ret;
}
@@ -180,7 +176,6 @@ static void dwc3_pci_remove(struct pci_dev *pci)
platform_device_unregister(glue->dwc3);
platform_device_unregister(glue->usb2_phy);
platform_device_unregister(glue->usb3_phy);
pci_disable_device(pci);
}
static const struct pci_device_id dwc3_pci_id_table[] = {
+77 -6
View File
@@ -298,11 +298,76 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
}
}
static const char *dwc3_gadget_generic_cmd_string(u8 cmd)
{
switch (cmd) {
case DWC3_DGCMD_SET_LMP:
return "Set LMP";
case DWC3_DGCMD_SET_PERIODIC_PAR:
return "Set Periodic Parameters";
case DWC3_DGCMD_XMIT_FUNCTION:
return "Transmit Function Wake Device Notification";
case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
return "Set Scratchpad Buffer Array Address Lo";
case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
return "Set Scratchpad Buffer Array Address Hi";
case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
return "Selected FIFO Flush";
case DWC3_DGCMD_ALL_FIFO_FLUSH:
return "All FIFO Flush";
case DWC3_DGCMD_SET_ENDPOINT_NRDY:
return "Set Endpoint NRDY";
case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
return "Run SoC Bus Loopback Test";
default:
return "UNKNOWN";
}
}
static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state)
{
switch (link_state) {
case DWC3_LINK_STATE_U0:
return "U0";
case DWC3_LINK_STATE_U1:
return "U1";
case DWC3_LINK_STATE_U2:
return "U2";
case DWC3_LINK_STATE_U3:
return "U3";
case DWC3_LINK_STATE_SS_DIS:
return "SS.Disabled";
case DWC3_LINK_STATE_RX_DET:
return "RX.Detect";
case DWC3_LINK_STATE_SS_INACT:
return "SS.Inactive";
case DWC3_LINK_STATE_POLL:
return "Polling";
case DWC3_LINK_STATE_RECOV:
return "Recovery";
case DWC3_LINK_STATE_HRESET:
return "Hot Reset";
case DWC3_LINK_STATE_CMPLY:
return "Compliance";
case DWC3_LINK_STATE_LPBK:
return "Loopback";
case DWC3_LINK_STATE_RESET:
return "Reset";
case DWC3_LINK_STATE_RESUME:
return "Resume";
default:
return "UNKNOWN link state\n";
}
}
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
{
u32 timeout = 500;
u32 reg;
dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n",
dwc3_gadget_generic_cmd_string(cmd), cmd, param);
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@ -332,9 +397,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
u32 timeout = 500;
u32 reg;
dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n",
dep->name,
dwc3_gadget_ep_cmd_string(cmd), params->param0,
dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0,
params->param1, params->param2);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
@@ -515,7 +580,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
{
struct dwc3 *dwc = dep->dwc;
u32 reg;
int ret = -ENOMEM;
int ret;
dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
@@ -604,6 +669,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dwc3_remove_requests(dwc, dep);
/* make sure HW endpoint isn't stalled */
if (dep->flags & DWC3_EP_STALL)
__dwc3_gadget_ep_set_halt(dep, 0);
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg &= ~DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
@@ -2441,8 +2510,6 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
}
}
dwc->link_state = next;
switch (next) {
case DWC3_LINK_STATE_U1:
if (dwc->speed == USB_SPEED_SUPER)
@@ -2460,7 +2527,11 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
break;
}
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n",
dwc3_gadget_link_string(dwc->link_state),
dwc->link_state, dwc3_gadget_link_string(next), next);
dwc->link_state = next;
}
static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
+1 -1
View File
@@ -1686,7 +1686,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
reset_all_endpoints(udc);
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver->disconnect) {
&& udc->driver && udc->driver->disconnect) {
udc->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock(&udc->lock);
udc->driver->disconnect(&udc->gadget);
+317 -1
View File
@@ -21,6 +21,24 @@
#include <linux/usb/composite.h>
#include <asm/unaligned.h>
#include "u_os_desc.h"
/**
* struct usb_os_string - represents OS String to be reported by a gadget
* @bLength: total length of the entire descritor, always 0x12
* @bDescriptorType: USB_DT_STRING
* @qwSignature: the OS String proper
* @bMS_VendorCode: code used by the host for subsequent requests
* @bPad: not used, must be zero
*/
struct usb_os_string {
__u8 bLength;
__u8 bDescriptorType;
__u8 qwSignature[OS_STRING_QW_SIGN_LEN];
__u8 bMS_VendorCode;
__u8 bPad;
} __packed;
/*
* The code in this file is utility code, used to build a gadget driver
* from one or more "function" drivers, one or more "configuration"
@@ -422,6 +440,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
{
struct usb_gadget *gadget = cdev->gadget;
struct usb_configuration *c;
struct list_head *pos;
u8 type = w_value >> 8;
enum usb_device_speed speed = USB_SPEED_UNKNOWN;
@@ -440,7 +459,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
/* This is a lookup by config *INDEX* */
w_value &= 0xff;
list_for_each_entry(c, &cdev->configs, list) {
pos = &cdev->configs;
c = cdev->os_desc_config;
if (c)
goto check_config;
while ((pos = pos->next) != &cdev->configs) {
c = list_entry(pos, typeof(*c), list);
/* skip OS Descriptors config which is handled separately */
if (c == cdev->os_desc_config)
continue;
check_config:
/* ignore configs that won't work at this speed */
switch (speed) {
case USB_SPEED_SUPER:
@@ -634,6 +666,7 @@ static int set_config(struct usb_composite_dev *cdev,
if (!c)
goto done;
usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
cdev->config = c;
/* Initialize all interfaces by setting them to altsetting zero. */
@@ -960,6 +993,19 @@ static int get_string(struct usb_composite_dev *cdev,
return s->bLength;
}
if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) {
struct usb_os_string *b = buf;
b->bLength = sizeof(*b);
b->bDescriptorType = USB_DT_STRING;
compiletime_assert(
sizeof(b->qwSignature) == sizeof(cdev->qw_sign),
"qwSignature size must be equal to qw_sign");
memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature));
b->bMS_VendorCode = cdev->b_vendor_code;
b->bPad = 0;
return sizeof(*b);
}
list_for_each_entry(uc, &cdev->gstrings, list) {
struct usb_gadget_strings **sp;
@@ -1206,6 +1252,158 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
req->status, req->actual, req->length);
}
static int count_ext_compat(struct usb_configuration *c)
{
int i, res;
res = 0;
for (i = 0; i < c->next_interface_id; ++i) {
struct usb_function *f;
int j;
f = c->interface[i];
for (j = 0; j < f->os_desc_n; ++j) {
struct usb_os_desc *d;
if (i != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d && d->ext_compat_id)
++res;
}
}
BUG_ON(res > 255);
return res;
}
static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
{
int i, count;
count = 16;
for (i = 0; i < c->next_interface_id; ++i) {
struct usb_function *f;
int j;
f = c->interface[i];
for (j = 0; j < f->os_desc_n; ++j) {
struct usb_os_desc *d;
if (i != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d && d->ext_compat_id) {
*buf++ = i;
*buf++ = 0x01;
memcpy(buf, d->ext_compat_id, 16);
buf += 22;
} else {
++buf;
*buf = 0x01;
buf += 23;
}
count += 24;
if (count >= 4096)
return;
}
}
}
static int count_ext_prop(struct usb_configuration *c, int interface)
{
struct usb_function *f;
int j, res;
res = 0;
f = c->interface[interface];
for (j = 0; j < f->os_desc_n; ++j) {
struct usb_os_desc *d;
if (interface != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d && d->ext_compat_id)
return d->ext_prop_count;
}
return res;
}
static int len_ext_prop(struct usb_configuration *c, int interface)
{
struct usb_function *f;
struct usb_os_desc *d;
int j, res;
res = 10; /* header length */
f = c->interface[interface];
for (j = 0; j < f->os_desc_n; ++j) {
if (interface != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d)
return min(res + d->ext_prop_len, 4096);
}
return res;
}
static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
{
struct usb_function *f;
struct usb_os_desc *d;
struct usb_os_desc_ext_prop *ext_prop;
int j, count, n, ret;
u8 *start = buf;
f = c->interface[interface];
for (j = 0; j < f->os_desc_n; ++j) {
if (interface != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d)
list_for_each_entry(ext_prop, &d->ext_prop, entry) {
/* 4kB minus header length */
n = buf - start;
if (n >= 4086)
return 0;
count = ext_prop->data_len +
ext_prop->name_len + 14;
if (count > 4086 - n)
return -EINVAL;
usb_ext_prop_put_size(buf, count);
usb_ext_prop_put_type(buf, ext_prop->type);
ret = usb_ext_prop_put_name(buf, ext_prop->name,
ext_prop->name_len);
if (ret < 0)
return ret;
switch (ext_prop->type) {
case USB_EXT_PROP_UNICODE:
case USB_EXT_PROP_UNICODE_ENV:
case USB_EXT_PROP_UNICODE_LINK:
usb_ext_prop_put_unicode(buf, ret,
ext_prop->data,
ext_prop->data_len);
break;
case USB_EXT_PROP_BINARY:
usb_ext_prop_put_binary(buf, ret,
ext_prop->data,
ext_prop->data_len);
break;
case USB_EXT_PROP_LE32:
/* not implemented */
case USB_EXT_PROP_BE32:
/* not implemented */
default:
return -EINVAL;
}
buf += count;
}
}
return 0;
}
/*
* The setup() callback implements all the ep0 functionality that's
* not handled lower down, in hardware or the hardware driver(like
@@ -1415,6 +1613,91 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
default:
unknown:
/*
* OS descriptors handling
*/
if (cdev->use_os_string && cdev->os_desc_config &&
(ctrl->bRequest & USB_TYPE_VENDOR) &&
ctrl->bRequest == cdev->b_vendor_code) {
struct usb_request *req;
struct usb_configuration *os_desc_cfg;
u8 *buf;
int interface;
int count = 0;
req = cdev->os_desc_req;
req->complete = composite_setup_complete;
buf = req->buf;
os_desc_cfg = cdev->os_desc_config;
memset(buf, 0, w_length);
buf[5] = 0x01;
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
if (w_index != 0x4 || (w_value >> 8))
break;
buf[6] = w_index;
if (w_length == 0x10) {
/* Number of ext compat interfaces */
count = count_ext_compat(os_desc_cfg);
buf[8] = count;
count *= 24; /* 24 B/ext compat desc */
count += 16; /* header */
put_unaligned_le32(count, buf);
value = w_length;
} else {
/* "extended compatibility ID"s */
count = count_ext_compat(os_desc_cfg);
buf[8] = count;
count *= 24; /* 24 B/ext compat desc */
count += 16; /* header */
put_unaligned_le32(count, buf);
buf += 16;
fill_ext_compat(os_desc_cfg, buf);
value = w_length;
}
break;
case USB_RECIP_INTERFACE:
if (w_index != 0x5 || (w_value >> 8))
break;
interface = w_value & 0xFF;
buf[6] = w_index;
if (w_length == 0x0A) {
count = count_ext_prop(os_desc_cfg,
interface);
put_unaligned_le16(count, buf + 8);
count = len_ext_prop(os_desc_cfg,
interface);
put_unaligned_le32(count, buf);
value = w_length;
} else {
count = count_ext_prop(os_desc_cfg,
interface);
put_unaligned_le16(count, buf + 8);
count = len_ext_prop(os_desc_cfg,
interface);
put_unaligned_le32(count, buf);
buf += 10;
value = fill_ext_prop(os_desc_cfg,
interface, buf);
if (value < 0)
return value;
value = w_length;
}
break;
}
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
composite_setup_complete(gadget->ep0, req);
}
return value;
}
VDBG(cdev,
"non-core control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
@@ -1638,6 +1921,29 @@ fail:
return ret;
}
int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
struct usb_ep *ep0)
{
int ret = 0;
cdev->os_desc_req = usb_ep_alloc_request(ep0, GFP_KERNEL);
if (!cdev->os_desc_req) {
ret = PTR_ERR(cdev->os_desc_req);
goto end;
}
/* OS feature descriptor length <= 4kB */
cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL);
if (!cdev->os_desc_req->buf) {
ret = PTR_ERR(cdev->os_desc_req->buf);
kfree(cdev->os_desc_req);
goto end;
}
cdev->os_desc_req->complete = composite_setup_complete;
end:
return ret;
}
void composite_dev_cleanup(struct usb_composite_dev *cdev)
{
struct usb_gadget_string_container *uc, *tmp;
@@ -1646,6 +1952,10 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
list_del(&uc->list);
kfree(uc);
}
if (cdev->os_desc_req) {
kfree(cdev->os_desc_req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req);
}
if (cdev->req) {
kfree(cdev->req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
@@ -1683,6 +1993,12 @@ static int composite_bind(struct usb_gadget *gadget,
if (status < 0)
goto fail;
if (cdev->use_os_string) {
status = composite_os_desc_req_prepare(cdev, gadget->ep0);
if (status)
goto fail;
}
update_unchanged_dev_desc(&cdev->desc, composite->dev);
/* has userspace failed to provide a serial number? */
File diff suppressed because it is too large Load Diff
+12
View File
@@ -1,6 +1,18 @@
#ifndef USB__GADGET__CONFIGFS__H
#define USB__GADGET__CONFIGFS__H
#include <linux/configfs.h>
void unregister_gadget_item(struct config_item *item);
int usb_os_desc_prepare_interf_dir(struct config_group *parent,
int n_interf,
struct usb_os_desc **desc,
struct module *owner);
static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item)
{
return container_of(to_config_group(item), struct usb_os_desc, group);
}
#endif /* USB__GADGET__CONFIGFS__H */
+4 -29
View File
@@ -33,36 +33,11 @@
#include <linux/poll.h>
#include "u_fs.h"
#include "u_f.h"
#include "configfs.h"
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
/* Variable Length Array Macros **********************************************/
#define vla_group(groupname) size_t groupname##__next = 0
#define vla_group_size(groupname) groupname##__next
#define vla_item(groupname, type, name, n) \
size_t groupname##_##name##__offset = ({ \
size_t align_mask = __alignof__(type) - 1; \
size_t offset = (groupname##__next + align_mask) & ~align_mask;\
size_t size = (n) * sizeof(type); \
groupname##__next = offset + size; \
offset; \
})
#define vla_item_with_sz(groupname, type, name, n) \
size_t groupname##_##name##__sz = (n) * sizeof(type); \
size_t groupname##_##name##__offset = ({ \
size_t align_mask = __alignof__(type) - 1; \
size_t offset = (groupname##__next + align_mask) & ~align_mask;\
size_t size = groupname##_##name##__sz; \
groupname##__next = offset + size; \
offset; \
})
#define vla_ptr(ptr, groupname, name) \
((void *) ((char *)ptr + groupname##_##name##__offset))
/* Reference counter handling */
static void ffs_data_get(struct ffs_data *ffs);
static void ffs_data_put(struct ffs_data *ffs);
@@ -190,7 +165,7 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
/* Devices management *******************************************************/
DEFINE_MUTEX(ffs_lock);
EXPORT_SYMBOL(ffs_lock);
EXPORT_SYMBOL_GPL(ffs_lock);
static struct ffs_dev *_ffs_find_dev(const char *name);
static struct ffs_dev *_ffs_alloc_dev(void);
@@ -2883,7 +2858,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name)
return ret;
}
EXPORT_SYMBOL(ffs_name_dev);
EXPORT_SYMBOL_GPL(ffs_name_dev);
int ffs_single_dev(struct ffs_dev *dev)
{
@@ -2900,7 +2875,7 @@ int ffs_single_dev(struct ffs_dev *dev)
ffs_dev_unlock();
return ret;
}
EXPORT_SYMBOL(ffs_single_dev);
EXPORT_SYMBOL_GPL(ffs_single_dev);
/*
* ffs_lock must be taken by the caller of this function

Some files were not shown because too many files have changed in this diff Show More