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

Merge tag 'usb-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB updates from Greg KH:
 "Here's the big USB 3.11-rc1 merge request.

  Lots of gadget and finally, chipidea driver updates (they were much
  needed), along with a new host controller driver, lots of little
  serial driver fixes, the removal of the 255 usb-serial device
  limitation, and a variety of other minor things.

  All of these have been in the linux-next releases for a while"

* tag 'usb-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (254 commits)
  usb: musb: omap2430: make it compile again
  usb: chipidea: ci_hdrc_imx: access phy via private data
  xhci: Add missing unlocks on error paths
  USB: option,qcserial: move Novatel Gobi1K IDs to qcserial
  ehci-atmel.c: prepare clk before calling enable
  USB: ohci-at91: prepare clk before calling enable
  USB: HWA: fix device probe failure
  wusbcore: add entries in Documentation/ABI for new wusbhc sysfs attributes
  wusbcore: add sysfs attribute for retry count
  wusbcore: add sysfs attribute for DNTS count and interval
  usb: chipidea: drop "13xxx" infix
  usb: phy: tegra: remove duplicated include from phy-tegra-usb.c
  usb: host: xhci-plat: release mem region while removing module
  usbmisc_imx: allow autoloading on according to dt ids
  usb: fix build error without CONFIG_USB_PHY
  usb: check usb_hub_to_struct_hub() return value
  xhci: check for failed dma pool allocation
  usb: gadget: f_subset: fix missing unlock on error in geth_alloc()
  usb: gadget: f_ncm: fix missing unlock on error in ncm_alloc()
  usb: gadget: f_ecm: fix missing unlock on error in ecm_alloc()
  ...
What: /config/usb-gadget
Date: Jun 2013
KenelVersion: 3.11
Description:
This group contains sub-groups corresponding to created
USB gadgets.
What: /config/usb-gadget/gadget
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes of a gadget:
UDC - bind a gadget to UDC/unbind a gadget;
write UDC's name found in /sys/class/udc/*
to bind a gadget, empty string "" to unbind.
bDeviceClass - USB device class code
bDeviceSubClass - USB device subclass code
bDeviceProtocol - USB device protocol code
bMaxPacketSize0 - maximum endpoint 0 packet size
bcdDevice - bcd device release number
bcdUSB - bcd USB specification version number
idProduct - product ID
idVendor - vendor ID
What: /config/usb-gadget/gadget/configs
Date: Jun 2013
KenelVersion: 3.11
Description:
This group contains a USB gadget's configurations
What: /config/usb-gadget/gadget/configs/config
Date: Jun 2013
KernelVersion: 3.11
Description:
The attributes of a configuration:
bmAttributes - configuration characteristics
MaxPower - maximum power consumption from the bus
What: /config/usb-gadget/gadget/configs/config/strings
Date: Jun 2013
KernelVersion: 3.11
Description:
This group contains subdirectories for language-specific
strings for this configuration.
What: /config/usb-gadget/gadget/configs/config/strings/language
Date: Jun 2013
KernelVersion: 3.11
Description:
The attributes:
configuration - configuration description
What: /config/usb-gadget/gadget/functions
Date: Jun 2013
KenelVersion: 3.11
Description:
This group contains functions available to this USB gadget.
What: /config/usb-gadget/gadget/strings
Date: Jun 2013
KenelVersion: 3.11
Description:
This group contains subdirectories for language-specific
strings for this gadget.
What: /config/usb-gadget/gadget/strings/language
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes:
serialnumber - gadget's serial number (string)
product - gadget's product description
manufacturer - gadget's manufacturer description
What: /config/usb-gadget/gadget/functions/acm.name
Date: Jun 2013
KenelVersion: 3.11
Description:
This item contains just one readonly attribute: port_num.
It contains the port number of the /dev/ttyGS<n> device
associated with acm function's instance "name".
What: /config/usb-gadget/gadget/functions/ecm.name
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes:
ifname - network device interface name associated with
this function instance
qmult - queue length multiplier for high and
super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
What: /config/usb-gadget/gadget/functions/eem.name
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes:
ifname - network device interface name associated with
this function instance
qmult - queue length multiplier for high and
super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
What: /config/usb-gadget/gadget/functions/ncm.name
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes:
ifname - network device interface name associated with
this function instance
qmult - queue length multiplier for high and
super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
What: /config/usb-gadget/gadget/functions/obex.name
Date: Jun 2013
KenelVersion: 3.11
Description:
This item contains just one readonly attribute: port_num.
It contains the port number of the /dev/ttyGS<n> device
associated with obex function's instance "name".
What: /config/usb-gadget/gadget/functions/phonet.name
Date: Jun 2013
KenelVersion: 3.11
Description:
This item contains just one readonly attribute: ifname.
It contains the network interface name assigned during
network device registration.
What: /config/usb-gadget/gadget/functions/rndis.name
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes:
ifname - network device interface name associated with
this function instance
qmult - queue length multiplier for high and
super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
What: /config/usb-gadget/gadget/functions/gser.name
Date: Jun 2013
KenelVersion: 3.11
Description:
This item contains just one readonly attribute: port_num.
It contains the port number of the /dev/ttyGS<n> device
associated with gser function's instance "name".
What: /config/usb-gadget/gadget/functions/geth.name
Date: Jun 2013
KenelVersion: 3.11
Description:
The attributes:
ifname - network device interface name associated with
this function instance
qmult - queue length multiplier for high and
super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
......@@ -236,3 +236,30 @@ Description:
This attribute is to expose these information to user space.
The file will read "hotplug", "wired" and "not used" if the
information is available, and "unknown" otherwise.
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
Date: May 2013
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
Description:
USB 2.0 devices may support hardware link power management (LPM)
L1 sleep state. The usb2_lpm_l1_timeout attribute allows
tuning the timeout for L1 inactivity timer (LPM timer), e.g.
needed inactivity time before host requests the device to go to L1 sleep.
Useful for power management tuning.
Supported values are 0 - 65535 microseconds.
What: /sys/bus/usb/devices/.../power/usb2_lpm_besl
Date: May 2013
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
Description:
USB 2.0 devices that support hardware link power management (LPM)
L1 sleep state now use a best effort service latency value (BESL) to
indicate the best effort to resumption of service to the device after the
initiation of the resume event.
If the device does not have a preferred besl value then the host can select
one instead. This usb2_lpm_besl attribute allows to tune the host selected besl
value in order to tune power saving and service latency.
Supported values are 0 - 15.
More information on how besl values map to microseconds can be found in
USB 2.0 ECN Errata for Link Power Management, section 4.10)
......@@ -36,3 +36,22 @@ Description:
Refer to [ECMA-368] section 10.3.1.1 for the value to
use.
What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_dnts
Date: June 2013
KernelVersion: 3.11
Contact: Thomas Pugliese <thomas.pugliese@gmail.com>
Description:
The device notification time slot (DNTS) count and inverval in
milliseconds that the WUSB host should use. This controls how
often the devices will have the opportunity to send
notifications to the host.
What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_retry_count
Date: June 2013
KernelVersion: 3.11
Contact: Thomas Pugliese <thomas.pugliese@gmail.com>
Description:
The number of retries that the WUSB host should attempt
before reporting an error for a bus transaction. The range of
valid values is [0..15], where 0 indicates infinite retries.
......@@ -5,6 +5,12 @@ Required properties:
- reg: Should contain registers location and length
- interrupts: Should contain controller interrupt
Recommended properies:
- phy_type: the type of the phy connected to the core. Should be one
of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
property the PORTSC register won't be touched
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
Optional properties:
- fsl,usbphy: phandler of usb phy that connects to the only one port
- fsl,usbmisc: phandler of non-core register device, with one argument
......
......@@ -6,27 +6,10 @@ Practice : Universal Serial Bus" with the following modifications
and additions :
Required properties :
- compatible : Should be "nvidia,tegra20-ehci" for USB controllers
used in host mode.
- phy_type : Should be one of "ulpi" or "utmi".
- nvidia,vbus-gpio : If present, specifies a gpio that needs to be
activated for the bus to be powered.
- nvidia,phy : phandle of the PHY instance, the controller is connected to.
Required properties for phy_type == ulpi:
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
- compatible : Should be "nvidia,tegra20-ehci".
- nvidia,phy : phandle of the PHY that the controller is connected to.
- clocks : Contains a single entry which defines the USB controller's clock.
Optional properties:
- dr_mode : dual role mode. Indicates the working mode for
nvidia,tegra20-ehci compatible controllers. Can be "host", "peripheral",
or "otg". Default to "host" if not defined for backward compatibility.
host means this is a host controller
peripheral means it is device controller
otg means it can operate as either ("on the go")
- nvidia,has-legacy-mode : boolean indicates whether this controller can
operate in legacy mode (as APX 2500 / 2600). In legacy mode some
registers are accessed through the APB_MISC base address instead of
the USB controller. Since this is a legacy issue it probably does not
warrant a compatible string of its own.
- nvidia,needs-double-reset : boolean is to be set for some of the Tegra2
USB ports, which need reset twice due to hardware issues.
- nvidia,needs-double-reset : boolean is to be set for some of the Tegra20
USB ports, which need reset twice due to hardware issues.
......@@ -4,14 +4,49 @@ The device node for Tegra SOC USB PHY:
Required properties :
- compatible : Should be "nvidia,tegra20-usb-phy".
- reg : Address and length of the register set for the USB PHY interface.
- phy_type : Should be one of "ulpi" or "utmi".
- reg : Defines the following set of registers, in the order listed:
- The PHY's own register set.
Always present.
- The register set of the PHY containing the UTMI pad control registers.
Present if-and-only-if phy_type == utmi.
- phy_type : Should be one of "utmi", "ulpi" or "hsic".
- clocks : Defines the clocks listed in the clock-names property.
- clock-names : The following clock names must be present:
- reg: The clock needed to access the PHY's own registers. This is the
associated EHCI controller's clock. Always present.
- pll_u: PLL_U. Always present.
- timer: The timeout clock (clk_m). Present if phy_type == utmi.
- utmi-pads: The clock needed to access the UTMI pad control registers.
Present if phy_type == utmi.
- ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2).
Present if phy_type == ulpi, and ULPI link mode is in use.
Required properties for phy_type == ulpi:
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
Required PHY timing params for utmi phy:
- nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
start of sync launches RxActive
- nvidia,elastic-limit : Variable FIFO Depth of elastic input store
- nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
before declare IDLE.
- nvidia,term-range-adj : Range adjusment on terminations
- nvidia,xcvr-setup : HS driver output control
- nvidia,xcvr-lsfslew : LS falling slew rate control.
- nvidia,xcvr-lsrslew : LS rising slew rate control.
Optional properties:
- nvidia,has-legacy-mode : boolean indicates whether this controller can
operate in legacy mode (as APX 2500 / 2600). In legacy mode some
registers are accessed through the APB_MISC base address instead of
the USB controller.
\ No newline at end of file
the USB controller.
- nvidia,is-wired : boolean. Indicates whether we can do certain kind of power
optimizations for the devices that are always connected. e.g. modem.
- dr_mode : dual role mode. Indicates the working mode for the PHY. Can be
"host", "peripheral", or "otg". Defaults to "host" if not defined.
host means this is a host controller
peripheral means it is device controller
otg means it can operate as either ("on the go")
Required properties for dr_mode == otg:
- vbus-supply: regulator for VBUS
......@@ -4,6 +4,10 @@ Required properties:
- compatible: Should be "smsc,usb3503".
- reg: Specifies the i2c slave address, it should be 0x08.
- connect-gpios: Should specify GPIO for connect.
- disabled-ports: Should specify the ports unused.
'1' or '2' or '3' are availe for this property to describe the port
number. 1~3 property values are possible to be desribed.
Do not describe this property if all ports have to be enabled.
- intn-gpios: Should specify GPIO for interrupt.
- reset-gpios: Should specify GPIO for reset.
- initial-mode: Should specify initial mode.
......@@ -14,6 +18,7 @@ Examples:
compatible = "smsc,usb3503";
reg = <0x08>;
connect-gpios = <&gpx3 0 1>;
disabled-ports = <2 3>;
intn-gpios = <&gpx3 4 1>;
reset-gpios = <&gpx3 5 1>;
initial-mode = <1>;
......
Linux USB gadget configured through configfs
25th April 2013
Overview
========
A USB Linux Gadget is a device which has a UDC (USB Device Controller) and can
be connected to a USB Host to extend it with additional functions like a serial
port or a mass storage capability.
A gadget is seen by its host as a set of configurations, each of which contains
a number of interfaces which, from the gadget's perspective, are known as
functions, each function representing e.g. a serial connection or a SCSI disk.
Linux provides a number of functions for gadgets to use.
Creating a gadget means deciding what configurations there will be
and which functions each configuration will provide.
Configfs (please see Documentation/filesystems/configfs/*) lends itslef nicely
for the purpose of telling the kernel about the above mentioned decision.
This document is about how to do it.
It also describes how configfs integration into gadget is designed.
Requirements
============
In order for this to work configfs must be available, so CONFIGFS_FS must be
'y' or 'm' in .config. As of this writing USB_LIBCOMPOSITE selects CONFIGFS_FS.
Usage
=====
(The original post describing the first function
made available through configfs can be seen here:
http://www.spinics.net/lists/linux-usb/msg76388.html)
$ modprobe libcomposite
$ mount none $CONFIGFS_HOME -t configfs
where CONFIGFS_HOME is the mount point for configfs
1. Creating the gadgets
-----------------------
For each gadget to be created its corresponding directory must be created:
$ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>
e.g.:
$ mkdir $CONFIGFS_HOME/usb_gadget/g1
...
...
...
$ cd $CONFIGFS_HOME/usb_gadget/g1
Each gadget needs to have its vendor id <VID> and product id <PID> specified:
$ echo <VID> > idVendor
$ echo <PID> > idProduct
A gadget also needs its serial number, manufacturer and product strings.
In order to have a place to store them, a strings subdirectory must be created
for each language, e.g.:
$ mkdir strings/0x409
Then the strings can be specified:
$ echo <serial number> > strings/0x409/serialnumber
$ echo <manufacturer> > strings/0x409/manufacturer
$ echo <product> > strings/0x409/product
2. Creating the configurations
------------------------------
Each gadget will consist of a number of configurations, their corresponding
directories must be created:
$ mkdir configs/<name>.<number>
where <name> can be any string which is legal in a filesystem and the
<numebr> is the configuration's number, e.g.:
$ mkdir configs/c.1
...
...
...
Each configuration also needs its strings, so a subdirectory must be created
for each language, e.g.:
$ mkdir configs/c.1/strings/0x409
Then the configuration string can be specified:
$ echo <configuration> > configs/c.1/strings/0x409/configuration
Some attributes can also be set for a configuration, e.g.:
$ echo 120 > configs/c.1/MaxPower
3. Creating the functions
-------------------------
The gadget will provide some functions, for each function its corresponding
directory must be created:
$ mkdir functions/<name>.<instance name>
where <name> corresponds to one of allowed function names and instance name
is an arbitrary string allowed in a filesystem, e.g.:
$ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()
...
...
...
Each function provides its specific set of attributes, with either read-only
or read-write access. Where applicable they need to be written to as
appropriate.
Please refer to Documentation/ABI/*/configfs-usb-gadget* for more information.
4. Associating the functions with their configurations
------------------------------------------------------
At this moment a number of gadgets is created, each of which has a number of
configurations specified and a number of functions available. What remains
is specifying which function is available in which configuration (the same
function can be used in multiple configurations). This is achieved with
creating symbolic links:
$ ln -s functions/<name>.<instance name> configs/<name>.<number>
e.g.:
$ ln -s functions/ncm.usb0 configs/c.1
...
...
...
5. Enabling the gadget
----------------------
All the above steps serve the purpose of composing the gadget of
configurations and functions.
An example directory structure might look like this:
.
./strings
./strings/0x409
./strings/0x409/serialnumber
./strings/0x409/product
./strings/0x409/manufacturer
./configs
./configs/c.1
./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0
./configs/c.1/strings
./configs/c.1/strings/0x409
./configs/c.1/strings/0x409/configuration
./configs/c.1/bmAttributes
./configs/c.1/MaxPower
./functions
./functions/ncm.usb0
./functions/ncm.usb0/ifname
./functions/ncm.usb0/qmult
./functions/ncm.usb0/host_addr
./functions/ncm.usb0/dev_addr
./UDC
./bcdUSB
./bcdDevice
./idProduct
./idVendor
./bMaxPacketSize0
./bDeviceProtocol
./bDeviceSubClass
./bDeviceClass
Such a gadget must be finally enabled so that the USB host can enumerate it.
In order to enable the gadget it must be bound to a UDC (USB Device Controller).
$ echo <udc name> > UDC
where <udc name> is one of those found in /sys/class/udc/*
e.g.:
$ echo s3c-hsotg > UDC
6. Disabling the gadget
-----------------------
$ echo "" > UDC
7. Cleaning up
--------------
Remove functions from configurations:
$ rm configs/<config name>.<number>/<function>
where <config name>.<number> specify the configuration and <function> is
a symlink to a function being removed from the configuration, e.g.:
$ rm configfs/c.1/ncm.usb0
...
...
...
Remove strings directories in configurations
$ rmdir configs/<config name>.<number>/strings/<lang>
e.g.:
$ rmdir configs/c.1/strings/0x409
...
...
...
and remove the configurations
$ rmdir configs/<config name>.<number>
e.g.:
rmdir configs/c.1
...
...
...
Remove functions (function modules are not unloaded, though)
$ rmdir functions/<name>.<instance name>
e.g.:
$ rmdir functions/ncm.usb0
...
...
...
Remove strings directories in the gadget
$ rmdir strings/<lang>
e.g.:
$ rmdir strings/0x409
and finally remove the gadget:
$ cd ..
$ rmdir <gadget name>
e.g.:
$ rmdir g1
Implementation design
=====================
Below the idea of how configfs works is presented.
In configfs there are items and groups, both represented as directories.
The difference between an item and a group is that a group can contain
other groups. In the picture below only an item is shown.
Both items and groups can have attributes, which are represented as files.
The user can create and remove directories, but cannot remove files,
which can be read-only or read-write, depending on what they represent.
The filesystem part of configfs operates on config_items/groups and
configfs_attributes which are generic and of the same type for all
configured elements. However, they are embedded in usage-specific
larger structures. In the picture below there is a "cs" which contains
a config_item and an "sa" which contains a configfs_attribute.
The filesystem view would be like this:
./
./cs (directory)
|
+--sa (file)
|
.
.
.
Whenever a user reads/writes the "sa" file, a function is called
which accepts a struct config_item and a struct configfs_attribute.
In the said function the "cs" and "sa" are retrieved using the well
known container_of technique and an appropriate sa's function (show or
store) is called and passed the "cs" and a character buffer. The "show"
is for displaying the file's contents (copy data from the cs to the
buffer), while the "store" is for modifying the file's contents (copy data
from the buffer to the cs), but it is up to the implementer of the
two functions to decide what they actually do.
typedef struct configured_structure cs;
typedef struc specific_attribute sa;
sa
+----------------------------------+
cs | (*show)(cs *, buffer); |
+-----------------+ | (*store)(cs *, buffer, length); |
| | | |
| +-------------+ | | +------------------+ |
| | struct |-|----|------>|struct | |
| | config_item | | | |configfs_attribute| |
| +-------------+ | | +------------------+ |
| | +----------------------------------+
| data to be set | .
| | .
+-----------------+ .
The file names are decided by the config item/group designer, while
the directories in general can be named at will. A group can have
a number of its default sub-groups created automatically.
For more information on configfs please see
Documentation/filesystems/configfs/*.
The concepts described above translate to USB gadgets like this:
1. A gadget has its config group, which has some attributes (idVendor,
idProduct etc) and default sub-groups (configs, functions, strings).
Writing to the attributes causes the information to be stored in
appropriate locations. In the configs, functions and strings sub-groups
a user can create their sub-groups to represent configurations, functions,
and groups of strings in a given language.
2. The user creates configurations and functions, in the configurations
creates symbolic links to functions. This information is used when the
gadget's UDC attribute is written to, which means binding the gadget
to the UDC. The code in drivers/usb/gadget/configfs.c iterates over
all configurations, and in each configuration it iterates over all
functions and binds them. This way the whole gadget is bound.
3. The file drivers/usb/gadget/configfs.c contains code for
- gadget's config_group
- gadget's default groups (configs, functions, strings)
- associating functions with configurations (symlinks)
4. Each USB function naturally has its own view of what it wants
configured, so config_groups for particular functions are defined
in the functions implementation files drivers/usb/gadget/f_*.c.
5. Funciton's code is written in such a way that it uses
usb_get_function_instance(), which, in turn, calls request_module.
So, provided that modprobe works, modules for particular functions
are loaded automatically. Please note that the converse is not true:
after a gadget is disabled and torn down, the modules remain loaded.
......@@ -449,7 +449,11 @@
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb-phy@c5004000 {
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
sdhci@c8000600 {
......
......@@ -428,17 +428,26 @@
status = "okay";
};
usb-phy@c5000000 {
status = "okay";
};
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb-phy@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
usb-phy@c5008000 {
status = "okay";
};
sdhci@c8000200 {
......
......@@ -38,13 +38,20 @@
usb@c5000000 {
status = "okay";
dr_mode = "otg";
};
usb-phy@c5000000 {
status = "okay";
};
usb@c5008000 {
status = "okay";
};
usb-phy@c5008000 {
status = "okay";
};
serial@70006000 {
status = "okay";
};
......
......@@ -427,17 +427,26 @@
status = "okay";
};
usb-phy@c5000000 {
status = "okay";
};
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};
usb-phy@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};
usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
usb-phy@c5008000 {
status = "okay";
};
sdhci@c8000000 {
......
......@@ -569,17 +569,28 @@
dr_mode = "otg";
};
usb-phy@c5000000 {
status = "okay";
vbus-supply = <&vbus_reg>;
dr_mode = "otg";
};
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb-phy@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
usb-phy@c5008000 {
status = "okay";
};
sdhci@c8000000 {
......@@ -807,6 +818,15 @@
gpio = <&pmic 1 0>;
enable-active-high;
};
vbus_reg: regulator@3 {
compatible = "regulator-fixed";
reg = <3>;
regulator-name = "vdd_vbus_wup1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio 24 0>; /* PD0 */
};
};
sound {
......
......@@ -470,6 +470,10 @@
status = "okay";
};
usb-phy@c5008000 {
status = "okay";
};
sdhci@c8000600 {
cd-gpios = <&gpio 58 1>; /* gpio PH2 */
wp-gpios = <&gpio 59 0>; /* gpio PH3 */
......
......@@ -314,17 +314,27 @@
nvidia,vbus-gpio = <&gpio 170 0>; /* gpio PV2 */
};
usb-phy@c5000000 {
status = "okay";
vbus-supply = <&vbus_reg>;
};
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};
usb-phy@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};
usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
usb-phy@c5008000 {
status = "okay";
};
sdhci@c8000000 {
......@@ -390,6 +400,15 @@
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
vbus_reg: regulator@2 {
compatible = "regulator-fixed";
reg = <2>;
regulator-name = "usb1_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio 170 0>; /* PV2 */
};
};
sound {
......
......@@ -505,17 +505,26 @@
status = "okay";
};
usb-phy@c5000000 {
status = "okay";
};
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb-phy@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};
usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
usb-phy@c5008000 {
status = "okay";
};
sdhci@c8000000 {
......
......@@ -511,11 +511,21 @@
nvidia,vbus-gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
};
usb-phy@c5000000 {
status = "okay";
vbus-supply = <&vbus1_reg>;
};
usb@c5008000 {
status = "okay";
nvidia,vbus-gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
};
usb-phy@c5008000 {
status = "okay";
vbus-supply = <&vbus3_reg>;
};
sdhci@c8000400 {
status = "okay";
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
......@@ -568,6 +578,24 @@
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
vbus1_reg: regulator@2 {
compatible = "regulator-fixed";
reg = <2>;
regulator-name = "vbus1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
};
vbus3_reg: regulator@3 {
compatible = "regulator-fixed";
reg = <3>;
regulator-name = "vbus3";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
};
};
sound {
......
......@@ -455,13 +455,24 @@
status = "disabled";
};
phy1: usb-phy@c5000400 {
phy1: usb-phy@c5000000 {
compatible = "nvidia,tegra20-usb-phy";
reg = <0xc5000400 0x3c00>;
reg = <0xc5000000 0x4000 0xc5000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car 22>,
<&tegra_car 127>,
<&tegra_car 106>,
<&tegra_car 22>;
clock-names = "reg", "pll_u", "timer", "utmi-pads";
nvidia,has-legacy-mode;
clocks = <&tegra_car 22>, <&tegra_car 127>;
clock-names = "phy", "pll_u";
hssync_start_delay = <9>;
idle_wait_delay = <17>;
elastic_limit = <16>;
term_range_adj = <6>;
xcvr_setup = <9>;
xcvr_lsfslew = <1>;
xcvr_lsrslew = <1>;
status = "disabled";
};
usb@c5004000 {
......@@ -474,12 +485,15 @@
status = "disabled";
};
phy2: usb-phy@c5004400 {
phy2: usb-phy@c5004000 {
compatible = "nvidia,tegra20-usb-phy";
reg = <0xc5004400 0x3c00>;
reg = <0xc5004000 0x4000>;
phy_type = "ulpi";
clocks = <&tegra_car 93>, <&tegra_car 127>;
clock-names = "phy", "pll_u";
clocks = <&tegra_car 58>,
<&tegra_car 127>,
<&tegra_car 93>;
clock-names = "reg", "pll_u", "ulpi-link";
status = "disabled";
};
usb@c5008000 {
......@@ -492,12 +506,23 @@
status = "disabled";
};
phy3: usb-phy@c5008400 {
phy3: usb-phy@c5008000 {
compatible = "nvidia,tegra20-usb-phy";
reg = <0xc5008400 0x3c00>;
reg = <0xc5008000 0x4000 0xc5000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car 22>, <&tegra_car 127>;
clock-names = "phy", "pll_u";
clocks = <&tegra_car 59>,
<&tegra_car 127>,
<&tegra_car 106>,
<&tegra_car 22>;
clock-names = "reg", "pll_u", "timer", "utmi-pads";
hssync_start_delay = <9>;
idle_wait_delay = <17>;
elastic_limit = <16>;
term_range_adj = <6>;
xcvr_setup = <9>;
xcvr_lsfslew = <2>;
xcvr_lsrslew = <2>;
status = "disabled";
};
sdhci@c8000000 {
......
......@@ -873,7 +873,7 @@ static int qt_open(struct tty_struct *tty,
result = qt_get_device(serial, &port0->DeviceData);
/* Port specific setups */
result = qt_open_channel(serial, port->number, &ChannelData);
result = qt_open_channel(serial, port->port_number, &ChannelData);
if (result < 0) {
dev_dbg(&port->dev, "qt_open_channel failed\n");
return result;
......@@ -888,7 +888,7 @@ static int qt_open(struct tty_struct *tty,
(SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD);
/* Set Baud rate to default and turn off (default)flow control here */
result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR);
result = qt_setuart(serial, port->port_number, DEFAULT_DIVISOR, DEFAULT_LCR);
if (result < 0) {
dev_dbg(&port->dev, "qt_setuart failed\n");
return result;
......@@ -906,8 +906,7 @@ static int qt_open(struct tty_struct *tty,
qt_submit_urb_from_open(serial, port);
}
dev_dbg(&port->dev, "port number is %d\n", port->number);
dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor);
dev_dbg(&port->dev, "minor number is %d\n", port->minor);
dev_dbg(&port->dev,
"Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
dev_dbg(&port->dev,
......@@ -1003,7 +1002,7 @@ static void qt_close(struct usb_serial_port *port)
status = 0;
tty = tty_port_tty_get(&port->port);
index = tty->index - serial->minor;
index = port->port_number;
qt_port = qt_get_port_private(port);
port0 = qt_get_port_private(serial->port[0]);
......@@ -1022,14 +1021,11 @@ static void qt_close(struct usb_serial_port *port)
/* Close uart channel */
status = qt_close_channel(serial, index);
if (status < 0)
dev_dbg(&port->dev,
"%s - port %d qt_close_channel failed.\n",
__func__, port->number);
dev_dbg(&port->dev, "%s - qt_close_channel failed.\n", __func__);
port0->open_ports--;
dev_dbg(&port->dev, "qt_num_open_ports in close%d:in port%d\n",
port0->open_ports, port->number);
dev_dbg(&port->dev, "qt_num_open_ports in close%d\n", port0->open_ports);
if (port0->open_ports == 0) {
if (serial->port[0]->interrupt_in_urb) {
......@@ -1133,12 +1129,11 @@ static int qt_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct quatech_port *qt_port = qt_get_port_private(port);
struct usb_serial *serial = get_usb_serial(port, __func__);
unsigned int index;
dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
index = tty->index - serial->minor;
index = port->port_number;
if (cmd == TIOCMIWAIT) {
while (qt_port != NULL) {
......@@ -1169,8 +1164,7 @@ static int qt_ioctl(struct tty_struct *tty,
return 0;
}
dev_dbg(&port->dev, "%s -No ioctl for that one. port = %d\n",
__func__, port->number);
dev_dbg(&port->dev, "%s -No ioctl for that one.\n", __func__);
return -ENOIOCTLCMD;
}
......@@ -1185,7 +1179,7 @@ static void qt_set_termios(struct tty_struct *tty,
int baud, divisor, remainder;
int status;
index = tty->index - port->serial->minor;
index = port->port_number;
switch (cflag & CSIZE) {
case CS5:
......@@ -1245,8 +1239,7 @@ static void qt_set_termios(struct tty_struct *tty,
/* Now determine flow control */
if (cflag & CRTSCTS) {
dev_dbg(&port->dev, "%s - Enabling HW flow control port %d\n",
__func__, port->number);
dev_dbg(&port->dev, "%s - Enabling HW flow control\n", __func__);
/* Enable RTS/CTS flow control */
status = BoxSetHW_FlowCtrl(port->serial, index, 1);
......@@ -1258,8 +1251,7 @@ static void qt_set_termios(struct tty_struct *tty,
} else {
/* Disable RTS/CTS flow control */
dev_dbg(&port->dev,
"%s - disabling HW flow control port %d\n",
__func__, port->number);
"%s - disabling HW flow control\n", __func__);
status = BoxSetHW_FlowCtrl(port->serial, index, 0);
if (status < 0) {
......@@ -1303,7 +1295,7 @@ static void qt_break(struct tty_struct *tty, int break_state)
u16 index, onoff;
unsigned int result;
index = tty->index - serial->minor;
index = port->port_number;
qt_port = qt_get_port_private(port);
......@@ -1332,7 +1324,7 @@ static inline int qt_real_tiocmget(struct tty_struct *tty,
int status;
unsigned int index;
index = tty->index - serial->minor;
index = port->port_number;
status =
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
if (status >= 0) {
......@@ -1371,7 +1363,7 @@ static inline int qt_real_tiocmset(struct tty_struct *tty,
int status;
unsigned int index;
index = tty->index - serial->minor;
index = port->port_number;
status =
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
if (status < 0)
......
......@@ -2,59 +2,15 @@
# USB device configuration
#
# many non-PCI SOC chips embed OHCI
# These are unused now, remove them once they are no longer selected
config USB_ARCH_HAS_OHCI
boolean
# ARM:
default y if SA1111
default y if ARCH_OMAP
default y if ARCH_S3C24XX
default y if PXA27x
default y if PXA3xx
default y if ARCH_EP93XX
default y if ARCH_AT91
default y if MFD_TC6393XB
default y if ARCH_W90X900
default y if ARCH_DAVINCI_DA8XX
default y if ARCH_CNS3XXX
default y if PLAT_SPEAR
default y if ARCH_EXYNOS
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
# MIPS:
default y if MIPS_ALCHEMY
default y if MACH_JZ4740
# more:
default PCI
# some non-PCI hcds implement EHCI
bool
config USB_ARCH_HAS_EHCI
boolean
default y if FSL_SOC
default y if PPC_MPC512x
default y if ARCH_IXP4XX
default y if ARCH_W90X900
default y if ARCH_AT91
default y if ARCH_MXC
default y if ARCH_MXS
default y if ARCH_OMAP3
default y if ARCH_CNS3XXX
default y if ARCH_VT8500
default y if PLAT_SPEAR
default y if PLAT_S5P
default y if ARCH_MSM
default y if MICROBLAZE
default y if SPARC_LEON
default y if ARCH_MMP
default y if MACH_LOONGSON1
default y if PLAT_ORION
default PCI
# some non-PCI HCDs implement xHCI
bool
config USB_ARCH_HAS_XHCI
boolean
default PCI
bool
menuconfig USB_SUPPORT
bool "USB support"
......@@ -71,19 +27,8 @@ config USB_COMMON
default y
depends on USB || USB_GADGET
# Host-side USB depends on having a host controller
# NOTE: dummy_hcd is always an option, but it's ignored here ...
# NOTE: SL-811 option should be board-specific ...
config USB_ARCH_HAS_HCD
boolean
default y if USB_ARCH_HAS_OHCI
default y if USB_ARCH_HAS_EHCI
default y if USB_ARCH_HAS_XHCI
default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811
default y if BLACKFIN # SL-811
default y if SUPERH # r8a66597-hcd
default PCI
def_bool y
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
config USB
......
......@@ -25,6 +25,7 @@ obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_ISP1760_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
obj-$(CONFIG_USB_FUSBH200_HCD) += host/
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
......
......@@ -12,15 +12,15 @@ if USB_CHIPIDEA
config USB_CHIPIDEA_UDC
bool "ChipIdea device controller"
depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA
depends on USB_GADGET=y || USB_CHIPIDEA=m
help
Say Y here to enable device controller functionality of the
ChipIdea driver.
config USB_CHIPIDEA_HOST
bool "ChipIdea host controller"
depends on USB=y || USB=USB_CHIPIDEA
depends on USB_EHCI_HCD=y
depends on USB=y
depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
select USB_EHCI_ROOT_HUB_TT
help
Say Y here to enable host controller functionality of the
......
......@@ -9,13 +9,13 @@ ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
# Glue/Bridge layers go here
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
# PCI doesn't provide stubs, need to check
ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_pci.o
endif
ifneq ($(CONFIG_OF_DEVICE),)
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_imx.o usbmisc_imx.o
endif
......@@ -48,10 +48,24 @@
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)
/* PTS and PTW for non lpm version only */
#define PORTSC_PTS(d) \
((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
#define PORTSC_PTW BIT(28)
#define PORTSC_STS BIT(29)
/* DEVLC */
#define DEVLC_PSPD (0x03UL << 25)
#define DEVLC_PSPD_HS (0x02UL << 25)
#define DEVLC_PSPD_HS (0x02UL << 25)
#define DEVLC_PTW BIT(27)
#define DEVLC_STS BIT(28)
#define DEVLC_PTS(d) (((d) & 0x7) << 29)
/* Encoding for DEVLC_PTS and PORTSC_PTS */
#define PTS_UTMI 0
#define PTS_ULPI 2
#define PTS_SERIAL 3
#define PTS_HSIC 4
/* OTGSC */
#define OTGSC_IDPU BIT(5)
......
......@@ -22,14 +22,14 @@
* DEFINE
*****************************************************************************/
#define TD_PAGE_COUNT 5
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define CI_HDRC_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
/******************************************************************************
* STRUCTURES
*****************************************************************************/
/**
* struct ci13xxx_ep - endpoint representation
* struct ci_hw_ep - endpoint representation
* @ep: endpoint structure for gadget drivers
* @dir: endpoint direction (TX/RX)
* @num: endpoint number
......@@ -41,7 +41,7 @@
* @lock: pointer to controller's spinlock
* @td_pool: pointer to controller's TD pool
*/
struct ci13xxx_ep {
struct ci_hw_ep {
struct usb_ep ep;
u8 dir;
u8 num;
......@@ -49,15 +49,16 @@ struct ci13xxx_ep {
char name[16];
struct {
struct list_head queue;
struct ci13xxx_qh *ptr;
struct ci_hw_qh *ptr;
dma_addr_t dma;
} qh;
int wedge;
/* global resources */
struct ci13xxx *ci;
struct ci_hdrc *ci;
spinlock_t *lock;
struct dma_pool *td_pool;
struct td_node *pending_td;
};
enum ci_role {
......@@ -74,9 +75,9 @@ enum ci_role {
* name: role name string (host/gadget)
*/
struct ci_role_driver {
int (*start)(struct ci13xxx *);
void (*stop)(struct ci13xxx *);
irqreturn_t (*irq)(struct ci13xxx *);
int (*start)(struct ci_hdrc *);
void (*stop)(struct ci_hdrc *);
irqreturn_t (*irq)(struct ci_hdrc *);
const char *name;
};
......@@ -101,7 +102,7 @@ struct hw_bank {
};
/**
* struct ci13xxx - chipidea device representation
* struct ci_hdrc - chipidea device representation
* @dev: pointer to parent device
* @lock: access synchronization
* @hw_bank: hardware register mapping
......@@ -116,7 +117,7 @@ struct hw_bank {
* @gadget: device side representation for peripheral controller
* @driver: gadget driver
* @hw_ep_max: total number of endpoints supported by hardware
* @ci13xxx_ep: array of endpoints
* @ci_hw_ep: array of endpoints
* @ep0_dir: ep0 direction
* @ep0out: pointer to ep0 OUT endpoint
* @ep0in: pointer to ep0 IN endpoint
......@@ -132,7 +133,7 @@ struct hw_bank {
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
*/
struct ci13xxx {
struct ci_hdrc {
struct device *dev;
spinlock_t lock;
struct hw_bank hw_bank;
......@@ -149,9 +150,9 @@ struct ci13xxx {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
unsigned hw_ep_max;
struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX];
struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
u32 ep0_dir;
struct ci13xxx_ep *ep0out, *ep0in;
struct ci_hw_ep *ep0out, *ep0in;
struct usb_request *status;
bool setaddr;
......@@ -160,7 +161,7 @@ struct ci13xxx {
u8 suspended;
u8 test_mode;
struct ci13xxx_platform_data *platdata;
struct ci_hdrc_platform_data *platdata;
int vbus_active;
/* FIXME: some day, we'll not use global phy */
bool global_phy;
......@@ -169,13 +170,13 @@ struct ci13xxx {
struct dentry *debugfs;
};
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
{
BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
return ci->roles[ci->role];
}
static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
{
int ret;
......@@ -191,7 +192,7 @@ static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
return ret;
}
static inline void ci_role_stop(struct ci13xxx *ci)
static inline void ci_role_stop(struct ci_hdrc *ci)
{
enum ci_role role = ci->role;
......@@ -210,7 +211,7 @@ static inline void ci_role_stop(struct ci13xxx *ci)
#define REG_BITS (32)
/* register indices */
enum ci13xxx_regs {
enum ci_hw_regs {
CAP_CAPLENGTH,
CAP_HCCPARAMS,
CAP_DCCPARAMS,
......@@ -242,7 +243,7 @@ enum ci13xxx_regs {
*
* This function returns register contents
*/
static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
static inline u32 hw_read(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask)
{
return ioread32(ci->hw_bank.regmap[reg]) & mask;
}
......@@ -253,7 +254,7 @@ static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
* @mask: bitfield mask
* @data: new value
*/
static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
static inline void hw_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
u32 mask, u32 data)
{
if (~mask)
......@@ -270,7 +271,7 @@ static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
*
* This function returns register contents
*/
static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
static inline u32 hw_test_and_clear(struct ci_hdrc *ci, enum ci_hw_regs reg,
u32 mask)
{
u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask;
......@@ -287,7 +288,7 @@ static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
*
* This function returns register contents
*/
static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
u32 mask, u32 data)
{
u32 val = hw_read(ci, reg, ~0);
......@@ -296,10 +297,10 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
return (val & mask) >> __ffs(mask);
}
int hw_device_reset(struct ci13xxx *ci, u32 mode);
int hw_device_reset(struct ci_hdrc *ci, u32 mode);
int hw_port_test_set(struct ci13xxx *ci, u8 mode);
int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
u8 hw_port_test_get(struct ci13xxx *ci);
u8 hw_port_test_get(struct ci_hdrc *ci);
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
......@@ -20,16 +20,14 @@
#include <linux/usb/chipidea.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include "ci.h"
#include "ci13xxx_imx.h"
#include "ci_hdrc_imx.h"
#define pdev_to_phy(pdev) \
((struct usb_phy *)platform_get_drvdata(pdev))
struct ci13xxx_imx_data {
struct device_node *phy_np;
struct ci_hdrc_imx_data {
struct usb_phy *phy;
struct platform_device *ci_pdev;
struct clk *clk;
......@@ -88,22 +86,17 @@ EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
/* End of common functions shared by usbmisc drivers*/
static struct ci13xxx_platform_data ci13xxx_imx_platdata = {
.name = "ci13xxx_imx",
.flags = CI13XXX_REQUIRE_TRANSCEIVER |
CI13XXX_PULLUP_ON_VBUS |
CI13XXX_DISABLE_STREAMING,
.capoffset = DEF_CAPOFFSET,
};
static int ci13xxx_imx_probe(struct platform_device *pdev)
static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
struct ci13xxx_imx_data *data;
struct platform_device *plat_ci, *phy_pdev;
struct device_node *phy_np;
struct ci_hdrc_imx_data *data;
struct ci_hdrc_platform_data pdata = {
.name = "ci_hdrc_imx",
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_PULLUP_ON_VBUS |
CI_HDRC_DISABLE_STREAMING,
};
struct resource *res;
struct regulator *reg_vbus;
struct pinctrl *pinctrl;
int ret;
if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
......@@ -112,7 +105,7 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
return -ENOMEM;
}
......@@ -122,11 +115,6 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
return -ENOENT;
}
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl))
dev_warn(&pdev->dev, "pinctrl get/select failed, err=%ld\n",
PTR_ERR(pinctrl));
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev,
......@@ -141,37 +129,33 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
return ret;
}
phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0);
if (phy_np) {
data->phy_np = phy_np;
phy_pdev = of_find_device_by_node(phy_np);
if (phy_pdev) {
struct usb_phy *phy;
phy = pdev_to_phy(phy_pdev);
if (phy &&
try_module_get(phy_pdev->dev.driver->owner)) {
usb_phy_init(phy);
data->phy = phy;
}
data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
if (!IS_ERR(data->phy)) {
ret = usb_phy_init(data->phy);
if (ret) {
dev_err(&pdev->dev, "unable to init phy: %d\n", ret);
goto err_clk;
}
} else if (PTR_ERR(data->phy) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_clk;
}
/* we only support host now, so enable vbus here */
reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
if (!IS_ERR(reg_vbus)) {
ret = regulator_enable(reg_vbus);
data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
if (!IS_ERR(data->reg_vbus)) {
ret = regulator_enable(data->reg_vbus);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable vbus regulator, err=%d\n",
ret);
goto put_np;
goto err_clk;
}
data->reg_vbus = reg_vbus;
} else {
reg_vbus = NULL;
data->reg_vbus = NULL;
}
ci13xxx_imx_platdata.phy = data->phy;
pdata.phy = data->phy;
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
......@@ -187,11 +171,11 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
}
}
plat_ci = ci13xxx_add_device(&pdev->dev,
data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
&ci13xxx_imx_platdata);
if (IS_ERR(plat_ci)) {
ret = PTR_ERR(plat_ci);
&pdata);
if (IS_ERR(data->ci_pdev)) {
ret = PTR_ERR(data->ci_pdev);
dev_err(&pdev->dev,
"Can't register ci_hdrc platform device, err=%d\n",
ret);
......@@ -203,11 +187,10 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"usbmisc post failed, ret=%d\n", ret);
goto put_np;
goto disable_device;
}
}
data->ci_pdev = plat_ci;
platform_set_drvdata(pdev, data);
pm_runtime_no_callbacks(&pdev->dev);
......@@ -215,22 +198,22 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
return 0;
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
err:
if (reg_vbus)
regulator_disable(reg_vbus);
put_np:
if (phy_np)
of_node_put(phy_np);
if (data->reg_vbus)
regulator_disable(data->reg_vbus);
err_clk:
clk_disable_unprepare(data->clk);
return ret;
}
static int ci13xxx_imx_remove(struct platform_device *pdev)
static int ci_hdrc_imx_remove(struct platform_device *pdev)
{
struct ci13xxx_imx_data *data = platform_get_drvdata(pdev);
struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
ci13xxx_remove_device(data->ci_pdev);
ci_hdrc_remove_device(data->ci_pdev);
if (data->reg_vbus)
regulator_disable(data->reg_vbus);
......@@ -240,35 +223,31 @@ static int ci13xxx_imx_remove(struct platform_device *pdev)
module_put(data->phy->dev->driver->owner);
}
of_node_put(data->phy_np);
clk_disable_unprepare(data->clk);
platform_set_drvdata(pdev, NULL);
return 0;
}
static const struct of_device_id ci13xxx_imx_dt_ids[] = {
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx27-usb", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids);
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
static struct platform_driver ci13xxx_imx_driver = {
.probe = ci13xxx_imx_probe,
.remove = ci13xxx_imx_remove,
static struct platform_driver ci_hdrc_imx_driver = {
.probe = ci_hdrc_imx_probe,
.remove = ci_hdrc_imx_remove,
.driver = {
.name = "imx_usb",
.owner = THIS_MODULE,
.of_match_table = ci13xxx_imx_dt_ids,
.of_match_table = ci_hdrc_imx_dt_ids,
},
};
module_platform_driver(ci13xxx_imx_driver);
module_platform_driver(ci_hdrc_imx_driver);
MODULE_ALIAS("platform:imx-usb");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CI13xxx i.MX USB binding");
MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
......@@ -17,19 +17,19 @@
#define MSM_USB_BASE (ci->hw_bank.abs)
static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
{
struct device *dev = ci->gadget.dev.parent;
int val;
switch (event) {
case CI13XXX_CONTROLLER_RESET_EVENT:
dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
case CI_HDRC_CONTROLLER_RESET_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE);
break;
case CI13XXX_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
/*
* Put the transceiver in non-driving mode. Otherwise host
* may not detect soft-disconnection.
......@@ -40,32 +40,32 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
usb_phy_io_write(ci->transceiver, val, ULPI_FUNC_CTRL);
break;
default:
dev_dbg(dev, "unknown ci13xxx event\n");
dev_dbg(dev, "unknown ci_hdrc event\n");
break;
}
}
static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
.name = "ci13xxx_msm",
.flags = CI13XXX_REGS_SHARED |
CI13XXX_REQUIRE_TRANSCEIVER |
CI13XXX_PULLUP_ON_VBUS |
CI13XXX_DISABLE_STREAMING,
static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
.name = "ci_hdrc_msm",
.flags = CI_HDRC_REGS_SHARED |
CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_PULLUP_ON_VBUS |
CI_HDRC_DISABLE_STREAMING,
.notify_event = ci13xxx_msm_notify_event,
.notify_event = ci_hdrc_msm_notify_event,
};
static int ci13xxx_msm_probe(struct platform_device *pdev)
static int ci_hdrc_msm_probe(struct platform_device *pdev)
{
struct platform_device *plat_ci;
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n");
plat_ci = ci13xxx_add_device(&pdev->dev,
plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
&ci13xxx_msm_platdata);
&ci_hdrc_msm_platdata);
if (IS_ERR(plat_ci)) {
dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
return PTR_ERR(plat_ci);
}
......@@ -77,23 +77,24 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
return 0;
}
static int ci13xxx_msm_remove(struct platform_device *pdev)
static int ci_hdrc_msm_remove(struct platform_device *pdev)
{
struct platform_device *plat_ci = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
ci13xxx_remove_device(plat_ci);
ci_hdrc_remove_device(plat_ci);
return 0;
}
static struct platform_driver ci13xxx_msm_driver = {
.probe = ci13xxx_msm_probe,
.remove = ci13xxx_msm_remove,
static struct platform_driver ci_hdrc_msm_driver = {
.probe = ci_hdrc_msm_probe,
.remove = ci_hdrc_msm_remove,
.driver = { .name = "msm_hsusb", },
};
module_platform_driver(ci13xxx_msm_driver);
module_platform_driver(ci_hdrc_msm_driver);
MODULE_ALIAS("platform:msm_hsusb");
MODULE_ALIAS("platform:ci13xxx_msm");
MODULE_LICENSE("GPL v2");
/*
* ci13xxx_pci.c - MIPS USB IP core family device controller
* ci_hdrc_pci.c - MIPS USB IP core family device controller
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
......@@ -18,29 +18,29 @@
#include <linux/usb/chipidea.h>
/* driver name */
#define UDC_DRIVER_NAME "ci13xxx_pci"
#define UDC_DRIVER_NAME "ci_hdrc_pci"
/******************************************************************************
* PCI block
*****************************************************************************/
static struct ci13xxx_platform_data pci_platdata = {
static struct ci_hdrc_platform_data pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = DEF_CAPOFFSET,
};
static struct ci13xxx_platform_data langwell_pci_platdata = {
static struct ci_hdrc_platform_data langwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
};
static struct ci13xxx_platform_data penwell_pci_platdata = {
static struct ci_hdrc_platform_data penwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
.power_budget = 200,
};
/**
* ci13xxx_pci_probe: PCI probe
* ci_hdrc_pci_probe: PCI probe
* @pdev: USB device controller being probed
* @id: PCI hotplug ID connecting controller to UDC framework
*
......@@ -48,10 +48,10 @@ static struct ci13xxx_platform_data penwell_pci_platdata = {
* Allocates basic PCI resources for this USB device controller, and then
* invokes the udc_probe() method to start the UDC associated with it
*/
static int ci13xxx_pci_probe(struct pci_dev *pdev,
static int ci_hdrc_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ci13xxx_platform_data *platdata = (void *)id->driver_data;
struct ci_hdrc_platform_data *platdata = (void *)id->driver_data;
struct platform_device *plat_ci;
struct resource res[3];
int retval = 0, nres = 2;
......@@ -61,17 +61,15 @@ static int ci13xxx_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}
retval = pci_enable_device(pdev);
retval = pcim_enable_device(pdev);
if (retval)
goto done;
return retval;
if (!pdev->irq) {
dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
retval = -ENODEV;
goto disable_device;
return -ENODEV;
}
pci_set_power_state(pdev, PCI_D0);
pci_set_master(pdev);
pci_try_set_mwi(pdev);
......@@ -82,38 +80,30 @@ static int ci13xxx_pci_probe(struct pci_dev *pdev,
res[1].start = pdev->irq;
res[1].flags = IORESOURCE_IRQ;
plat_ci = ci13xxx_add_device(&pdev->dev, res, nres, platdata);
plat_ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata);
if (IS_ERR(plat_ci)) {
dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
retval = PTR_ERR(plat_ci);
goto disable_device;
dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
return PTR_ERR(plat_ci);
}
pci_set_drvdata(pdev, plat_ci);
return 0;
disable_device:
pci_disable_device(pdev);
done:
return retval;
}
/**
* ci13xxx_pci_remove: PCI remove
* ci_hdrc_pci_remove: PCI remove
* @pdev: USB Device Controller being removed
*
* Reverses the effect of ci13xxx_pci_probe(),
* Reverses the effect of ci_hdrc_pci_probe(),
* first invoking the udc_remove() and then releases
* all PCI resources allocated for this USB device controller
*/
static void ci13xxx_pci_remove(struct pci_dev *pdev)
static void ci_hdrc_pci_remove(struct pci_dev *pdev)
{
struct platform_device *plat_ci = pci_get_drvdata(pdev);
ci13xxx_remove_device(plat_ci);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
ci_hdrc_remove_device(plat_ci);
}
/**
......@@ -122,7 +112,7 @@ static void ci13xxx_pci_remove(struct pci_dev *pdev)
*
* Check "pci.h" for details
*/
static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
static DEFINE_PCI_DEVICE_TABLE(ci_hdrc_pci_id_table) = {
{
PCI_DEVICE(0x153F, 0x1004),
.driver_data = (kernel_ulong_t)&pci_platdata,
......@@ -141,18 +131,19 @@ static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
},
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
static struct pci_driver ci13xxx_pci_driver = {
static struct pci_driver ci_hdrc_pci_driver = {
.name = UDC_DRIVER_NAME,
.id_table = ci13xxx_pci_id_table,
.probe = ci13xxx_pci_probe,
.remove = ci13xxx_pci_remove,
.id_table = ci_hdrc_pci_id_table,
.probe = ci_hdrc_pci_probe,
.remove = ci_hdrc_pci_remove,
};
module_pci_driver(ci13xxx_pci_driver);
module_pci_driver(ci_hdrc_pci_driver);
MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
MODULE_LICENSE("GPL");
MODULE_VERSION("June 2008");
MODULE_ALIAS("platform:ci13xxx_pci");
......@@ -43,8 +43,7 @@
*
* TODO List
* - OTG
* - Isochronous & Interrupt Traffic
* - Handle requests which spawns into several TDs
* - Interrupt Traffic
* - GET_STATUS(device) - always reports 0
* - Gadget API (majority of optional features)
* - Suspend & Remote Wakeup
......@@ -64,6 +63,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
#include <linux/usb/of.h>
#include <linux/phy.h>
#include "ci.h"
#include "udc.h"
......@@ -116,7 +117,7 @@ static uintptr_t ci_regs_lpm[] = {
[OP_ENDPTCTRL] = 0x0ECUL,
};
static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
{
int i;
......@@ -148,7 +149,7 @@ static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
*
* This function returns an error code
*/
int hw_port_test_set(struct ci13xxx *ci, u8 mode)
int hw_port_test_set(struct ci_hdrc *ci, u8 mode)
{
const u8 TEST_MODE_MAX = 7;
......@@ -164,12 +165,12 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
*
* This function returns port test mode value
*/
u8 hw_port_test_get(struct ci13xxx *ci)
u8 hw_port_test_get(struct ci_hdrc *ci)
{
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
{
u32 reg;
......@@ -208,13 +209,52 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
return 0;
}
static void hw_phymode_configure(struct ci_hdrc *ci)
{
u32 portsc, lpm, sts;
switch (ci->platdata->phy_mode) {
case USBPHY_INTERFACE_MODE_UTMI:
portsc = PORTSC_PTS(PTS_UTMI);
lpm = DEVLC_PTS(PTS_UTMI);
break;
case USBPHY_INTERFACE_MODE_UTMIW:
portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW;
lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW;
break;
case USBPHY_INTERFACE_MODE_ULPI:
portsc = PORTSC_PTS(PTS_ULPI);
lpm = DEVLC_PTS(PTS_ULPI);
break;
case USBPHY_INTERFACE_MODE_SERIAL:
portsc = PORTSC_PTS(PTS_SERIAL);
lpm = DEVLC_PTS(PTS_SERIAL);
sts = 1;
break;
case USBPHY_INTERFACE_MODE_HSIC:
portsc = PORTSC_PTS(PTS_HSIC);
lpm = DEVLC_PTS(PTS_HSIC);
break;
default:
return;
}
if (ci->hw_bank.lpm) {
hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm);
hw_write(ci, OP_DEVLC, DEVLC_STS, sts);
} else {
hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc);
hw_write(ci, OP_PORTSC, PORTSC_STS, sts);
}
}
/**
* hw_device_reset: resets chip (execute without interruption)
* @ci: the controller
*
* This function returns an error code
*/
int hw_device_reset(struct ci13xxx *ci, u32 mode)
int hw_device_reset(struct ci_hdrc *ci, u32 mode)
{
/* should flush & stop before reset */
hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
......@@ -224,12 +264,13 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
while (hw_read(ci, OP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
hw_phymode_configure(ci);
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
CI13XXX_CONTROLLER_RESET_EVENT);
CI_HDRC_CONTROLLER_RESET_EVENT);
if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
/* USBMODE should be configured step by step */
......@@ -251,7 +292,7 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
* ci_otg_role - pick role based on ID pin state
* @ci: the controller
*/
static enum ci_role ci_otg_role(struct ci13xxx *ci)
static enum ci_role ci_otg_role(struct ci_hdrc *ci)
{
u32 sts = hw_read(ci, OP_OTGSC, ~0);
enum ci_role role = sts & OTGSC_ID
......@@ -267,7 +308,7 @@ static enum ci_role ci_otg_role(struct ci13xxx *ci)
*/
static void ci_role_work(struct work_struct *work)
{
struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
enum ci_role role = ci_otg_role(ci);
if (role != ci->role) {
......@@ -283,7 +324,7 @@ static void ci_role_work(struct work_struct *work)
static irqreturn_t ci_irq(int irq, void *data)
{
struct ci13xxx *ci = data;
struct ci_hdrc *ci = data;
irqreturn_t ret = IRQ_NONE;
u32 otgsc = 0;
......@@ -305,9 +346,9 @@ static irqreturn_t ci_irq(int irq, void *data)
static DEFINE_IDA(ci_ida);
struct platform_device *ci13xxx_add_device(struct device *dev,
struct platform_device *ci_hdrc_add_device(struct device *dev,
struct resource *res, int nres,
struct ci13xxx_platform_data *platdata)
struct ci_hdrc_platform_data *platdata)
{
struct platform_device *pdev;
int id, ret;
......@@ -347,29 +388,33 @@ struct platform_device *ci13xxx_add_device(struct device *dev,
ida_simple_remove(&ci_ida, id);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(ci13xxx_add_device);
EXPORT_SYMBOL_GPL(ci_hdrc_add_device);
void ci13xxx_remove_device(struct platform_device *pdev)
void ci_hdrc_remove_device(struct platform_device *pdev)
{
int id = pdev->id;
platform_device_unregister(pdev);
ida_simple_remove(&ci_ida, id);
}
EXPORT_SYMBOL_GPL(ci13xxx_remove_device);
EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
static int ci_hdrc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ci13xxx *ci;
struct ci_hdrc *ci;
struct resource *res;
void __iomem *base;
int ret;
enum usb_dr_mode dr_mode;
if (!dev->platform_data) {
dev_err(dev, "platform data missing\n");
return -ENODEV;
}
if (!dev->of_node && dev->parent)
dev->of_node = dev->parent->of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
......@@ -409,14 +454,28 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
if (!ci->platdata->phy_mode)
ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
if (!ci->platdata->dr_mode)
ci->platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
if (ci->platdata->dr_mode == USB_DR_MODE_UNKNOWN)
ci->platdata->dr_mode = USB_DR_MODE_OTG;
dr_mode = ci->platdata->dr_mode;
/* initialize role(s) before the interrupt is requested */
ret = ci_hdrc_host_init(ci);
if (ret)
dev_info(dev, "doesn't support host\n");
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
ret = ci_hdrc_host_init(ci);
if (ret)
dev_info(dev, "doesn't support host\n");
}
ret = ci_hdrc_gadget_init(ci);
if (ret)
dev_info(dev, "doesn't support gadget\n");
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
ret = ci_hdrc_gadget_init(ci);
if (ret)
dev_info(dev, "doesn't support gadget\n");
}
if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
dev_err(dev, "no supported roles\n");
......@@ -467,7 +526,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
static int ci_hdrc_remove(struct platform_device *pdev)
{
struct ci13xxx *ci = platform_get_drvdata(pdev);
struct ci_hdrc *ci = platform_get_drvdata(pdev);
dbg_remove_files(ci);
flush_workqueue(ci->wq);
......
......@@ -18,7 +18,7 @@
*/
static int ci_device_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
struct usb_gadget *gadget = &ci->gadget;
seq_printf(s, "speed = %d\n", gadget->speed);
......@@ -58,7 +58,7 @@ static const struct file_operations ci_device_fops = {
*/
static int ci_port_test_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
unsigned long flags;
unsigned mode;
......@@ -78,7 +78,7 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
unsigned long flags;
unsigned mode;
char buf[32];
......@@ -115,7 +115,7 @@ static const struct file_operations ci_port_test_fops = {
*/
static int ci_qheads_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
unsigned long flags;
unsigned i, j;
......@@ -126,15 +126,15 @@ static int ci_qheads_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max/2; i++) {
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
struct ci13xxx_ep *mEpTx =
&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
struct ci_hw_ep *hweptx =
&ci->ci_hw_ep[i + ci->hw_ep_max/2];
seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
seq_printf(s, " %04X: %08X %08X\n", j,
*((u32 *)mEpRx->qh.ptr + j),
*((u32 *)mEpTx->qh.ptr + j));
*((u32 *)hweprx->qh.ptr + j),
*((u32 *)hweptx->qh.ptr + j));
}
spin_unlock_irqrestore(&ci->lock, flags);
......@@ -158,11 +158,12 @@ static const struct file_operations ci_qheads_fops = {
*/
static int ci_requests_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
unsigned long flags;
struct list_head *ptr = NULL;
struct ci13xxx_req *req = NULL;
unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
struct ci_hw_req *req = NULL;
struct td_node *node, *tmpnode;
unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
if (ci->role != CI_ROLE_GADGET) {
seq_printf(s, "not in gadget mode\n");
......@@ -171,16 +172,20 @@ static int ci_requests_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max; i++)
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
seq_printf(s, "EP=%02i: TD=%08X %s\n",
i % (ci->hw_ep_max / 2), (u32)req->dma,
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
for (j = 0; j < qsize; j++)
seq_printf(s, " %04X: %08X\n", j,
*((u32 *)req->ptr + j));
list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
req = list_entry(ptr, struct ci_hw_req, queue);
list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
seq_printf(s, "EP=%02i: TD=%08X %s\n",
i % (ci->hw_ep_max / 2),
(u32)node->dma,
((i < ci->hw_ep_max/2) ?
"RX" : "TX"));
for (j = 0; j < qsize; j++)
seq_printf(s, " %04X: %08X\n", j,
*((u32 *)node->ptr + j));
}
}
spin_unlock_irqrestore(&ci->lock, flags);
......@@ -201,7 +206,7 @@ static const struct file_operations ci_requests_fops = {
static int ci_role_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
seq_printf(s, "%s\n", ci_role(ci)->name);
......@@ -212,7 +217,7 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct ci13xxx *ci = s->private;
struct ci_hdrc *ci = s->private;
enum ci_role role;
char buf[8];
int ret;
......@@ -254,7 +259,7 @@ static const struct file_operations ci_role_fops = {
*
* This function returns an error code
*/
int dbg_create_files(struct ci13xxx *ci)
int dbg_create_files(struct ci_hdrc *ci)
{
struct dentry *dent;
......@@ -295,7 +300,7 @@ int dbg_create_files(struct ci13xxx *ci)
* dbg_remove_files: destroys the attribute interface
* @ci: device
*/
void dbg_remove_files(struct ci13xxx *ci)
void dbg_remove_files(struct ci_hdrc *ci)
{
debugfs_remove_recursive(ci->debugfs);
}
......@@ -14,15 +14,15 @@
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
int dbg_create_files(struct ci13xxx *ci);
void dbg_remove_files(struct ci13xxx *ci);
int dbg_create_files(struct ci_hdrc *ci);
void dbg_remove_files(struct ci_hdrc *ci);
#else
static inline int dbg_create_files(struct ci13xxx *ci)
static inline int dbg_create_files(struct ci_hdrc *ci)
{
return 0;
}
static inline void dbg_remove_files(struct ci13xxx *ci)
static inline void dbg_remove_files(struct ci_hdrc *ci)
{
}
#endif
......
......@@ -33,12 +33,12 @@
static struct hc_driver __read_mostly ci_ehci_hc_driver;
static irqreturn_t host_irq(struct ci13xxx *ci)
static irqreturn_t host_irq(struct ci_hdrc *ci)
{
return usb_hcd_irq(ci->irq, ci->hcd);
}
static int host_start(struct ci13xxx *ci)
static int host_start(struct ci_hdrc *ci)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
......@@ -70,13 +70,13 @@ static int host_start(struct ci13xxx *ci)
else
ci->hcd = hcd;
if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
return ret;
}
static void host_stop(struct ci13xxx *ci)
static void host_stop(struct ci_hdrc *ci)
{
struct usb_hcd *hcd = ci->hcd;
......@@ -84,7 +84,7 @@ static void host_stop(struct ci13xxx *ci)
usb_put_hcd(hcd);
}
int ci_hdrc_host_init(struct ci13xxx *ci)
int ci_hdrc_host_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
......
......@@ -3,11 +3,11 @@
#ifdef CONFIG_USB_CHIPIDEA_HOST
int ci_hdrc_host_init(struct ci13xxx *ci);
int ci_hdrc_host_init(struct ci_hdrc *ci);
#else
static inline int ci_hdrc_host_init(struct ci13xxx *ci)
static inline int ci_hdrc_host_init(struct ci_hdrc *ci)
{
return -ENXIO;
}
......
此差异已折叠。
......@@ -20,7 +20,7 @@
#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
/* DMA layout of transfer descriptors */
struct ci13xxx_td {
struct ci_hw_td {
/* 0 */
u32 next;
#define TD_TERMINATE BIT(0)
......@@ -43,24 +43,31 @@ struct ci13xxx_td {
} __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */
struct ci13xxx_qh {
struct ci_hw_qh {
/* 0 */
u32 cap;
#define QH_IOS BIT(15)
#define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30)
#define QH_ISO_MULT(x) ((x >> 11) & 0x03)
/* 1 */
u32 curr;
/* 2 - 8 */
struct ci13xxx_td td;
struct ci_hw_td td;
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
} __attribute__ ((packed, aligned(4)));
struct td_node {
struct list_head td;
dma_addr_t dma;
struct ci_hw_td *ptr;
};
/**
* struct ci13xxx_req - usb request representation
* struct ci_hw_req - usb request representation
* @req: request structure for gadget drivers
* @queue: link to QH list
* @ptr: transfer descriptor for this request
......@@ -68,22 +75,19 @@ struct ci13xxx_qh {
* @zptr: transfer descriptor for the zero packet
* @zdma: dma address of the zero packet's transfer descriptor
*/
struct ci13xxx_req {
struct ci_hw_req {
struct usb_request req;
struct list_head queue;
struct ci13xxx_td *ptr;
dma_addr_t dma;
struct ci13xxx_td *zptr;
dma_addr_t zdma;
struct list_head tds;
};
#ifdef CONFIG_USB_CHIPIDEA_UDC
int ci_hdrc_gadget_init(struct ci13xxx *ci);
int ci_hdrc_gadget_init(struct ci_hdrc *ci);
#else
static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
static inline int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
return -ENXIO;
}
......
......@@ -16,7 +16,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include "ci13xxx_imx.h"
#include "ci_hdrc_imx.h"
#define USB_DEV_MAX 4
......@@ -175,6 +175,7 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
static int usbmisc_imx_probe(struct platform_device *pdev)
{
......@@ -243,17 +244,7 @@ static struct platform_driver usbmisc_imx_driver = {
},
};
int usbmisc_imx_drv_init(void)
{
return platform_driver_register(&usbmisc_imx_driver);
}
subsys_initcall(usbmisc_imx_drv_init);
void usbmisc_imx_drv_exit(void)
{
platform_driver_unregister(&usbmisc_imx_driver);
}
module_exit(usbmisc_imx_drv_exit);
module_platform_driver(usbmisc_imx_driver);
MODULE_ALIAS("platform:usbmisc-imx");
MODULE_LICENSE("GPL v2");
......
......@@ -216,38 +216,6 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
return rc;
}
static int acm_write_start(struct acm *acm, int wbn)
{
unsigned long flags;
struct acm_wb *wb = &acm->wb[wbn];
int rc;
spin_lock_irqsave(&acm->write_lock, flags);
if (!acm->dev) {
wb->use = 0;
spin_unlock_irqrestore(&acm->write_lock, flags);
return -ENODEV;
}
dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
acm->susp_count);
usb_autopm_get_interface_async(acm->control);
if (acm->susp_count) {
if (!acm->delayed_wb)
acm->delayed_wb = wb;
else
usb_autopm_put_interface_async(acm->control);
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0; /* A white lie */
}
usb_mark_last_busy(acm->dev);
rc = acm_start_wb(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags);
return rc;
}
/*
* attributes exported through sysfs
*/
......@@ -653,13 +621,31 @@ static int acm_tty_write(struct tty_struct *tty,
}
wb = &acm->wb[wbn];
if (!acm->dev) {
wb->use = 0;
spin_unlock_irqrestore(&acm->write_lock, flags);
return -ENODEV;
}
count = (count > acm->writesize) ? acm->writesize : count;
dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
memcpy(wb->buf, buf, count);
wb->len = count;
usb_autopm_get_interface_async(acm->control);
if (acm->susp_count) {
if (!acm->delayed_wb)
acm->delayed_wb = wb;
else
usb_autopm_put_interface_async(acm->control);
spin_unlock_irqrestore(&acm->write_lock, flags);
return count; /* A white lie */
}
usb_mark_last_busy(acm->dev);
stat = acm_start_wb(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags);
stat = acm_write_start(acm, wbn);
if (stat < 0)
return stat;
return count;
......
......@@ -31,6 +31,8 @@
#include <linux/usb/tmc.h>
#define RIGOL 1
#define USBTMC_HEADER_SIZE 12
#define USBTMC_MINOR_BASE 176
/*
......@@ -84,6 +86,8 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read; /* needed for abort */
u8 rigol_quirk;
/* attributes from the USB TMC spec for this device */
u8 TermChar;
bool TermCharEnabled;
......@@ -97,6 +101,16 @@ struct usbtmc_device_data {
};
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
struct usbtmc_ID_rigol_quirk {
__u16 idVendor;
__u16 idProduct;
};
static const struct usbtmc_ID_rigol_quirk usbtmc_id_quirk[] = {
{ 0x1ab1, 0x0588 },
{ 0, 0 }
};
/* Forward declarations */
static struct usb_driver usbtmc_driver;
......@@ -361,6 +375,59 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
return rv;
}
/*
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint.
* @transfer_size: number of bytes to request from the device.
*
* See the USBTMC specification, Table 4.
*
* Also updates bTag_last_write.
*/
static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size)
{
int retval;
u8 buffer[USBTMC_HEADER_SIZE];
int actual;
/* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message
* Refer to class specs for details
*/
buffer[0] = 2;
buffer[1] = data->bTag;
buffer[2] = ~(data->bTag);
buffer[3] = 0; /* Reserved */
buffer[4] = (transfer_size) & 255;
buffer[5] = ((transfer_size) >> 8) & 255;
buffer[6] = ((transfer_size) >> 16) & 255;
buffer[7] = ((transfer_size) >> 24) & 255;
buffer[8] = data->TermCharEnabled * 2;
/* Use term character? */
buffer[9] = data->TermChar;
buffer[10] = 0; /* Reserved */
buffer[11] = 0; /* Reserved */
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE, &actual, USBTMC_TIMEOUT);
/* Store bTag (in case we need to abort) */
data->bTag_last_write = data->bTag;
/* Increment bTag -- and increment again if zero */
data->bTag++;
if (!data->bTag)
(data->bTag)++;
if (retval < 0) {
dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);
return retval;
}
return 0;
}
static ssize_t usbtmc_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
......@@ -388,51 +455,39 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
goto exit;
}
remaining = count;
done = 0;
if (data->rigol_quirk) {
dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
while (remaining > 0) {
if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3)
this_part = USBTMC_SIZE_IOBUFFER - 12 - 3;
else
this_part = remaining;
retval = send_request_dev_dep_msg_in(data, count);
/* Setup IO buffer for DEV_DEP_MSG_IN message
* Refer to class specs for details
*/
buffer[0] = 2;
buffer[1] = data->bTag;
buffer[2] = ~(data->bTag);
buffer[3] = 0; /* Reserved */
buffer[4] = (this_part) & 255;
buffer[5] = ((this_part) >> 8) & 255;
buffer[6] = ((this_part) >> 16) & 255;
buffer[7] = ((this_part) >> 24) & 255;
buffer[8] = data->TermCharEnabled * 2;
/* Use term character? */
buffer[9] = data->TermChar;
buffer[10] = 0; /* Reserved */
buffer[11] = 0; /* Reserved */
if (retval < 0) {
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
}
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, 12, &actual, USBTMC_TIMEOUT);
/* Loop until we have fetched everything we requested */
remaining = count;
this_part = remaining;
done = 0;
/* Store bTag (in case we need to abort) */
data->bTag_last_write = data->bTag;
while (remaining > 0) {
if (!(data->rigol_quirk)) {
dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
/* Increment bTag -- and increment again if zero */
data->bTag++;
if (!data->bTag)
(data->bTag)++;
if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3;
else
this_part = remaining;
if (retval < 0) {
retval = send_request_dev_dep_msg_in(data, this_part);
if (retval < 0) {
dev_err(dev, "usb_bulk_msg returned %d\n", retval);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
}
/* Send bulk URB */
......@@ -442,51 +497,109 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
buffer, USBTMC_SIZE_IOBUFFER, &actual,
USBTMC_TIMEOUT);
dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
/* Store bTag (in case we need to abort) */
data->bTag_last_read = data->bTag;
if (retval < 0) {
dev_err(dev, "Unable to read data, error %d\n", retval);
dev_dbg(dev, "Unable to read data, error %d\n", retval);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* How many characters did the instrument send? */
n_characters = buffer[4] +
(buffer[5] << 8) +
(buffer[6] << 16) +
(buffer[7] << 24);
/* Parse header in first packet */
if ((done == 0) || (!(data->rigol_quirk))) {
/* Sanity checks for the header */
if (actual < USBTMC_HEADER_SIZE) {
dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Ensure the instrument doesn't lie about it */
if(n_characters > actual - 12) {
dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12);
n_characters = actual - 12;
}
if (buffer[0] != 2) {
dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Ensure the instrument doesn't send more back than requested */
if(n_characters > this_part) {
dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
n_characters = this_part;
}
if (buffer[1] != data->bTag_last_write) {
dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Bound amount of data received by amount of data requested */
if (n_characters > this_part)
n_characters = this_part;
/* How many characters did the instrument send? */
n_characters = buffer[4] +
(buffer[5] << 8) +
(buffer[6] << 16) +
(buffer[7] << 24);
/* Copy buffer to user space */
if (copy_to_user(buf + done, &buffer[12], n_characters)) {
/* There must have been an addressing problem */
retval = -EFAULT;
goto exit;
if (n_characters > this_part) {
dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
/* Remove the USBTMC header */
actual -= USBTMC_HEADER_SIZE;
/* Check if the message is smaller than requested */
if (data->rigol_quirk) {
if (remaining > n_characters)
remaining = n_characters;
/* Remove padding if it exists */
if (actual > remaining)
actual = remaining;
}
else {
if (this_part > n_characters)
this_part = n_characters;
/* Remove padding if it exists */
if (actual > this_part)
actual = this_part;
}
dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]);
remaining -= actual;
/* Terminate if end-of-message bit received from device */
if ((buffer[8] & 0x01) && (actual >= n_characters))
remaining = 0;
dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
/* Copy buffer to user space */
if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) {
/* There must have been an addressing problem */
retval = -EFAULT;
goto exit;
}
done += actual;
}
else {
if (actual > remaining)
actual = remaining;
remaining -= actual;
dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer);
done += n_characters;
/* Terminate if end-of-message bit received from device */
if ((buffer[8] & 0x01) && (actual >= n_characters + 12))
remaining = 0;
else
remaining -= n_characters;
/* Copy buffer to user space */
if (copy_to_user(buf + done, buffer, actual)) {
/* There must have been an addressing problem */
retval = -EFAULT;
goto exit;
}
done += actual;
}
}
/* Update file position value */
......@@ -527,8 +640,8 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
done = 0;
while (remaining > 0) {
if (remaining > USBTMC_SIZE_IOBUFFER - 12) {
this_part = USBTMC_SIZE_IOBUFFER - 12;
if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
buffer[8] = 0;
} else {
this_part = remaining;
......@@ -549,13 +662,13 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
buffer[10] = 0; /* Reserved */
buffer[11] = 0; /* Reserved */
if (copy_from_user(&buffer[12], buf + done, this_part)) {
if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf + done, this_part)) {
retval = -EFAULT;
goto exit;
}
n_bytes = roundup(12 + this_part, 4);
memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part));
n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - (USBTMC_HEADER_SIZE + this_part));
do {
retval = usb_bulk_msg(data->usb_dev,
......@@ -1003,6 +1116,20 @@ static int usbtmc_probe(struct usb_interface *intf,
mutex_init(&data->io_mutex);
data->zombie = 0;
/* Determine if it is a Rigol or not */
data->rigol_quirk = 0;
dev_dbg(&intf->dev, "Trying to find if device Vendor 0x%04X Product 0x%04X has the RIGOL quirk\n",
data->usb_dev->descriptor.idVendor,
data->usb_dev->descriptor.idProduct);
for(n = 0; usbtmc_id_quirk[n].idVendor > 0; n++) {
if ((usbtmc_id_quirk[n].idVendor == data->usb_dev->descriptor.idVendor) &&
(usbtmc_id_quirk[n].idProduct == data->usb_dev->descriptor.idProduct)) {
dev_dbg(&intf->dev, "Setting this device as having the RIGOL quirk\n");
data->rigol_quirk = 1;
break;
}
}
/* Initialize USBTMC bTag and other fields */
data->bTag = 1;
data->TermCharEnabled = 0;
......
......@@ -49,14 +49,14 @@
#include <linux/security.h>
#include <linux/user_namespace.h>
#include <linux/scatterlist.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
#include "usb.h"
#define USB_MAXBUS 64
#define USB_DEVICE_MAX USB_MAXBUS * 128
#define USB_DEVICE_MAX (USB_MAXBUS * 128)
#define USB_SG_SIZE 16384 /* split-size for large txs */
/* Mutual exclusion for removal, open, and release */
......@@ -1804,7 +1804,8 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* alloc buffer */
if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
buf = kmalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
if (copy_from_user(buf, ctl->data, size)) {
......
......@@ -94,7 +94,7 @@ static int init_usb_class(void)
kref_init(&usb_class->kref);
usb_class->class = class_create(THIS_MODULE, "usbmisc");
if (IS_ERR(usb_class->class)) {
result = IS_ERR(usb_class->class);
result = PTR_ERR(usb_class->class);
printk(KERN_ERR "class_create failed for usb devices\n");
kfree(usb_class);
usb_class = NULL;
......
......@@ -149,6 +149,27 @@ static const u8 usb3_rh_dev_descriptor[18] = {
0x01 /* __u8 bNumConfigurations; */
};
/* usb 2.5 (wireless USB 1.0) root hub device descriptor */
static const u8 usb25_rh_dev_descriptor[18] = {
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x50, 0x02, /* __le16 bcdUSB; v2.5 */
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
0xFF, /* __u8 bMaxPacketSize0; always 0xFF (WUSB Spec 7.4.1). */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
/* usb 2.0 root hub device descriptor */
static const u8 usb2_rh_dev_descriptor [18] = {
0x12, /* __u8 bLength; */
......@@ -527,6 +548,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case HCD_USB3:
bufp = usb3_rh_dev_descriptor;
break;
case HCD_USB25:
bufp = usb25_rh_dev_descriptor;
break;
case HCD_USB2:
bufp = usb2_rh_dev_descriptor;
break;
......@@ -546,6 +570,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
bufp = ss_rh_config_descriptor;
len = sizeof ss_rh_config_descriptor;
break;
case HCD_USB25:
case HCD_USB2:
bufp = hs_rh_config_descriptor;
len = sizeof hs_rh_config_descriptor;
......@@ -2511,6 +2536,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
case HCD_USB2:
rhdev->speed = USB_SPEED_HIGH;
break;
case HCD_USB25:
rhdev->speed = USB_SPEED_WIRELESS;
break;
case HCD_USB3:
rhdev->speed = USB_SPEED_SUPER;
break;
......
......@@ -718,18 +718,18 @@ static void hub_tt_work(struct work_struct *work)
/**
* usb_hub_set_port_power - control hub port's power state
* @hdev: target hub
* @hdev: USB device belonging to the usb hub
* @hub: target hub
* @port1: port index
* @set: expected status
*
* call this function to control port's power via setting or
* clearing the port's PORT_POWER feature.
*/
int usb_hub_set_port_power(struct usb_device *hdev, int port1,
bool set)
int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
int port1, bool set)
{
int ret;
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
struct usb_port *port_dev = hub->ports[port1 - 1];
if (set)
......@@ -1769,15 +1769,17 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
static int find_port_owner(struct usb_device *hdev, unsigned port1,
struct dev_state ***ppowner)
{
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
if (hdev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
if (port1 == 0 || port1 > hdev->maxchild)
return -EINVAL;
/* This assumes that devices not managed by the hub driver
/* Devices not managed by the hub driver
* will always have maxchild equal to 0.
*/
*ppowner = &(usb_hub_to_struct_hub(hdev)->ports[port1 - 1]->port_owner);
*ppowner = &(hub->ports[port1 - 1]->port_owner);
return 0;
}
......@@ -5323,7 +5325,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
{
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
hub->ports[port1 - 1]->connect_type = type;
if (hub)
hub->ports[port1 - 1]->connect_type = type;
}
/**
......@@ -5339,6 +5342,9 @@ usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
{
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
if (!hub)
return USB_PORT_CONNECT_TYPE_UNKNOWN;
return hub->ports[port1 - 1]->connect_type;
}
......@@ -5397,6 +5403,9 @@ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
{
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
if (!hub)
return NULL;
return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
}
#endif
......@@ -100,7 +100,7 @@ extern int usb_hub_create_port_device(struct usb_hub *hub,
int port1);
extern void usb_hub_remove_port_device(struct usb_hub *hub,
int port1);
extern int usb_hub_set_port_power(struct usb_device *hdev,
extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
int port1, bool set);
extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
extern int hub_port_debounce(struct usb_hub *hub, int port1,
......
......@@ -252,7 +252,7 @@ static void sg_clean(struct usb_sg_request *io)
{
if (io->urbs) {
while (io->entries--)
usb_free_urb(io->urbs [io->entries]);
usb_free_urb(io->urbs[io->entries]);
kfree(io->urbs);
io->urbs = NULL;
}
......@@ -300,10 +300,10 @@ static void sg_complete(struct urb *urb)
*/
spin_unlock(&io->lock);
for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs [i] || !io->urbs [i]->dev)
if (!io->urbs[i] || !io->urbs[i]->dev)
continue;
if (found) {
retval = usb_unlink_urb(io->urbs [i]);
retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS &&
retval != -ENODEV &&
retval != -EBUSY &&
......@@ -311,7 +311,7 @@ static void sg_complete(struct urb *urb)
dev_err(&io->dev->dev,
"%s, unlink --> %d\n",
__func__, retval);
} else if (urb == io->urbs [i])
} else if (urb == io->urbs[i])
found = 1;
}
spin_lock(&io->lock);
......@@ -379,7 +379,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
}
/* initialize all the urbs we'll use */
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
io->urbs = kmalloc(io->entries * sizeof(*io->urbs), mem_flags);
if (!io->urbs)
goto nomem;
......@@ -511,7 +511,7 @@ void usb_sg_wait(struct usb_sg_request *io)
int retval;
io->urbs[i]->dev = io->dev;
retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC);
retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
/* after we submit, let completions or cancelations fire;
* we handshake using io->status.
......@@ -586,9 +586,9 @@ void usb_sg_cancel(struct usb_sg_request *io)
for (i = 0; i < io->entries; i++) {
int retval;
if (!io->urbs [i]->dev)
if (!io->urbs[i]->dev)
continue;
retval = usb_unlink_urb(io->urbs [i]);
retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS
&& retval != -ENODEV
&& retval != -EBUSY
......
......@@ -86,7 +86,7 @@ static int usb_port_runtime_resume(struct device *dev)
usb_autopm_get_interface(intf);
set_bit(port1, hub->busy_bits);
retval = usb_hub_set_port_power(hdev, port1, true);
retval = usb_hub_set_port_power(hdev, hub, port1, true);
if (port_dev->child && !retval) {
/*
* Wait for usb hub port to be reconnected in order to make
......@@ -128,7 +128,7 @@ static int usb_port_runtime_suspend(struct device *dev)
usb_autopm_get_interface(intf);
set_bit(port1, hub->busy_bits);
retval = usb_hub_set_port_power(hdev, port1, false);
retval = usb_hub_set_port_power(hdev, hub, port1, false);
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
clear_bit(port1, hub->busy_bits);
......
......@@ -497,8 +497,62 @@ set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
set_usb2_hardware_lpm);
static ssize_t
show_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->l1_params.timeout);
}
static ssize_t
set_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
u16 timeout;
if (kstrtou16(buf, 0, &timeout))
return -EINVAL;
udev->l1_params.timeout = timeout;
return count;
}
static DEVICE_ATTR(usb2_lpm_l1_timeout, S_IRUGO | S_IWUSR,
show_usb2_lpm_l1_timeout, set_usb2_lpm_l1_timeout);
static ssize_t
show_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->l1_params.besl);
}
static ssize_t
set_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
u8 besl;
if (kstrtou8(buf, 0, &besl) || besl > 15)
return -EINVAL;
udev->l1_params.besl = besl;
return count;
}
static DEVICE_ATTR(usb2_lpm_besl, S_IRUGO | S_IWUSR,
show_usb2_lpm_besl, set_usb2_lpm_besl);
static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_hardware_lpm.attr,
&dev_attr_usb2_lpm_l1_timeout.attr,
&dev_attr_usb2_lpm_besl.attr,
NULL,
};
static struct attribute_group usb2_hardware_lpm_attr_group = {
......
......@@ -209,6 +209,39 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
}
EXPORT_SYMBOL_GPL(usb_find_interface);
struct each_dev_arg {
void *data;
int (*fn)(struct usb_device *, void *);
};
static int __each_dev(struct device *dev, void *data)
{
struct each_dev_arg *arg = (struct each_dev_arg *)data;
/* There are struct usb_interface on the same bus, filter them out */
if (!is_usb_device(dev))
return 0;
return arg->fn(container_of(dev, struct usb_device, dev), arg->data);
}
/**
* usb_for_each_dev - iterate over all USB devices in the system
* @data: data pointer that will be handed to the callback function
* @fn: callback function to be called for each USB device
*
* Iterate over all USB devices and call @fn for each, passing it @data. If it
* returns anything other than 0, we break the iteration prematurely and return
* that value.
*/
int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *))
{
struct each_dev_arg arg = {data, fn};
return bus_for_each_dev(&usb_bus_type, NULL, &arg, __each_dev);
}
EXPORT_SYMBOL_GPL(usb_for_each_dev);
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
......
此差异已折叠。
......@@ -133,7 +133,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
return -ENODEV;
}
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);
ret = dwc3_pci_register_phys(glue);
......
此差异已折叠。
......@@ -33,6 +33,7 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
# USB Functions
......@@ -45,6 +46,21 @@ usb_f_serial-y := f_serial.o
obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
usb_f_obex-y := f_obex.o
obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
obj-$(CONFIG_USB_U_ETHER) += u_ether.o
u_rndis-y := rndis.o
obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o
usb_f_ncm-y := f_ncm.o
obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o
usb_f_ecm-y := f_ecm.o
obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o
usb_f_phonet-y := f_phonet.o
obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o
usb_f_eem-y := f_eem.o
obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o
usb_f_ecm_subset-y := f_subset.o
obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o
usb_f_rndis-y := f_rndis.o
obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o
#
# USB gadget drivers
......
......@@ -15,6 +15,7 @@
#include "u_ether.h"
#include "u_serial.h"
#include "u_ecm.h"
#define DRIVER_DESC "CDC Composite Gadget"
......@@ -32,18 +33,9 @@
#define CDC_VENDOR_NUM 0x0525 /* NetChip */
#define CDC_PRODUCT_NUM 0xa4aa /* CDC Composite: ECM + ACM */
/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();
/*
* Kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
* separate compilation ... ensuring init/exit sections work to shrink
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "f_ecm.c"
#include "u_ether.c"
USB_ETHERNET_MODULE_PARAMETERS();
/*-------------------------------------------------------------------------*/
......@@ -102,12 +94,13 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL,
};
static u8 hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/
static struct usb_function *f_acm;
static struct usb_function_instance *fi_serial;
static struct usb_function *f_ecm;
static struct usb_function_instance *fi_ecm;
/*
* We _always_ have both CDC ECM and CDC ACM functions.
*/
......@@ -120,13 +113,27 @@ static int __init cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
status = ecm_bind_config(c, hostaddr, the_dev);
if (status < 0)
return status;
fi_ecm = usb_get_function_instance("ecm");
if (IS_ERR(fi_ecm)) {
status = PTR_ERR(fi_ecm);
goto err_func_ecm;
}
f_ecm = usb_get_function(fi_ecm);
if (IS_ERR(f_ecm)) {
status = PTR_ERR(f_ecm);
goto err_get_ecm;
}
status = usb_add_function(c, f_ecm);
if (status)
goto err_add_ecm;
fi_serial = usb_get_function_instance("acm");
if (IS_ERR(fi_serial))
return PTR_ERR(fi_serial);
if (IS_ERR(fi_serial)) {
status = PTR_ERR(fi_serial);
goto err_get_acm;
}
f_acm = usb_get_function(fi_serial);
if (IS_ERR(f_acm)) {
......@@ -136,12 +143,21 @@ static int __init cdc_do_config(struct usb_configuration *c)
status = usb_add_function(c, f_acm);
if (status)
goto err_conf;
goto err_add_acm;
return 0;
err_conf:
err_add_acm:
usb_put_function(f_acm);
err_func_acm:
usb_put_function_instance(fi_serial);
err_get_acm:
usb_remove_function(c, f_ecm);
err_add_ecm:
usb_put_function(f_ecm);
err_get_ecm:
usb_put_function_instance(fi_ecm);
err_func_ecm:
return status;
}
......@@ -157,6 +173,7 @@ static struct usb_configuration cdc_config_driver = {
static int __init cdc_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct f_ecm_opts *ecm_opts;
int status;
if (!can_support_ecm(cdev->gadget)) {
......@@ -165,10 +182,23 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return -EINVAL;
}
/* set up network link layer */
the_dev = gether_setup(cdev->gadget, hostaddr);
if (IS_ERR(the_dev))
return PTR_ERR(the_dev);
fi_ecm = usb_get_function_instance("ecm");
if (IS_ERR(fi_ecm))
return PTR_ERR(fi_ecm);
ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
gether_set_qmult(ecm_opts->net, qmult);
if (!gether_set_host_addr(ecm_opts->net, host_addr))
pr_info("using host ethernet address: %s", host_addr);
if (!gether_set_dev_addr(ecm_opts->net, dev_addr))
pr_info("using self ethernet address: %s", dev_addr);
fi_serial = usb_get_function_instance("acm");
if (IS_ERR(fi_serial)) {
status = PTR_ERR(fi_serial);
goto fail;
}
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
......@@ -192,7 +222,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return 0;
fail1:
gether_cleanup(the_dev);
usb_put_function_instance(fi_serial);
fail:
usb_put_function_instance(fi_ecm);
return status;
}
......@@ -200,7 +232,10 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
{
usb_put_function(f_acm);
usb_put_function_instance(fi_serial);
gether_cleanup(the_dev);
if (!IS_ERR_OR_NULL(f_ecm))
usb_put_function(f_ecm);
if (!IS_ERR_OR_NULL(fi_ecm))
usb_put_function_instance(fi_ecm);
return 0;
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -413,6 +413,7 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Caller must hold fsg->lock */
static void wakeup_thread(struct fsg_common *common)
{
smp_wmb(); /* ensure the write of bh->state is complete */
/* Tell the main thread that something has happened */
common->thread_wakeup_needed = 1;
if (common->thread_task)
......@@ -632,6 +633,7 @@ static int sleep_thread(struct fsg_common *common)
}
__set_current_state(TASK_RUNNING);
common->thread_wakeup_needed = 0;
smp_rmb(); /* ensure the latest bh->state is visible */
return rc;
}
......@@ -2745,8 +2747,8 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
"%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
/* Assume product name dependent on the first LUN */
cfg->product_name ?: (common->luns->cdrom
? "File-Stor Gadget"
: "File-CD Gadget"),
? "File-CD Gadget"
: "File-Stor Gadget"),
i);
/*
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -156,8 +156,6 @@ static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = {
/* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
.wMaxPacketSize = 0,
.bInterval = 0,
};
static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
......@@ -169,8 +167,6 @@ static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
/* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
.wMaxPacketSize = 0,
.bInterval = 0,
};
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
......@@ -183,17 +179,14 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
/* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
.wMaxPacketSize = 0,
.bInterval = 0,
};
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = {
.bLength = sizeof(uvc_ss_streaming_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* The following 3 values can be tweaked if necessary. */
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = cpu_to_le16(1024),
/* The bMaxBurst, bmAttributes and wBytesPerInterval values will be
* initialized from module parameters.
*/
};
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册