USB 3.11-rc1 merge

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iEYEABECAAYFAlHRtqkACgkQMUfUDdst+ykIWACguGzwSkoBjh2q8p+M6l4zGwQI
 fSAAoJvh8OKLWS7J3VkTWkyYy+Z2XV5d
 =FdaG
 -----END PGP SIGNATURE-----

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()
  ...
This commit is contained in:
Linus Torvalds 2013-07-02 11:31:09 -07:00
commit a84270189e
249 changed files with 16062 additions and 3379 deletions

View File

@ -0,0 +1,81 @@
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

View File

@ -0,0 +1,8 @@
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".

View File

@ -0,0 +1,16 @@
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

View File

@ -0,0 +1,14 @@
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

View File

@ -0,0 +1,15 @@
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

View File

@ -0,0 +1,9 @@
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".

View File

@ -0,0 +1,8 @@
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.

View File

@ -0,0 +1,14 @@
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

View File

@ -0,0 +1,9 @@
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".

View File

@ -0,0 +1,14 @@
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

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.
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

View File

@ -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>;

View File

@ -0,0 +1,384 @@
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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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";
};

View File

@ -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 {

View File

@ -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 {

View File

@ -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 */

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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
bool
# some non-PCI hcds implement EHCI
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
bool
# some non-PCI HCDs implement xHCI
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

View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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>");

View File

@ -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");

View File

@ -1,5 +1,5 @@
/*
* 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");

View File

@ -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 @@ put_id:
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;
}
/* 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 (!ci->platdata->phy_mode)
ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
ret = ci_hdrc_gadget_init(ci);
if (ret)
dev_info(dev, "doesn't support gadget\n");
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 */
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");
}
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 @@ rm_wq:
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);

View File

@ -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);
list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
req = list_entry(ptr, struct ci_hw_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"));
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 *)req->ptr + j));
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 @@ err:
* 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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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");

View File

@ -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;

View File

@ -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 @@ exit:
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,52 +455,40 @@ 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;
/* 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 */
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, 12, &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)++;
retval = send_request_dev_dep_msg_in(data, count);
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;
}
}
/* Loop until we have fetched everything we requested */
remaining = count;
this_part = remaining;
done = 0;
while (remaining > 0) {
if (!(data->rigol_quirk)) {
dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3;
else
this_part = remaining;
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;
}
}
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
@ -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;
}
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;
}
/* How many characters did the instrument send? */
n_characters = buffer[4] +
(buffer[5] << 8) +
(buffer[6] << 16) +
(buffer[7] << 24);
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;
/* 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;
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);
/* 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;
}
/* Bound amount of data received by amount of data requested */
if (n_characters > this_part)
n_characters = this_part;
/* 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;
}
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;
}
/* 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;

View File

@ -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)) {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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 = {

View File

@ -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

View File

@ -61,21 +61,46 @@
#define USBOTGSS_REVISION 0x0000
#define USBOTGSS_SYSCONFIG 0x0010
#define USBOTGSS_IRQ_EOI 0x0020
#define USBOTGSS_EOI_OFFSET 0x0008
#define USBOTGSS_IRQSTATUS_RAW_0 0x0024
#define USBOTGSS_IRQSTATUS_0 0x0028
#define USBOTGSS_IRQENABLE_SET_0 0x002c
#define USBOTGSS_IRQENABLE_CLR_0 0x0030
#define USBOTGSS_IRQSTATUS_RAW_1 0x0034
#define USBOTGSS_IRQSTATUS_1 0x0038
#define USBOTGSS_IRQENABLE_SET_1 0x003c
#define USBOTGSS_IRQENABLE_CLR_1 0x0040
#define USBOTGSS_IRQ0_OFFSET 0x0004
#define USBOTGSS_IRQSTATUS_RAW_1 0x0030
#define USBOTGSS_IRQSTATUS_1 0x0034
#define USBOTGSS_IRQENABLE_SET_1 0x0038
#define USBOTGSS_IRQENABLE_CLR_1 0x003c
#define USBOTGSS_IRQSTATUS_RAW_2 0x0040
#define USBOTGSS_IRQSTATUS_2 0x0044
#define USBOTGSS_IRQENABLE_SET_2 0x0048
#define USBOTGSS_IRQENABLE_CLR_2 0x004c
#define USBOTGSS_IRQSTATUS_RAW_3 0x0050
#define USBOTGSS_IRQSTATUS_3 0x0054
#define USBOTGSS_IRQENABLE_SET_3 0x0058
#define USBOTGSS_IRQENABLE_CLR_3 0x005c
#define USBOTGSS_IRQSTATUS_EOI_MISC 0x0030
#define USBOTGSS_IRQSTATUS_RAW_MISC 0x0034
#define USBOTGSS_IRQSTATUS_MISC 0x0038
#define USBOTGSS_IRQENABLE_SET_MISC 0x003c
#define USBOTGSS_IRQENABLE_CLR_MISC 0x0040
#define USBOTGSS_IRQMISC_OFFSET 0x03fc
#define USBOTGSS_UTMI_OTG_CTRL 0x0080
#define USBOTGSS_UTMI_OTG_STATUS 0x0084
#define USBOTGSS_UTMI_OTG_OFFSET 0x0480
#define USBOTGSS_TXFIFO_DEPTH 0x0508
#define USBOTGSS_RXFIFO_DEPTH 0x050c
#define USBOTGSS_MMRAM_OFFSET 0x0100
#define USBOTGSS_FLADJ 0x0104
#define USBOTGSS_DEBUG_CFG 0x0108
#define USBOTGSS_DEBUG_DATA 0x010c
#define USBOTGSS_DEV_EBC_EN 0x0110
#define USBOTGSS_DEBUG_OFFSET 0x0600
/* REVISION REGISTER */
#define USBOTGSS_REVISION_XMAJOR(reg) ((reg >> 8) & 0x7)
#define USBOTGSS_REVISION_XMAJOR1 1
#define USBOTGSS_REVISION_XMAJOR2 2
/* SYSCONFIG REGISTER */
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
@ -85,17 +110,17 @@
/* IRQS0 BITS */
#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
/* IRQ1 BITS */
#define USBOTGSS_IRQ1_DMADISABLECLR (1 << 17)
#define USBOTGSS_IRQ1_OEVT (1 << 16)
#define USBOTGSS_IRQ1_DRVVBUS_RISE (1 << 13)
#define USBOTGSS_IRQ1_CHRGVBUS_RISE (1 << 12)
#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE (1 << 11)
#define USBOTGSS_IRQ1_IDPULLUP_RISE (1 << 8)
#define USBOTGSS_IRQ1_DRVVBUS_FALL (1 << 5)
#define USBOTGSS_IRQ1_CHRGVBUS_FALL (1 << 4)
#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL (1 << 3)
#define USBOTGSS_IRQ1_IDPULLUP_FALL (1 << 0)
/* IRQMISC BITS */
#define USBOTGSS_IRQMISC_DMADISABLECLR (1 << 17)
#define USBOTGSS_IRQMISC_OEVT (1 << 16)
#define USBOTGSS_IRQMISC_DRVVBUS_RISE (1 << 13)
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE (1 << 12)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE (1 << 11)
#define USBOTGSS_IRQMISC_IDPULLUP_RISE (1 << 8)
#define USBOTGSS_IRQMISC_DRVVBUS_FALL (1 << 5)
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL (1 << 4)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL (1 << 3)
#define USBOTGSS_IRQMISC_IDPULLUP_FALL (1 << 0)
/* UTMI_OTG_CTRL REGISTER */
#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5)
@ -122,6 +147,12 @@ struct dwc3_omap {
void __iomem *base;
u32 utmi_otg_status;
u32 utmi_otg_offset;
u32 irqmisc_offset;
u32 irq_eoi_offset;
u32 debug_offset;
u32 irq0_offset;
u32 revision;
u32 dma_status:1;
};
@ -138,6 +169,58 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
writel(value, base + offset);
}
static u32 dwc3_omap_read_utmi_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS +
omap->utmi_otg_offset);
}
static void dwc3_omap_write_utmi_status(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS +
omap->utmi_otg_offset, value);
}
static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0 -
omap->irq0_offset);
}
static void dwc3_omap_write_irq0_status(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0 -
omap->irq0_offset, value);
}
static u32 dwc3_omap_read_irqmisc_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_MISC +
omap->irqmisc_offset);
}
static void dwc3_omap_write_irqmisc_status(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_MISC +
omap->irqmisc_offset, value);
}
static void dwc3_omap_write_irqmisc_set(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_MISC +
omap->irqmisc_offset, value);
}
static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0 -
omap->irq0_offset, value);
}
int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
{
u32 val;
@ -150,38 +233,38 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n");
val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
val = dwc3_omap_read_utmi_status(omap);
val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
| USBOTGSS_UTMI_OTG_STATUS_SESSEND);
val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
dwc3_omap_write_utmi_status(omap, val);
break;
case OMAP_DWC3_VBUS_VALID:
dev_dbg(omap->dev, "VBUS Connect\n");
val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
val = dwc3_omap_read_utmi_status(omap);
val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND;
val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
| USBOTGSS_UTMI_OTG_STATUS_SESSVALID
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
dwc3_omap_write_utmi_status(omap, val);
break;
case OMAP_DWC3_ID_FLOAT:
case OMAP_DWC3_VBUS_OFF:
dev_dbg(omap->dev, "VBUS Disconnect\n");
val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
val = dwc3_omap_read_utmi_status(omap);
val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT);
val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND
| USBOTGSS_UTMI_OTG_STATUS_IDDIG;
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
dwc3_omap_write_utmi_status(omap, val);
break;
default:
@ -199,44 +282,45 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
spin_lock(&omap->lock);
reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
reg = dwc3_omap_read_irqmisc_status(omap);
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
omap->dma_status = false;
}
if (reg & USBOTGSS_IRQ1_OEVT)
if (reg & USBOTGSS_IRQMISC_OEVT)
dev_dbg(omap->dev, "OTG Event\n");
if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE)
if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE)
dev_dbg(omap->dev, "DRVVBUS Rise\n");
if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE)
if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE)
dev_dbg(omap->dev, "CHRGVBUS Rise\n");
if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE)
if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE)
dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE)
if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE)
dev_dbg(omap->dev, "IDPULLUP Rise\n");
if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL)
if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL)
dev_dbg(omap->dev, "DRVVBUS Fall\n");
if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL)
if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL)
dev_dbg(omap->dev, "CHRGVBUS Fall\n");
if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL)
if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL)
dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
dwc3_omap_write_irqmisc_status(omap, reg);
reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
reg = dwc3_omap_read_irq0_status(omap);
dwc3_omap_write_irq0_status(omap, reg);
spin_unlock(&omap->lock);
@ -258,26 +342,26 @@ static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
/* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST;
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
dwc3_omap_write_irq0_set(omap, reg);
reg = (USBOTGSS_IRQ1_OEVT |
USBOTGSS_IRQ1_DRVVBUS_RISE |
USBOTGSS_IRQ1_CHRGVBUS_RISE |
USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
USBOTGSS_IRQ1_IDPULLUP_RISE |
USBOTGSS_IRQ1_DRVVBUS_FALL |
USBOTGSS_IRQ1_CHRGVBUS_FALL |
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
USBOTGSS_IRQ1_IDPULLUP_FALL);
reg = (USBOTGSS_IRQMISC_OEVT |
USBOTGSS_IRQMISC_DRVVBUS_RISE |
USBOTGSS_IRQMISC_CHRGVBUS_RISE |
USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
USBOTGSS_IRQMISC_IDPULLUP_RISE |
USBOTGSS_IRQMISC_DRVVBUS_FALL |
USBOTGSS_IRQMISC_CHRGVBUS_FALL |
USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
USBOTGSS_IRQMISC_IDPULLUP_FALL);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
dwc3_omap_write_irqmisc_set(omap, reg);
}
static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
{
/* disable all IRQs */
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
dwc3_omap_write_irqmisc_set(omap, 0x00);
dwc3_omap_write_irq0_set(omap, 0x00);
}
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
@ -294,6 +378,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
int irq;
int utmi_mode = 0;
int x_major;
u32 reg;
@ -347,10 +432,46 @@ static int dwc3_omap_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "get_sync failed with err %d\n", ret);
return ret;
goto err0;
}
reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
reg = dwc3_omap_readl(omap->base, USBOTGSS_REVISION);
omap->revision = reg;
x_major = USBOTGSS_REVISION_XMAJOR(reg);
/* Differentiate between OMAP5 and AM437x */
switch (x_major) {
case USBOTGSS_REVISION_XMAJOR1:
case USBOTGSS_REVISION_XMAJOR2:
omap->irq_eoi_offset = 0;
omap->irq0_offset = 0;
omap->irqmisc_offset = 0;
omap->utmi_otg_offset = 0;
omap->debug_offset = 0;
break;
default:
/* Default to the latest revision */
omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
break;
}
/* For OMAP5(ES2.0) and AM437x x_major is 2 even though there are
* changes in wrapper registers, Using dt compatible for aegis
*/
if (of_device_is_compatible(node, "ti,am437x-dwc3")) {
omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
}
reg = dwc3_omap_read_utmi_status(omap);
of_property_read_u32(node, "utmi-mode", &utmi_mode);
@ -365,7 +486,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
}
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
dwc3_omap_write_utmi_status(omap, reg);
/* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
@ -376,7 +497,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
if (ret) {
dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);
return ret;
goto err1;
}
dwc3_omap_enable_irqs(omap);
@ -384,10 +505,21 @@ static int dwc3_omap_probe(struct platform_device *pdev)
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(&pdev->dev, "failed to create dwc3 core\n");
return ret;
goto err2;
}
return 0;
err2:
dwc3_omap_disable_irqs(omap);
err1:
pm_runtime_put_sync(dev);
err0:
pm_runtime_disable(dev);
return ret;
}
static int dwc3_omap_remove(struct platform_device *pdev)
@ -406,6 +538,9 @@ static const struct of_device_id of_dwc3_match[] = {
{
.compatible = "ti,dwc3"
},
{
.compatible = "ti,am437x-dwc3"
},
{ },
};
MODULE_DEVICE_TABLE(of, of_dwc3_match);
@ -431,8 +566,7 @@ static int dwc3_omap_suspend(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
omap->utmi_otg_status = dwc3_omap_readl(omap->base,
USBOTGSS_UTMI_OTG_STATUS);
omap->utmi_otg_status = dwc3_omap_read_utmi_status(omap);
return 0;
}
@ -441,8 +575,7 @@ static int dwc3_omap_resume(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS,
omap->utmi_otg_status);
dwc3_omap_write_utmi_status(omap, omap->utmi_otg_status);
pm_runtime_disable(dev);
pm_runtime_set_active(dev);

View File

@ -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);

View File

@ -192,6 +192,16 @@ config USB_FUSB300
help
Faraday usb device controller FUSB300 driver
config USB_FOTG210_UDC
tristate "Faraday FOTG210 USB Peripheral Controller"
help
Faraday USB2.0 OTG controller which can be configured as
high speed or full speed USB device. This driver supppors
Bulk Transfer so far.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "fotg210_udc".
config USB_OMAP
tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1
@ -334,14 +344,6 @@ config USB_MV_U3D
# Controllers available in both integrated and discrete versions
#
# musb builds in ../musb along with host support
config USB_GADGET_MUSB_HDRC
tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
depends on USB_MUSB_HDRC
help
This OTG-capable silicon IP is used in dual designs including
the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
config USB_M66592
tristate "Renesas M66592 USB Peripheral Controller"
help
@ -507,12 +509,36 @@ config USB_F_SS_LB
config USB_U_SERIAL
tristate
config USB_U_ETHER
tristate
config USB_U_RNDIS
tristate
config USB_F_SERIAL
tristate
config USB_F_OBEX
tristate
config USB_F_NCM
tristate
config USB_F_ECM
tristate
config USB_F_PHONET
tristate
config USB_F_EEM
tristate
config USB_F_SUBSET
tristate
config USB_F_RNDIS
tristate
choice
tristate "USB Gadget Drivers"
default USB_ETH
@ -534,6 +560,121 @@ choice
# this first set of drivers all depend on bulk-capable hardware.
config USB_CONFIGFS
tristate "USB functions configurable through configfs"
select USB_LIBCOMPOSITE
help
A Linux USB "gadget" can be set up through configfs.
If this is the case, the USB functions (which from the host's
perspective are seen as interfaces) and configurations are
specified simply by creating appropriate directories in configfs.
Associating functions with configurations is done by creating
appropriate symbolic links.
For more information see Documentation/usb/gadget-configfs.txt.
config USB_CONFIGFS_SERIAL
boolean "Generic serial bulk in/out"
depends on USB_CONFIGFS
depends on TTY
select USB_U_SERIAL
select USB_F_SERIAL
help
The function talks to the Linux-USB generic serial driver.
config USB_CONFIGFS_ACM
boolean "Abstract Control Model (CDC ACM)"
depends on USB_CONFIGFS
depends on TTY
select USB_U_SERIAL
select USB_F_ACM
help
ACM serial link. This function can be used to interoperate with
MS-Windows hosts or with the Linux-USB "cdc-acm" driver.
config USB_CONFIGFS_OBEX
boolean "Object Exchange Model (CDC OBEX)"
depends on USB_CONFIGFS
depends on TTY
select USB_U_SERIAL
select USB_F_OBEX
help
You will need a user space OBEX server talking to /dev/ttyGS*,
since the kernel itself doesn't implement the OBEX protocol.
config USB_CONFIGFS_NCM
boolean "Network Control Model (CDC NCM)"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_NCM
help
NCM is an advanced protocol for Ethernet encapsulation, allows
grouping of several ethernet frames into one USB transfer and
different alignment possibilities.
config USB_CONFIGFS_ECM
boolean "Ethernet Control Model (CDC ECM)"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_ECM
help
The "Communication Device Class" (CDC) Ethernet Control Model.
That protocol is often avoided with pure Ethernet adapters, in
favor of simpler vendor-specific hardware, but is widely
supported by firmware for smart network devices.
config USB_CONFIGFS_ECM_SUBSET
boolean "Ethernet Control Model (CDC ECM) subset"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_SUBSET
help
On hardware that can't implement the full protocol,
a simple CDC subset is used, placing fewer demands on USB.
config USB_CONFIGFS_RNDIS
bool "RNDIS"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_RNDIS
help
Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
and Microsoft provides redistributable binary RNDIS drivers for
older versions of Windows.
To make MS-Windows work with this, use Documentation/usb/linux.inf
as the "driver info file". For versions of MS-Windows older than
XP, you'll need to download drivers from Microsoft's website; a URL
is given in comments found in that info file.
config USB_CONFIGFS_EEM
bool "Ethernet Emulation Model (EEM)"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_EEM
help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
and therefore can be supported by more hardware. Technically ECM and
EEM are designed for different applications. The ECM model extends
the network interface to the target (e.g. a USB cable modem), and the
EEM model is for mobile devices to communicate with hosts using
ethernet over USB. For Linux gadgets, however, the interface with
the host is the same (a usbX device), so the differences are minimal.
config USB_CONFIGFS_PHONET
boolean "Phonet protocol"
depends on USB_CONFIGFS
depends on NET
depends on PHONET
select USB_U_ETHER
select USB_F_PHONET
help
The Phonet protocol implementation for USB device.
config USB_ZERO
tristate "Gadget Zero (DEVELOPMENT)"
select USB_LIBCOMPOSITE
@ -603,6 +744,10 @@ config USB_ETH
tristate "Ethernet Gadget (with CDC Ethernet support)"
depends on NET
select USB_LIBCOMPOSITE
select USB_U_ETHER
select USB_U_RNDIS
select USB_F_ECM
select USB_F_SUBSET
select CRC32
help
This driver implements Ethernet style communication, in one of
@ -639,6 +784,7 @@ config USB_ETH_RNDIS
bool "RNDIS support"
depends on USB_ETH
select USB_LIBCOMPOSITE
select USB_F_RNDIS
default y
help
Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
@ -658,6 +804,7 @@ config USB_ETH_EEM
bool "Ethernet Emulation Model (EEM) support"
depends on USB_ETH
select USB_LIBCOMPOSITE
select USB_F_EEM
default n
help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
@ -675,6 +822,8 @@ config USB_G_NCM
tristate "Network Control Model (NCM) support"
depends on NET
select USB_LIBCOMPOSITE
select USB_U_ETHER
select USB_F_NCM
select CRC32
help
This driver implements USB CDC NCM subclass standard. NCM is
@ -718,6 +867,7 @@ config USB_FUNCTIONFS
config USB_FUNCTIONFS_ETH
bool "Include configuration with CDC ECM (Ethernet)"
depends on USB_FUNCTIONFS && NET
select USB_U_ETHER
help
Include a configuration with CDC ECM function (Ethernet) and the
Function Filesystem.
@ -725,6 +875,8 @@ config USB_FUNCTIONFS_ETH
config USB_FUNCTIONFS_RNDIS
bool "Include configuration with RNDIS (Ethernet)"
depends on USB_FUNCTIONFS && NET
select USB_U_ETHER
select USB_U_RNDIS
help
Include a configuration with RNDIS function (Ethernet) and the Filesystem.
@ -825,7 +977,9 @@ config USB_CDC_COMPOSITE
depends on NET
select USB_LIBCOMPOSITE
select USB_U_SERIAL
select USB_U_ETHER
select USB_F_ACM
select USB_F_ECM
help
This driver provides two functions in one configuration:
a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
@ -842,7 +996,11 @@ config USB_G_NOKIA
depends on PHONET
select USB_LIBCOMPOSITE
select USB_U_SERIAL
select USB_U_ETHER
select USB_F_ACM
select USB_F_OBEX
select USB_F_PHONET
select USB_F_ECM
help
The Nokia composite gadget provides support for acm, obex
and phonet in only one composite gadget driver.
@ -869,6 +1027,8 @@ config USB_G_MULTI
select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
select USB_LIBCOMPOSITE
select USB_U_SERIAL
select USB_U_ETHER
select USB_U_RNDIS
select USB_F_ACM
help
The Multifunction Composite Gadget provides Ethernet (RNDIS

View File

@ -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

View File

@ -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;
}

View File

@ -14,6 +14,7 @@
/* #define VERBOSE_DEBUG */
#include <linux/kernel.h>
#include <linux/netdevice.h>
#if defined USB_ETH_RNDIS
# undef USB_ETH_RNDIS
@ -91,27 +92,23 @@ static inline bool has_rndis(void)
#endif
}
/*-------------------------------------------------------------------------*/
#include <linux/module.h>
/*
* 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 "f_subset.c"
#include "u_ecm.h"
#include "u_gether.h"
#ifdef USB_ETH_RNDIS
#include "f_rndis.c"
#include "rndis.c"
#include "u_rndis.h"
#include "rndis.h"
#else
#define rndis_borrow_net(...) do {} while (0)
#endif
#include "f_eem.c"
#include "u_ether.c"
#include "u_eem.h"
/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();
USB_ETHERNET_MODULE_PARAMETERS();
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures.
*/
@ -206,8 +203,18 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL,
};
static u8 hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
static struct usb_function_instance *fi_ecm;
static struct usb_function *f_ecm;
static struct usb_function_instance *fi_eem;
static struct usb_function *f_eem;
static struct usb_function_instance *fi_geth;
static struct usb_function *f_geth;
static struct usb_function_instance *fi_rndis;
static struct usb_function *f_rndis;
/*-------------------------------------------------------------------------*/
/*
@ -217,6 +224,8 @@ static struct eth_dev *the_dev;
*/
static int __init rndis_do_config(struct usb_configuration *c)
{
int status;
/* FIXME alloc iConfiguration string, set it in c->strings */
if (gadget_is_otg(c->cdev->gadget)) {
@ -224,7 +233,15 @@ static int __init rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
return rndis_bind_config(c, hostaddr, the_dev);
f_rndis = usb_get_function(fi_rndis);
if (IS_ERR(f_rndis))
return PTR_ERR(f_rndis);
status = usb_add_function(c, f_rndis);
if (status < 0)
usb_put_function(f_rndis);
return status;
}
static struct usb_configuration rndis_config_driver = {
@ -249,6 +266,8 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
*/
static int __init eth_do_config(struct usb_configuration *c)
{
int status = 0;
/* FIXME alloc iConfiguration string, set it in c->strings */
if (gadget_is_otg(c->cdev->gadget)) {
@ -256,12 +275,38 @@ static int __init eth_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
if (use_eem)
return eem_bind_config(c, the_dev);
else if (can_support_ecm(c->cdev->gadget))
return ecm_bind_config(c, hostaddr, the_dev);
else
return geth_bind_config(c, hostaddr, the_dev);
if (use_eem) {
f_eem = usb_get_function(fi_eem);
if (IS_ERR(f_eem))
return PTR_ERR(f_eem);
status = usb_add_function(c, f_eem);
if (status < 0)
usb_put_function(f_eem);
return status;
} else if (can_support_ecm(c->cdev->gadget)) {
f_ecm = usb_get_function(fi_ecm);
if (IS_ERR(f_ecm))
return PTR_ERR(f_ecm);
status = usb_add_function(c, f_ecm);
if (status < 0)
usb_put_function(f_ecm);
return status;
} else {
f_geth = usb_get_function(fi_geth);
if (IS_ERR(f_geth))
return PTR_ERR(f_geth);
status = usb_add_function(c, f_geth);
if (status < 0)
usb_put_function(f_geth);
return status;
}
}
static struct usb_configuration eth_config_driver = {
@ -276,24 +321,50 @@ static struct usb_configuration eth_config_driver = {
static int __init eth_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct f_eem_opts *eem_opts = NULL;
struct f_ecm_opts *ecm_opts = NULL;
struct f_gether_opts *geth_opts = NULL;
struct net_device *net;
int status;
/* set up network link layer */
the_dev = gether_setup(cdev->gadget, hostaddr);
if (IS_ERR(the_dev))
return PTR_ERR(the_dev);
/* set up main config label and device descriptor */
if (use_eem) {
/* EEM */
fi_eem = usb_get_function_instance("eem");
if (IS_ERR(fi_eem))
return PTR_ERR(fi_eem);
eem_opts = container_of(fi_eem, struct f_eem_opts, func_inst);
net = eem_opts->net;
eth_config_driver.label = "CDC Ethernet (EEM)";
device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM);
device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM);
} else if (can_support_ecm(cdev->gadget)) {
} else if (can_support_ecm(gadget)) {
/* ECM */
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);
net = ecm_opts->net;
eth_config_driver.label = "CDC Ethernet (ECM)";
} else {
/* CDC Subset */
fi_geth = usb_get_function_instance("geth");
if (IS_ERR(fi_geth))
return PTR_ERR(fi_geth);
geth_opts = container_of(fi_geth, struct f_gether_opts,
func_inst);
net = geth_opts->net;
eth_config_driver.label = "CDC Subset/SAFE";
device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM);
@ -302,8 +373,34 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
}
gether_set_qmult(net, qmult);
if (!gether_set_host_addr(net, host_addr))
pr_info("using host ethernet address: %s", host_addr);
if (!gether_set_dev_addr(net, dev_addr))
pr_info("using self ethernet address: %s", dev_addr);
if (has_rndis()) {
/* RNDIS plus ECM-or-Subset */
gether_set_gadget(net, cdev->gadget);
status = gether_register_netdev(net);
if (status)
goto fail;
if (use_eem)
eem_opts->bound = true;
else if (can_support_ecm(gadget))
ecm_opts->bound = true;
else
geth_opts->bound = true;
fi_rndis = usb_get_function_instance("rndis");
if (IS_ERR(fi_rndis)) {
status = PTR_ERR(fi_rndis);
goto fail;
}
rndis_borrow_net(fi_rndis, net);
device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM);
device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);
device_desc.bNumConfigurations = 2;
@ -315,7 +412,7 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
goto fail;
goto fail1;
device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
@ -324,12 +421,12 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
status = usb_add_config(cdev, &rndis_config_driver,
rndis_do_config);
if (status < 0)
goto fail;
goto fail1;
}
status = usb_add_config(cdev, &eth_config_driver, eth_do_config);
if (status < 0)
goto fail;
goto fail1;
usb_composite_overwrite_options(cdev, &coverwrite);
dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
@ -337,14 +434,29 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
return 0;
fail1:
if (has_rndis())
usb_put_function_instance(fi_rndis);
fail:
gether_cleanup(the_dev);
if (use_eem)
usb_put_function_instance(fi_eem);
else if (can_support_ecm(gadget))
usb_put_function_instance(fi_ecm);
else
usb_put_function_instance(fi_geth);
return status;
}
static int __exit eth_unbind(struct usb_composite_dev *cdev)
{
gether_cleanup(the_dev);
if (has_rndis())
usb_put_function_instance(fi_rndis);
if (use_eem)
usb_put_function_instance(fi_eem);
else if (can_support_ecm(cdev->gadget))
usb_put_function_instance(fi_ecm);
else
usb_put_function_instance(fi_geth);
return 0;
}

View File

@ -14,10 +14,13 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>
#include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_ecm.h"
/*
@ -684,9 +687,44 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_ecm *ecm = func_to_ecm(f);
struct usb_string *us;
int status;
struct usb_ep *ep;
#ifndef USBF_ECM_INCLUDED
struct f_ecm_opts *ecm_opts;
if (!can_support_ecm(cdev->gadget))
return -EINVAL;
ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to ecm_opts->bound access
*/
if (!ecm_opts->bound) {
mutex_lock(&ecm_opts->lock);
gether_set_gadget(ecm_opts->net, cdev->gadget);
status = gether_register_netdev(ecm_opts->net);
mutex_unlock(&ecm_opts->lock);
if (status)
return status;
ecm_opts->bound = true;
}
#endif
us = usb_gstrings_attach(cdev, ecm_strings,
ARRAY_SIZE(ecm_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
ecm_control_intf.iInterface = us[0].id;
ecm_data_intf.iInterface = us[2].id;
ecm_desc.iMACAddress = us[1].id;
ecm_iad_descriptor.iFunction = us[3].id;
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@ -796,14 +834,15 @@ fail:
return status;
}
#ifdef USBF_ECM_INCLUDED
static void
ecm_unbind(struct usb_configuration *c, struct usb_function *f)
ecm_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_ecm *ecm = func_to_ecm(f);
DBG(c->cdev, "ecm unbind\n");
ecm_string_defs[0].id = 0;
usb_free_all_descriptors(f);
kfree(ecm->notify_req->buf);
@ -834,17 +873,6 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
return -EINVAL;
if (ecm_string_defs[0].id == 0) {
status = usb_string_ids_tab(c->cdev, ecm_string_defs);
if (status)
return status;
ecm_control_intf.iInterface = ecm_string_defs[0].id;
ecm_data_intf.iInterface = ecm_string_defs[2].id;
ecm_desc.iMACAddress = ecm_string_defs[1].id;
ecm_iad_descriptor.iFunction = ecm_string_defs[3].id;
}
/* allocate and initialize one new instance */
ecm = kzalloc(sizeof *ecm, GFP_KERNEL);
if (!ecm)
@ -858,10 +886,9 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
ecm->port.cdc_filter = DEFAULT_FILTER;
ecm->port.func.name = "cdc_ethernet";
ecm->port.func.strings = ecm_strings;
/* descriptors are per-instance copies */
ecm->port.func.bind = ecm_bind;
ecm->port.func.unbind = ecm_unbind;
ecm->port.func.unbind = ecm_old_unbind;
ecm->port.func.set_alt = ecm_set_alt;
ecm->port.func.get_alt = ecm_get_alt;
ecm->port.func.setup = ecm_setup;
@ -872,3 +899,143 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
kfree(ecm);
return status;
}
#else
static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_ecm_opts,
func_inst.group);
}
/* f_ecm_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(ecm);
/* f_ecm_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ecm);
/* f_ecm_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ecm);
/* f_ecm_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ecm);
/* f_ecm_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ecm);
static struct configfs_attribute *ecm_attrs[] = {
&f_ecm_opts_dev_addr.attr,
&f_ecm_opts_host_addr.attr,
&f_ecm_opts_qmult.attr,
&f_ecm_opts_ifname.attr,
NULL,
};
static struct config_item_type ecm_func_type = {
.ct_item_ops = &ecm_item_ops,
.ct_attrs = ecm_attrs,
.ct_owner = THIS_MODULE,
};
static void ecm_free_inst(struct usb_function_instance *f)
{
struct f_ecm_opts *opts;
opts = container_of(f, struct f_ecm_opts, func_inst);
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
kfree(opts);
}
static struct usb_function_instance *ecm_alloc_inst(void)
{
struct f_ecm_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = ecm_free_inst;
opts->net = gether_setup_default();
if (IS_ERR(opts->net))
return ERR_PTR(PTR_ERR(opts->net));
config_group_init_type_name(&opts->func_inst.group, "", &ecm_func_type);
return &opts->func_inst;
}
static void ecm_free(struct usb_function *f)
{
struct f_ecm *ecm;
struct f_ecm_opts *opts;
ecm = func_to_ecm(f);
opts = container_of(f->fi, struct f_ecm_opts, func_inst);
kfree(ecm);
mutex_lock(&opts->lock);
opts->refcnt--;
mutex_unlock(&opts->lock);
}
static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_ecm *ecm = func_to_ecm(f);
DBG(c->cdev, "ecm unbind\n");
usb_free_all_descriptors(f);
kfree(ecm->notify_req->buf);
usb_ep_free_request(ecm->notify, ecm->notify_req);
}
struct usb_function *ecm_alloc(struct usb_function_instance *fi)
{
struct f_ecm *ecm;
struct f_ecm_opts *opts;
int status;
/* allocate and initialize one new instance */
ecm = kzalloc(sizeof(*ecm), GFP_KERNEL);
if (!ecm)
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_ecm_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
/* export host's Ethernet address in CDC format */
status = gether_get_host_addr_cdc(opts->net, ecm->ethaddr,
sizeof(ecm->ethaddr));
if (status < 12) {
kfree(ecm);
mutex_unlock(&opts->lock);
return ERR_PTR(-EINVAL);
}
ecm_string_defs[1].s = ecm->ethaddr;
ecm->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
ecm->port.cdc_filter = DEFAULT_FILTER;
ecm->port.func.name = "cdc_ethernet";
/* descriptors are per-instance copies */
ecm->port.func.bind = ecm_bind;
ecm->port.func.unbind = ecm_unbind;
ecm->port.func.set_alt = ecm_set_alt;
ecm->port.func.get_alt = ecm_get_alt;
ecm->port.func.setup = ecm_setup;
ecm->port.func.disable = ecm_disable;
ecm->port.func.free_func = ecm_free;
return &ecm->port.func;
}
DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");
#endif

View File

@ -12,12 +12,15 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_eem.h"
#define EEM_HLEN 2
@ -40,7 +43,7 @@ static inline struct f_eem *func_to_eem(struct usb_function *f)
/* interface descriptor: */
static struct usb_interface_descriptor eem_intf __initdata = {
static struct usb_interface_descriptor eem_intf = {
.bLength = sizeof eem_intf,
.bDescriptorType = USB_DT_INTERFACE,
@ -54,7 +57,7 @@ static struct usb_interface_descriptor eem_intf __initdata = {
/* full speed support: */
static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = {
static struct usb_endpoint_descriptor eem_fs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -62,7 +65,7 @@ static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = {
static struct usb_endpoint_descriptor eem_fs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -70,7 +73,7 @@ static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_descriptor_header *eem_fs_function[] __initdata = {
static struct usb_descriptor_header *eem_fs_function[] = {
/* CDC EEM control descriptors */
(struct usb_descriptor_header *) &eem_intf,
(struct usb_descriptor_header *) &eem_fs_in_desc,
@ -80,7 +83,7 @@ static struct usb_descriptor_header *eem_fs_function[] __initdata = {
/* high speed support: */
static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = {
static struct usb_endpoint_descriptor eem_hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -89,7 +92,7 @@ static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = {
static struct usb_endpoint_descriptor eem_hs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -98,7 +101,7 @@ static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_descriptor_header *eem_hs_function[] __initdata = {
static struct usb_descriptor_header *eem_hs_function[] = {
/* CDC EEM control descriptors */
(struct usb_descriptor_header *) &eem_intf,
(struct usb_descriptor_header *) &eem_hs_in_desc,
@ -108,7 +111,7 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {
/* super speed support: */
static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = {
static struct usb_endpoint_descriptor eem_ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -117,7 +120,7 @@ static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = {
static struct usb_endpoint_descriptor eem_ss_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -126,7 +129,7 @@ static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = {
static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc = {
.bLength = sizeof eem_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
@ -135,7 +138,7 @@ static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = {
/* .bmAttributes = 0, */
};
static struct usb_descriptor_header *eem_ss_function[] __initdata = {
static struct usb_descriptor_header *eem_ss_function[] = {
/* CDC EEM control descriptors */
(struct usb_descriptor_header *) &eem_intf,
(struct usb_descriptor_header *) &eem_ss_in_desc,
@ -242,14 +245,40 @@ static void eem_disable(struct usb_function *f)
/* EEM function driver setup/binding */
static int __init
eem_bind(struct usb_configuration *c, struct usb_function *f)
static int eem_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_eem *eem = func_to_eem(f);
struct usb_string *us;
int status;
struct usb_ep *ep;
struct f_eem_opts *eem_opts;
eem_opts = container_of(f->fi, struct f_eem_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to eem_opts->bound access
*/
if (!eem_opts->bound) {
mutex_lock(&eem_opts->lock);
gether_set_gadget(eem_opts->net, cdev->gadget);
status = gether_register_netdev(eem_opts->net);
mutex_unlock(&eem_opts->lock);
if (status)
return status;
eem_opts->bound = true;
}
us = usb_gstrings_attach(cdev, eem_strings,
ARRAY_SIZE(eem_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
eem_intf.iInterface = us[0].id;
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@ -307,17 +336,6 @@ fail:
return status;
}
static void
eem_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_eem *eem = func_to_eem(f);
DBG(c->cdev, "eem unbind\n");
usb_free_all_descriptors(f);
kfree(eem);
}
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
{
struct sk_buff *skb = (struct sk_buff *)req->context;
@ -518,55 +536,124 @@ error:
return status;
}
/**
* eem_bind_config - add CDC Ethernet (EEM) network link to a configuration
* @c: the configuration to support the network link
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
static inline struct f_eem_opts *to_f_eem_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_eem_opts,
func_inst.group);
}
/* f_eem_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(eem);
/* f_eem_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(eem);
/* f_eem_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(eem);
/* f_eem_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(eem);
/* f_eem_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(eem);
static struct configfs_attribute *eem_attrs[] = {
&f_eem_opts_dev_addr.attr,
&f_eem_opts_host_addr.attr,
&f_eem_opts_qmult.attr,
&f_eem_opts_ifname.attr,
NULL,
};
static struct config_item_type eem_func_type = {
.ct_item_ops = &eem_item_ops,
.ct_attrs = eem_attrs,
.ct_owner = THIS_MODULE,
};
static void eem_free_inst(struct usb_function_instance *f)
{
struct f_eem_opts *opts;
opts = container_of(f, struct f_eem_opts, func_inst);
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
kfree(opts);
}
static struct usb_function_instance *eem_alloc_inst(void)
{
struct f_eem_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = eem_free_inst;
opts->net = gether_setup_default();
if (IS_ERR(opts->net))
return ERR_CAST(opts->net);
config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type);
return &opts->func_inst;
}
static void eem_free(struct usb_function *f)
{
struct f_eem *eem;
struct f_eem_opts *opts;
eem = func_to_eem(f);
opts = container_of(f->fi, struct f_eem_opts, func_inst);
kfree(eem);
mutex_lock(&opts->lock);
opts->refcnt--;
mutex_unlock(&opts->lock);
}
static void eem_unbind(struct usb_configuration *c, struct usb_function *f)
{
DBG(c->cdev, "eem unbind\n");
usb_free_all_descriptors(f);
}
struct usb_function *eem_alloc(struct usb_function_instance *fi)
{
struct f_eem *eem;
int status;
/* maybe allocate device-global string IDs */
if (eem_string_defs[0].id == 0) {
/* control interface label */
status = usb_string_id(c->cdev);
if (status < 0)
return status;
eem_string_defs[0].id = status;
eem_intf.iInterface = status;
}
struct f_eem_opts *opts;
/* allocate and initialize one new instance */
eem = kzalloc(sizeof *eem, GFP_KERNEL);
eem = kzalloc(sizeof(*eem), GFP_KERNEL);
if (!eem)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
eem->port.ioport = dev;
opts = container_of(fi, struct f_eem_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
eem->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem";
eem->port.func.strings = eem_strings;
/* descriptors are per-instance copies */
eem->port.func.bind = eem_bind;
eem->port.func.unbind = eem_unbind;
eem->port.func.set_alt = eem_set_alt;
eem->port.func.setup = eem_setup;
eem->port.func.disable = eem_disable;
eem->port.func.free_func = eem_free;
eem->port.wrap = eem_wrap;
eem->port.unwrap = eem_unwrap;
eem->port.header_len = EEM_HLEN;
status = usb_add_function(c, &eem->port.func);
if (status)
kfree(eem);
return status;
return &eem->port.func;
}
DECLARE_USB_FUNCTION_INIT(eem, eem_alloc_inst, eem_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");

View File

@ -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 @@ buffhds_first_it:
"%-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);
/*

View File

@ -16,6 +16,7 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
@ -23,6 +24,8 @@
#include <linux/usb/cdc.h>
#include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_ncm.h"
/*
* This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
@ -125,7 +128,7 @@ static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
#define NCM_STATUS_INTERVAL_MS 32
#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
static struct usb_interface_assoc_descriptor ncm_iad_desc = {
.bLength = sizeof ncm_iad_desc,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
@ -139,7 +142,7 @@ static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
/* interface descriptor: */
static struct usb_interface_descriptor ncm_control_intf __initdata = {
static struct usb_interface_descriptor ncm_control_intf = {
.bLength = sizeof ncm_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
@ -151,7 +154,7 @@ static struct usb_interface_descriptor ncm_control_intf __initdata = {
/* .iInterface = DYNAMIC */
};
static struct usb_cdc_header_desc ncm_header_desc __initdata = {
static struct usb_cdc_header_desc ncm_header_desc = {
.bLength = sizeof ncm_header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
@ -159,7 +162,7 @@ static struct usb_cdc_header_desc ncm_header_desc __initdata = {
.bcdCDC = cpu_to_le16(0x0110),
};
static struct usb_cdc_union_desc ncm_union_desc __initdata = {
static struct usb_cdc_union_desc ncm_union_desc = {
.bLength = sizeof(ncm_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@ -167,7 +170,7 @@ static struct usb_cdc_union_desc ncm_union_desc __initdata = {
/* .bSlaveInterface0 = DYNAMIC */
};
static struct usb_cdc_ether_desc ecm_desc __initdata = {
static struct usb_cdc_ether_desc ecm_desc = {
.bLength = sizeof ecm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
@ -182,7 +185,7 @@ static struct usb_cdc_ether_desc ecm_desc __initdata = {
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
static struct usb_cdc_ncm_desc ncm_desc __initdata = {
static struct usb_cdc_ncm_desc ncm_desc = {
.bLength = sizeof ncm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_NCM_TYPE,
@ -194,7 +197,7 @@ static struct usb_cdc_ncm_desc ncm_desc __initdata = {
/* the default data interface has no endpoints ... */
static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
static struct usb_interface_descriptor ncm_data_nop_intf = {
.bLength = sizeof ncm_data_nop_intf,
.bDescriptorType = USB_DT_INTERFACE,
@ -209,7 +212,7 @@ static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
/* ... but the "real" data interface has two bulk endpoints */
static struct usb_interface_descriptor ncm_data_intf __initdata = {
static struct usb_interface_descriptor ncm_data_intf = {
.bLength = sizeof ncm_data_intf,
.bDescriptorType = USB_DT_INTERFACE,
@ -224,7 +227,7 @@ static struct usb_interface_descriptor ncm_data_intf __initdata = {
/* full speed support: */
static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
static struct usb_endpoint_descriptor fs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -234,7 +237,7 @@ static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
.bInterval = NCM_STATUS_INTERVAL_MS,
};
static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
static struct usb_endpoint_descriptor fs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -242,7 +245,7 @@ static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
static struct usb_endpoint_descriptor fs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -250,7 +253,7 @@ static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
static struct usb_descriptor_header *ncm_fs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
@ -269,7 +272,7 @@ static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
/* high speed support: */
static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -278,7 +281,7 @@ static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
.bInterval = USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS),
};
static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
static struct usb_endpoint_descriptor hs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -287,7 +290,7 @@ static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
static struct usb_endpoint_descriptor hs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -296,7 +299,7 @@ static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
static struct usb_descriptor_header *ncm_hs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
@ -1152,13 +1155,44 @@ static void ncm_close(struct gether *geth)
/* ethernet function driver setup/binding */
static int __init
ncm_bind(struct usb_configuration *c, struct usb_function *f)
static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_ncm *ncm = func_to_ncm(f);
struct usb_string *us;
int status;
struct usb_ep *ep;
struct f_ncm_opts *ncm_opts;
if (!can_support_ecm(cdev->gadget))
return -EINVAL;
ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to ncm_opts->bound access
*/
if (!ncm_opts->bound) {
mutex_lock(&ncm_opts->lock);
gether_set_gadget(ncm_opts->net, cdev->gadget);
status = gether_register_netdev(ncm_opts->net);
mutex_unlock(&ncm_opts->lock);
if (status)
return status;
ncm_opts->bound = true;
}
us = usb_gstrings_attach(cdev, ncm_strings,
ARRAY_SIZE(ncm_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
ecm_desc.iMACAddress = us[STRING_MAC_IDX].id;
ncm_iad_desc.iFunction = us[STRING_IAD_IDX].id;
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
@ -1259,74 +1293,128 @@ fail:
return status;
}
static void
ncm_unbind(struct usb_configuration *c, struct usb_function *f)
static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
{
struct f_ncm *ncm = func_to_ncm(f);
return container_of(to_config_group(item), struct f_ncm_opts,
func_inst.group);
}
/* f_ncm_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(ncm);
/* f_ncm_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm);
/* f_ncm_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm);
/* f_ncm_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
/* f_ncm_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
static struct configfs_attribute *ncm_attrs[] = {
&f_ncm_opts_dev_addr.attr,
&f_ncm_opts_host_addr.attr,
&f_ncm_opts_qmult.attr,
&f_ncm_opts_ifname.attr,
NULL,
};
static struct config_item_type ncm_func_type = {
.ct_item_ops = &ncm_item_ops,
.ct_attrs = ncm_attrs,
.ct_owner = THIS_MODULE,
};
static void ncm_free_inst(struct usb_function_instance *f)
{
struct f_ncm_opts *opts;
opts = container_of(f, struct f_ncm_opts, func_inst);
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
kfree(opts);
}
static struct usb_function_instance *ncm_alloc_inst(void)
{
struct f_ncm_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = ncm_free_inst;
opts->net = gether_setup_default();
if (IS_ERR(opts->net))
return ERR_PTR(PTR_ERR(opts->net));
config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
return &opts->func_inst;
}
static void ncm_free(struct usb_function *f)
{
struct f_ncm *ncm;
struct f_ncm_opts *opts;
ncm = func_to_ncm(f);
opts = container_of(f->fi, struct f_ncm_opts, func_inst);
kfree(ncm);
mutex_lock(&opts->lock);
opts->refcnt--;
mutex_unlock(&opts->lock);
}
static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_ncm *ncm = func_to_ncm(f);
DBG(c->cdev, "ncm unbind\n");
ncm_string_defs[0].id = 0;
usb_free_all_descriptors(f);
kfree(ncm->notify_req->buf);
usb_ep_free_request(ncm->notify, ncm->notify_req);
kfree(ncm);
}
/**
* ncm_bind_config - add CDC Network link to a configuration
* @c: the configuration to support the network link
* @ethaddr: a buffer in which the ethernet address of the host side
* side of the link was recorded
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev)
struct usb_function *ncm_alloc(struct usb_function_instance *fi)
{
struct f_ncm *ncm;
int status;
if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
return -EINVAL;
if (ncm_string_defs[0].id == 0) {
status = usb_string_ids_tab(c->cdev, ncm_string_defs);
if (status < 0)
return status;
ncm_control_intf.iInterface =
ncm_string_defs[STRING_CTRL_IDX].id;
status = ncm_string_defs[STRING_DATA_IDX].id;
ncm_data_nop_intf.iInterface = status;
ncm_data_intf.iInterface = status;
ecm_desc.iMACAddress = ncm_string_defs[STRING_MAC_IDX].id;
ncm_iad_desc.iFunction = ncm_string_defs[STRING_IAD_IDX].id;
}
struct f_ncm *ncm;
struct f_ncm_opts *opts;
int status;
/* allocate and initialize one new instance */
ncm = kzalloc(sizeof *ncm, GFP_KERNEL);
ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
if (!ncm)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_ncm_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
/* export host's Ethernet address in CDC format */
snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr);
status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
sizeof(ncm->ethaddr));
if (status < 12) { /* strlen("01234567890a") */
kfree(ncm);
mutex_unlock(&opts->lock);
return ERR_PTR(-EINVAL);
}
ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
spin_lock_init(&ncm->lock);
ncm_reset_values(ncm);
ncm->port.ioport = dev;
ncm->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
ncm->port.is_fixed = true;
ncm->port.func.name = "cdc_network";
ncm->port.func.strings = ncm_strings;
/* descriptors are per-instance copies */
ncm->port.func.bind = ncm_bind;
ncm->port.func.unbind = ncm_unbind;
@ -1334,12 +1422,14 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
ncm->port.func.get_alt = ncm_get_alt;
ncm->port.func.setup = ncm_setup;
ncm->port.func.disable = ncm_disable;
ncm->port.func.free_func = ncm_free;
ncm->port.wrap = ncm_wrap_ntb;
ncm->port.unwrap = ncm_unwrap_ntb;
status = usb_add_function(c, &ncm->port.func);
if (status)
kfree(ncm);
return status;
return &ncm->port.func;
}
DECLARE_USB_FUNCTION_INIT(ncm, ncm_alloc_inst, ncm_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yauheni Kaliuta");

View File

@ -309,23 +309,20 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_obex *obex = func_to_obex(f);
struct usb_string *us;
int status;
struct usb_ep *ep;
if (!can_support_obex(c))
return -EINVAL;
if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
status = usb_string_ids_tab(c->cdev, obex_string_defs);
if (status < 0)
return status;
obex_control_intf.iInterface =
obex_string_defs[OBEX_CTRL_IDX].id;
status = obex_string_defs[OBEX_DATA_IDX].id;
obex_data_nop_intf.iInterface = status;
obex_data_intf.iInterface = status;
}
us = usb_gstrings_attach(cdev, obex_strings,
ARRAY_SIZE(obex_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
obex_control_intf.iInterface = us[OBEX_CTRL_IDX].id;
obex_data_nop_intf.iInterface = us[OBEX_DATA_IDX].id;
obex_data_intf.iInterface = us[OBEX_DATA_IDX].id;
/* allocate instance-specific interface IDs, and patch descriptors */
@ -406,57 +403,6 @@ fail:
return status;
}
#ifdef USBF_OBEX_INCLUDED
static void
obex_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
obex_string_defs[OBEX_CTRL_IDX].id = 0;
usb_free_all_descriptors(f);
kfree(func_to_obex(f));
}
/**
* obex_bind_config - add a CDC OBEX function to a configuration
* @c: the configuration to support the CDC OBEX instance
* @port_num: /dev/ttyGS* port this interface will use
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*/
int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
{
struct f_obex *obex;
int status;
/* allocate and initialize one new instance */
obex = kzalloc(sizeof *obex, GFP_KERNEL);
if (!obex)
return -ENOMEM;
obex->port_num = port_num;
obex->port.connect = obex_connect;
obex->port.disconnect = obex_disconnect;
obex->port.func.name = "obex";
obex->port.func.strings = obex_strings;
/* descriptors are per-instance copies */
obex->port.func.bind = obex_bind;
obex->port.func.unbind = obex_old_unbind;
obex->port.func.set_alt = obex_set_alt;
obex->port.func.get_alt = obex_get_alt;
obex->port.func.disable = obex_disable;
status = usb_add_function(c, &obex->port.func);
if (status)
kfree(obex);
return status;
}
#else
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_serial_opts,
@ -550,7 +496,6 @@ static void obex_free(struct usb_function *f)
static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
{
obex_string_defs[OBEX_CTRL_IDX].id = 0;
usb_free_all_descriptors(f);
}
@ -572,7 +517,6 @@ struct usb_function *obex_alloc(struct usb_function_instance *fi)
obex->port.disconnect = obex_disconnect;
obex->port.func.name = "obex";
obex->port.func.strings = obex_strings;
/* descriptors are per-instance copies */
obex->port.func.bind = obex_bind;
obex->port.func.unbind = obex_unbind;
@ -585,8 +529,5 @@ struct usb_function *obex_alloc(struct usb_function_instance *fi)
}
DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
#endif
MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL");

View File

@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/netdevice.h>
@ -25,6 +26,7 @@
#include <linux/usb/composite.h>
#include "u_phonet.h"
#include "u_ether.h"
#define PN_MEDIA_USB 0x1B
#define MAXPACKET 512
@ -478,8 +480,7 @@ static void pn_disconnect(struct usb_function *f)
/*-------------------------------------------------------------------------*/
static __init
int pn_bind(struct usb_configuration *c, struct usb_function *f)
static int pn_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct usb_gadget *gadget = cdev->gadget;
@ -487,6 +488,27 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
int status, i;
#ifndef USBF_PHONET_INCLUDED
struct f_phonet_opts *phonet_opts;
phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to phonet_opts->bound access
*/
if (!phonet_opts->bound) {
gphonet_set_gadget(phonet_opts->net, gadget);
status = gphonet_register_netdev(phonet_opts->net);
if (status)
return status;
phonet_opts->bound = true;
}
#endif
/* Reserve interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@ -560,8 +582,98 @@ err:
return status;
}
static void
pn_unbind(struct usb_configuration *c, struct usb_function *f)
static inline struct f_phonet_opts *to_f_phonet_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_phonet_opts,
func_inst.group);
}
CONFIGFS_ATTR_STRUCT(f_phonet_opts);
static ssize_t f_phonet_attr_show(struct config_item *item,
struct configfs_attribute *attr,
char *page)
{
struct f_phonet_opts *opts = to_f_phonet_opts(item);
struct f_phonet_opts_attribute *f_phonet_opts_attr =
container_of(attr, struct f_phonet_opts_attribute, attr);
ssize_t ret = 0;
if (f_phonet_opts_attr->show)
ret = f_phonet_opts_attr->show(opts, page);
return ret;
}
static void phonet_attr_release(struct config_item *item)
{
struct f_phonet_opts *opts = to_f_phonet_opts(item);
usb_put_function_instance(&opts->func_inst);
}
static struct configfs_item_operations phonet_item_ops = {
.release = phonet_attr_release,
.show_attribute = f_phonet_attr_show,
};
static ssize_t f_phonet_ifname_show(struct f_phonet_opts *opts, char *page)
{
return gether_get_ifname(opts->net, page, PAGE_SIZE);
}
static struct f_phonet_opts_attribute f_phonet_ifname =
__CONFIGFS_ATTR_RO(ifname, f_phonet_ifname_show);
static struct configfs_attribute *phonet_attrs[] = {
&f_phonet_ifname.attr,
NULL,
};
static struct config_item_type phonet_func_type = {
.ct_item_ops = &phonet_item_ops,
.ct_attrs = phonet_attrs,
.ct_owner = THIS_MODULE,
};
static void phonet_free_inst(struct usb_function_instance *f)
{
struct f_phonet_opts *opts;
opts = container_of(f, struct f_phonet_opts, func_inst);
if (opts->bound)
gphonet_cleanup(opts->net);
else
free_netdev(opts->net);
kfree(opts);
}
static struct usb_function_instance *phonet_alloc_inst(void)
{
struct f_phonet_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = phonet_free_inst;
opts->net = gphonet_setup_default();
if (IS_ERR(opts->net))
return ERR_PTR(PTR_ERR(opts->net));
config_group_init_type_name(&opts->func_inst.group, "",
&phonet_func_type);
return &opts->func_inst;
}
static void phonet_free(struct usb_function *f)
{
struct f_phonet *phonet;
phonet = func_to_pn(f);
kfree(phonet);
}
static void pn_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_phonet *fp = func_to_pn(f);
int i;
@ -574,61 +686,72 @@ pn_unbind(struct usb_configuration *c, struct usb_function *f)
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
usb_free_all_descriptors(f);
kfree(fp);
}
/*-------------------------------------------------------------------------*/
static struct net_device *dev;
int __init phonet_bind_config(struct usb_configuration *c)
struct usb_function *phonet_alloc(struct usb_function_instance *fi)
{
struct f_phonet *fp;
int err, size;
struct f_phonet_opts *opts;
int size;
size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *));
fp = kzalloc(size, GFP_KERNEL);
if (!fp)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
fp->dev = dev;
opts = container_of(fi, struct f_phonet_opts, func_inst);
fp->dev = opts->net;
fp->function.name = "phonet";
fp->function.bind = pn_bind;
fp->function.unbind = pn_unbind;
fp->function.set_alt = pn_set_alt;
fp->function.get_alt = pn_get_alt;
fp->function.disable = pn_disconnect;
fp->function.free_func = phonet_free;
spin_lock_init(&fp->rx.lock);
err = usb_add_function(c, &fp->function);
if (err)
kfree(fp);
return err;
return &fp->function;
}
int __init gphonet_setup(struct usb_gadget *gadget)
struct net_device *gphonet_setup_default(void)
{
struct net_device *dev;
struct phonet_port *port;
int err;
/* Create net device */
BUG_ON(dev);
dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup);
if (!dev)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
port = netdev_priv(dev);
spin_lock_init(&port->lock);
netif_carrier_off(dev);
SET_NETDEV_DEV(dev, &gadget->dev);
err = register_netdev(dev);
if (err)
free_netdev(dev);
return err;
return dev;
}
void gphonet_cleanup(void)
void gphonet_set_gadget(struct net_device *net, struct usb_gadget *g)
{
SET_NETDEV_DEV(net, &g->dev);
}
int gphonet_register_netdev(struct net_device *net)
{
int status;
status = register_netdev(net);
if (status)
free_netdev(net);
return status;
}
void gphonet_cleanup(struct net_device *dev)
{
unregister_netdev(dev);
}
DECLARE_USB_FUNCTION_INIT(phonet, phonet_alloc_inst, phonet_alloc);
MODULE_AUTHOR("Rémi Denis-Courmont");
MODULE_LICENSE("GPL");

View File

@ -17,15 +17,17 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>
#include <linux/atomic.h>
#include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_rndis.h"
#include "rndis.h"
/*
* This function is an RNDIS Ethernet port -- a Microsoft protocol that's
* been promoted instead of the standard CDC Ethernet. The published RNDIS
@ -655,6 +657,13 @@ static void rndis_close(struct gether *geth)
/*-------------------------------------------------------------------------*/
/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{
/* everything else is *presumably* fine */
return true;
}
/* ethernet function driver setup/binding */
static int
@ -662,9 +671,41 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_rndis *rndis = func_to_rndis(f);
struct usb_string *us;
int status;
struct usb_ep *ep;
#ifndef USB_FRNDIS_INCLUDED
struct f_rndis_opts *rndis_opts;
if (!can_support_rndis(c))
return -EINVAL;
rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to rndis_opts->bound access
*/
if (!rndis_opts->bound) {
gether_set_gadget(rndis_opts->net, cdev->gadget);
status = gether_register_netdev(rndis_opts->net);
if (status)
return status;
rndis_opts->bound = true;
}
#endif
us = usb_gstrings_attach(cdev, rndis_strings,
ARRAY_SIZE(rndis_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
rndis_control_intf.iInterface = us[0].id;
rndis_data_intf.iInterface = us[1].id;
rndis_iad_descriptor.iFunction = us[2].id;
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@ -741,10 +782,12 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
rndis->port.open = rndis_open;
rndis->port.close = rndis_close;
#ifdef USB_FRNDIS_INCLUDED
status = rndis_register(rndis_response_available, rndis);
if (status < 0)
goto fail;
rndis->config = status;
#endif
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
@ -787,15 +830,15 @@ fail:
return status;
}
#ifdef USB_FRNDIS_INCLUDED
static void
rndis_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rndis *rndis = func_to_rndis(f);
rndis_deregister(rndis->config);
rndis_exit();
rndis_string_defs[0].id = 0;
usb_free_all_descriptors(f);
kfree(rndis->notify_req->buf);
@ -804,13 +847,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
kfree(rndis);
}
/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{
/* everything else is *presumably* fine */
return true;
}
int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer, struct eth_dev *dev)
@ -818,24 +854,6 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct f_rndis *rndis;
int status;
if (!can_support_rndis(c) || !ethaddr)
return -EINVAL;
if (rndis_string_defs[0].id == 0) {
/* ... and setup RNDIS itself */
status = rndis_init();
if (status < 0)
return status;
status = usb_string_ids_tab(c->cdev, rndis_string_defs);
if (status)
return status;
rndis_control_intf.iInterface = rndis_string_defs[0].id;
rndis_data_intf.iInterface = rndis_string_defs[1].id;
rndis_iad_descriptor.iFunction = rndis_string_defs[2].id;
}
/* allocate and initialize one new instance */
status = -ENOMEM;
rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
@ -856,19 +874,178 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
rndis->port.unwrap = rndis_rm_hdr;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;
/* descriptors are per-instance copies */
rndis->port.func.bind = rndis_bind;
rndis->port.func.unbind = rndis_old_unbind;
rndis->port.func.set_alt = rndis_set_alt;
rndis->port.func.setup = rndis_setup;
rndis->port.func.disable = rndis_disable;
status = usb_add_function(c, &rndis->port.func);
if (status)
kfree(rndis);
fail:
return status;
}
#else
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
{
struct f_rndis_opts *opts;
opts = container_of(f, struct f_rndis_opts, func_inst);
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
opts->borrowed_net = opts->bound = true;
opts->net = net;
}
EXPORT_SYMBOL(rndis_borrow_net);
static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_rndis_opts,
func_inst.group);
}
/* f_rndis_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(rndis);
/* f_rndis_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(rndis);
/* f_rndis_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(rndis);
/* f_rndis_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis);
/* f_rndis_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis);
static struct configfs_attribute *rndis_attrs[] = {
&f_rndis_opts_dev_addr.attr,
&f_rndis_opts_host_addr.attr,
&f_rndis_opts_qmult.attr,
&f_rndis_opts_ifname.attr,
NULL,
};
static struct config_item_type rndis_func_type = {
.ct_item_ops = &rndis_item_ops,
.ct_attrs = rndis_attrs,
.ct_owner = THIS_MODULE,
};
static void rndis_free_inst(struct usb_function_instance *f)
{
struct f_rndis_opts *opts;
opts = container_of(f, struct f_rndis_opts, func_inst);
if (!opts->borrowed_net) {
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
}
kfree(opts);
}
static struct usb_function_instance *rndis_alloc_inst(void)
{
struct f_rndis_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = rndis_free_inst;
opts->net = gether_setup_default();
if (IS_ERR(opts->net))
return ERR_CAST(opts->net);
config_group_init_type_name(&opts->func_inst.group, "",
&rndis_func_type);
return &opts->func_inst;
}
static void rndis_free(struct usb_function *f)
{
struct f_rndis *rndis;
struct f_rndis_opts *opts;
rndis = func_to_rndis(f);
rndis_deregister(rndis->config);
opts = container_of(f->fi, struct f_rndis_opts, func_inst);
kfree(rndis);
mutex_lock(&opts->lock);
opts->refcnt--;
mutex_unlock(&opts->lock);
}
static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rndis *rndis = func_to_rndis(f);
usb_free_all_descriptors(f);
kfree(rndis->notify_req->buf);
usb_ep_free_request(rndis->notify, rndis->notify_req);
}
static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
{
struct f_rndis *rndis;
struct f_rndis_opts *opts;
int status;
/* allocate and initialize one new instance */
rndis = kzalloc(sizeof(*rndis), GFP_KERNEL);
if (!rndis)
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_rndis_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
gether_get_host_addr_u8(opts->net, rndis->ethaddr);
rndis->vendorID = opts->vendor_id;
rndis->manufacturer = opts->manufacturer;
rndis->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
/* RNDIS activates when the host changes this filter */
rndis->port.cdc_filter = 0;
/* RNDIS has special (and complex) framing */
rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
rndis->port.func.name = "rndis";
/* descriptors are per-instance copies */
rndis->port.func.bind = rndis_bind;
rndis->port.func.unbind = rndis_unbind;
rndis->port.func.set_alt = rndis_set_alt;
rndis->port.func.setup = rndis_setup;
rndis->port.func.disable = rndis_disable;
rndis->port.func.free_func = rndis_free;
status = usb_add_function(c, &rndis->port.func);
if (status) {
status = rndis_register(rndis_response_available, rndis);
if (status < 0) {
kfree(rndis);
fail:
rndis_exit();
return ERR_PTR(status);
}
return status;
rndis->config = status;
return &rndis->port.func;
}
DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");
#endif

View File

@ -12,11 +12,13 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>
#include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_gether.h"
/*
* This function packages a simple "CDC Subset" Ethernet port with no real
@ -295,9 +297,40 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_gether *geth = func_to_geth(f);
struct usb_string *us;
int status;
struct usb_ep *ep;
#ifndef USB_FSUBSET_INCLUDED
struct f_gether_opts *gether_opts;
gether_opts = container_of(f->fi, struct f_gether_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to gether_opts->bound access
*/
if (!gether_opts->bound) {
mutex_lock(&gether_opts->lock);
gether_set_gadget(gether_opts->net, cdev->gadget);
status = gether_register_netdev(gether_opts->net);
mutex_unlock(&gether_opts->lock);
if (status)
return status;
gether_opts->bound = true;
}
#endif
us = usb_gstrings_attach(cdev, geth_strings,
ARRAY_SIZE(geth_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
subset_data_intf.iInterface = us[0].id;
ether_desc.iMACAddress = us[1].id;
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@ -360,8 +393,10 @@ fail:
return status;
}
#ifdef USB_FSUBSET_INCLUDED
static void
geth_unbind(struct usb_configuration *c, struct usb_function *f)
geth_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
geth_string_defs[0].id = 0;
usb_free_all_descriptors(f);
@ -387,18 +422,6 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct f_gether *geth;
int status;
if (!ethaddr)
return -EINVAL;
/* maybe allocate device-global string IDs */
if (geth_string_defs[0].id == 0) {
status = usb_string_ids_tab(c->cdev, geth_string_defs);
if (status < 0)
return status;
subset_data_intf.iInterface = geth_string_defs[0].id;
ether_desc.iMACAddress = geth_string_defs[1].id;
}
/* allocate and initialize one new instance */
geth = kzalloc(sizeof *geth, GFP_KERNEL);
if (!geth)
@ -412,9 +435,8 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset";
geth->port.func.strings = geth_strings;
geth->port.func.bind = geth_bind;
geth->port.func.unbind = geth_unbind;
geth->port.func.unbind = geth_old_unbind;
geth->port.func.set_alt = geth_set_alt;
geth->port.func.disable = geth_disable;
@ -423,3 +445,130 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
kfree(geth);
return status;
}
#else
static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_gether_opts,
func_inst.group);
}
/* f_gether_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(gether);
/* f_gether_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(gether);
/* f_gether_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(gether);
/* f_gether_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(gether);
/* f_gether_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(gether);
static struct configfs_attribute *gether_attrs[] = {
&f_gether_opts_dev_addr.attr,
&f_gether_opts_host_addr.attr,
&f_gether_opts_qmult.attr,
&f_gether_opts_ifname.attr,
NULL,
};
static struct config_item_type gether_func_type = {
.ct_item_ops = &gether_item_ops,
.ct_attrs = gether_attrs,
.ct_owner = THIS_MODULE,
};
static void geth_free_inst(struct usb_function_instance *f)
{
struct f_gether_opts *opts;
opts = container_of(f, struct f_gether_opts, func_inst);
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
kfree(opts);
}
static struct usb_function_instance *geth_alloc_inst(void)
{
struct f_gether_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = geth_free_inst;
opts->net = gether_setup_default();
if (IS_ERR(opts->net))
return ERR_CAST(opts->net);
config_group_init_type_name(&opts->func_inst.group, "",
&gether_func_type);
return &opts->func_inst;
}
static void geth_free(struct usb_function *f)
{
struct f_gether *eth;
eth = func_to_geth(f);
kfree(eth);
}
static void geth_unbind(struct usb_configuration *c, struct usb_function *f)
{
geth_string_defs[0].id = 0;
usb_free_all_descriptors(f);
}
static struct usb_function *geth_alloc(struct usb_function_instance *fi)
{
struct f_gether *geth;
struct f_gether_opts *opts;
int status;
/* allocate and initialize one new instance */
geth = kzalloc(sizeof(*geth), GFP_KERNEL);
if (!geth)
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_gether_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
/* export host's Ethernet address in CDC format */
status = gether_get_host_addr_cdc(opts->net, geth->ethaddr,
sizeof(geth->ethaddr));
if (status < 12) {
kfree(geth);
mutex_unlock(&opts->lock);
return ERR_PTR(-EINVAL);
}
geth_string_defs[1].s = geth->ethaddr;
geth->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset";
geth->port.func.bind = geth_bind;
geth->port.func.unbind = geth_unbind;
geth->port.func.set_alt = geth_set_alt;
geth->port.func.disable = geth_disable;
geth->port.func.free_func = geth_free;
return &geth->port.func;
}
DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");
#endif

View File

@ -90,6 +90,7 @@ struct uac2_req {
};
struct uac2_rtd_params {
struct snd_uac2_chip *uac2; /* parent chip */
bool ep_enabled; /* if the ep is enabled */
/* Size of the ring buffer */
size_t dma_bytes;
@ -168,18 +169,6 @@ struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p)
return container_of(p, struct snd_uac2_chip, pdev);
}
static inline
struct snd_uac2_chip *prm_to_uac2(struct uac2_rtd_params *r)
{
struct snd_uac2_chip *uac2 = container_of(r,
struct snd_uac2_chip, c_prm);
if (&uac2->c_prm != r)
uac2 = container_of(r, struct snd_uac2_chip, p_prm);
return uac2;
}
static inline
uint num_channels(uint chanmask)
{
@ -204,7 +193,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
struct uac2_req *ur = req->context;
struct snd_pcm_substream *substream;
struct uac2_rtd_params *prm = ur->pp;
struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
struct snd_uac2_chip *uac2 = prm->uac2;
/* i/f shutting down */
if (!prm->ep_enabled)
@ -894,7 +883,7 @@ struct cntrl_range_lay3 {
static inline void
free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
{
struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
struct snd_uac2_chip *uac2 = prm->uac2;
int i;
prm->ep_enabled = false;
@ -970,6 +959,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
}
agdev->in_ep->driver_data = agdev;
uac2->p_prm.uac2 = uac2;
uac2->c_prm.uac2 = uac2;
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;

View File

@ -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[] = {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,253 @@
/*
* Faraday FOTG210 USB OTG controller
*
* Copyright (C) 2013 Faraday Technology Corporation
* Author: Yuan-Hsin Chen <yhchen@faraday-tech.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#define FOTG210_MAX_NUM_EP 5 /* ep0...ep4 */
#define FOTG210_MAX_FIFO_NUM 4 /* fifo0...fifo4 */
/* Global Mask of HC/OTG/DEV interrupt Register(0xC4) */
#define FOTG210_GMIR 0xC4
#define GMIR_INT_POLARITY 0x8 /*Active High*/
#define GMIR_MHC_INT 0x4
#define GMIR_MOTG_INT 0x2
#define GMIR_MDEV_INT 0x1
/* Device Main Control Register(0x100) */
#define FOTG210_DMCR 0x100
#define DMCR_HS_EN (1 << 6)
#define DMCR_CHIP_EN (1 << 5)
#define DMCR_SFRST (1 << 4)
#define DMCR_GOSUSP (1 << 3)
#define DMCR_GLINT_EN (1 << 2)
#define DMCR_HALF_SPEED (1 << 1)
#define DMCR_CAP_RMWAKUP (1 << 0)
/* Device Address Register(0x104) */
#define FOTG210_DAR 0x104
#define DAR_AFT_CONF (1 << 7)
/* Device Test Register(0x108) */
#define FOTG210_DTR 0x108
#define DTR_TST_CLRFF (1 << 0)
/* PHY Test Mode Selector register(0x114) */
#define FOTG210_PHYTMSR 0x114
#define PHYTMSR_TST_PKT (1 << 4)
#define PHYTMSR_TST_SE0NAK (1 << 3)
#define PHYTMSR_TST_KSTA (1 << 2)
#define PHYTMSR_TST_JSTA (1 << 1)
#define PHYTMSR_UNPLUG (1 << 0)
/* Cx configuration and FIFO Empty Status register(0x120) */
#define FOTG210_DCFESR 0x120
#define DCFESR_FIFO_EMPTY(fifo) (1 << 8 << (fifo))
#define DCFESR_CX_EMP (1 << 5)
#define DCFESR_CX_CLR (1 << 3)
#define DCFESR_CX_STL (1 << 2)
#define DCFESR_TST_PKDONE (1 << 1)
#define DCFESR_CX_DONE (1 << 0)
/* Device IDLE Counter Register(0x124) */
#define FOTG210_DICR 0x124
/* Device Mask of Interrupt Group Register (0x130) */
#define FOTG210_DMIGR 0x130
#define DMIGR_MINT_G0 (1 << 0)
/* Device Mask of Interrupt Source Group 0(0x134) */
#define FOTG210_DMISGR0 0x134
#define DMISGR0_MCX_COMEND (1 << 3)
#define DMISGR0_MCX_OUT_INT (1 << 2)
#define DMISGR0_MCX_IN_INT (1 << 1)
#define DMISGR0_MCX_SETUP_INT (1 << 0)
/* Device Mask of Interrupt Source Group 1 Register(0x138)*/
#define FOTG210_DMISGR1 0x138
#define DMISGR1_MF3_IN_INT (1 << 19)
#define DMISGR1_MF2_IN_INT (1 << 18)
#define DMISGR1_MF1_IN_INT (1 << 17)
#define DMISGR1_MF0_IN_INT (1 << 16)
#define DMISGR1_MF_IN_INT(fifo) (1 << (16 + (fifo)))
#define DMISGR1_MF3_SPK_INT (1 << 7)
#define DMISGR1_MF3_OUT_INT (1 << 6)
#define DMISGR1_MF2_SPK_INT (1 << 5)
#define DMISGR1_MF2_OUT_INT (1 << 4)
#define DMISGR1_MF1_SPK_INT (1 << 3)
#define DMISGR1_MF1_OUT_INT (1 << 2)
#define DMISGR1_MF0_SPK_INT (1 << 1)
#define DMISGR1_MF0_OUT_INT (1 << 0)
#define DMISGR1_MF_OUTSPK_INT(fifo) (0x3 << (fifo) * 2)
/* Device Mask of Interrupt Source Group 2 Register (0x13C) */
#define FOTG210_DMISGR2 0x13C
#define DMISGR2_MDMA_ERROR (1 << 8)
#define DMISGR2_MDMA_CMPLT (1 << 7)
/* Device Interrupt group Register (0x140) */
#define FOTG210_DIGR 0x140
#define DIGR_INT_G2 (1 << 2)
#define DIGR_INT_G1 (1 << 1)
#define DIGR_INT_G0 (1 << 0)
/* Device Interrupt Source Group 0 Register (0x144) */
#define FOTG210_DISGR0 0x144
#define DISGR0_CX_COMABT_INT (1 << 5)
#define DISGR0_CX_COMFAIL_INT (1 << 4)
#define DISGR0_CX_COMEND_INT (1 << 3)
#define DISGR0_CX_OUT_INT (1 << 2)
#define DISGR0_CX_IN_INT (1 << 1)
#define DISGR0_CX_SETUP_INT (1 << 0)
/* Device Interrupt Source Group 1 Register (0x148) */
#define FOTG210_DISGR1 0x148
#define DISGR1_OUT_INT(fifo) (1 << ((fifo) * 2))
#define DISGR1_SPK_INT(fifo) (1 << 1 << ((fifo) * 2))
#define DISGR1_IN_INT(fifo) (1 << 16 << (fifo))
/* Device Interrupt Source Group 2 Register (0x14C) */
#define FOTG210_DISGR2 0x14C
#define DISGR2_DMA_ERROR (1 << 8)
#define DISGR2_DMA_CMPLT (1 << 7)
#define DISGR2_RX0BYTE_INT (1 << 6)
#define DISGR2_TX0BYTE_INT (1 << 5)
#define DISGR2_ISO_SEQ_ABORT_INT (1 << 4)
#define DISGR2_ISO_SEQ_ERR_INT (1 << 3)
#define DISGR2_RESM_INT (1 << 2)
#define DISGR2_SUSP_INT (1 << 1)
#define DISGR2_USBRST_INT (1 << 0)
/* Device Receive Zero-Length Data Packet Register (0x150)*/
#define FOTG210_RX0BYTE 0x150
#define RX0BYTE_EP8 (1 << 7)
#define RX0BYTE_EP7 (1 << 6)
#define RX0BYTE_EP6 (1 << 5)
#define RX0BYTE_EP5 (1 << 4)
#define RX0BYTE_EP4 (1 << 3)
#define RX0BYTE_EP3 (1 << 2)
#define RX0BYTE_EP2 (1 << 1)
#define RX0BYTE_EP1 (1 << 0)
/* Device Transfer Zero-Length Data Packet Register (0x154)*/
#define FOTG210_TX0BYTE 0x154
#define TX0BYTE_EP8 (1 << 7)
#define TX0BYTE_EP7 (1 << 6)
#define TX0BYTE_EP6 (1 << 5)
#define TX0BYTE_EP5 (1 << 4)
#define TX0BYTE_EP4 (1 << 3)
#define TX0BYTE_EP3 (1 << 2)
#define TX0BYTE_EP2 (1 << 1)
#define TX0BYTE_EP1 (1 << 0)
/* Device IN Endpoint x MaxPacketSize Register(0x160+4*(x-1)) */
#define FOTG210_INEPMPSR(ep) (0x160 + 4 * ((ep) - 1))
#define INOUTEPMPSR_MPS(mps) ((mps) & 0x2FF)
#define INOUTEPMPSR_STL_EP (1 << 11)
#define INOUTEPMPSR_RESET_TSEQ (1 << 12)
/* Device OUT Endpoint x MaxPacketSize Register(0x180+4*(x-1)) */
#define FOTG210_OUTEPMPSR(ep) (0x180 + 4 * ((ep) - 1))
/* Device Endpoint 1~4 Map Register (0x1A0) */
#define FOTG210_EPMAP 0x1A0
#define EPMAP_FIFONO(ep, dir) \
((((ep) - 1) << ((ep) - 1) * 8) << ((dir) ? 0 : 4))
#define EPMAP_FIFONOMSK(ep, dir) \
((3 << ((ep) - 1) * 8) << ((dir) ? 0 : 4))
/* Device FIFO Map Register (0x1A8) */
#define FOTG210_FIFOMAP 0x1A8
#define FIFOMAP_DIROUT(fifo) (0x0 << 4 << (fifo) * 8)
#define FIFOMAP_DIRIN(fifo) (0x1 << 4 << (fifo) * 8)
#define FIFOMAP_BIDIR(fifo) (0x2 << 4 << (fifo) * 8)
#define FIFOMAP_NA(fifo) (0x3 << 4 << (fifo) * 8)
#define FIFOMAP_EPNO(ep) ((ep) << ((ep) - 1) * 8)
#define FIFOMAP_EPNOMSK(ep) (0xF << ((ep) - 1) * 8)
/* Device FIFO Confuguration Register (0x1AC) */
#define FOTG210_FIFOCF 0x1AC
#define FIFOCF_TYPE(type, fifo) ((type) << (fifo) * 8)
#define FIFOCF_BLK_SIN(fifo) (0x0 << (fifo) * 8 << 2)
#define FIFOCF_BLK_DUB(fifo) (0x1 << (fifo) * 8 << 2)
#define FIFOCF_BLK_TRI(fifo) (0x2 << (fifo) * 8 << 2)
#define FIFOCF_BLKSZ_512(fifo) (0x0 << (fifo) * 8 << 4)
#define FIFOCF_BLKSZ_1024(fifo) (0x1 << (fifo) * 8 << 4)
#define FIFOCF_FIFO_EN(fifo) (0x1 << (fifo) * 8 << 5)
/* Device FIFO n Instruction and Byte Count Register (0x1B0+4*n) */
#define FOTG210_FIBCR(fifo) (0x1B0 + (fifo) * 4)
#define FIBCR_BCFX 0x7FF
#define FIBCR_FFRST (1 << 12)
/* Device DMA Target FIFO Number Register (0x1C0) */
#define FOTG210_DMATFNR 0x1C0
#define DMATFNR_ACC_CXF (1 << 4)
#define DMATFNR_ACC_F3 (1 << 3)
#define DMATFNR_ACC_F2 (1 << 2)
#define DMATFNR_ACC_F1 (1 << 1)
#define DMATFNR_ACC_F0 (1 << 0)
#define DMATFNR_ACC_FN(fifo) (1 << (fifo))
#define DMATFNR_DISDMA 0
/* Device DMA Controller Parameter setting 1 Register (0x1C8) */
#define FOTG210_DMACPSR1 0x1C8
#define DMACPSR1_DMA_LEN(len) (((len) & 0xFFFF) << 8)
#define DMACPSR1_DMA_ABORT (1 << 3)
#define DMACPSR1_DMA_TYPE(dir_in) (((dir_in) ? 1 : 0) << 1)
#define DMACPSR1_DMA_START (1 << 0)
/* Device DMA Controller Parameter setting 2 Register (0x1CC) */
#define FOTG210_DMACPSR2 0x1CC
/* Device DMA Controller Parameter setting 3 Register (0x1CC) */
#define FOTG210_CXPORT 0x1D0
struct fotg210_request {
struct usb_request req;
struct list_head queue;
};
struct fotg210_ep {
struct usb_ep ep;
struct fotg210_udc *fotg210;
struct list_head queue;
unsigned stall:1;
unsigned wedged:1;
unsigned use_dma:1;
unsigned char epnum;
unsigned char type;
unsigned char dir_in;
unsigned int maxp;
const struct usb_endpoint_descriptor *desc;
};
struct fotg210_udc {
spinlock_t lock; /* protect the struct */
void __iomem *reg;
unsigned long irq_trigger;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct fotg210_ep *ep[FOTG210_MAX_NUM_EP];
struct usb_request *ep0_req; /* for internal request */
__le16 ep0_data;
u8 ep0_dir; /* 0/0x80 out/in */
u8 reenum; /* if re-enumeration */
};
#define gadget_to_fotg210(g) container_of((g), struct fotg210_udc, gadget)

View File

@ -2589,7 +2589,7 @@ static int qe_udc_probe(struct platform_device *ofdev)
if (ret)
goto err6;
dev_set_drvdata(&ofdev->dev, udc);
platform_set_drvdata(ofdev, udc);
dev_info(udc->dev,
"%s USB controller initialized as device\n",
(udc->soc_type == PORT_QE) ? "QE" : "CPM");
@ -2640,7 +2640,7 @@ static int qe_udc_resume(struct platform_device *dev)
static int qe_udc_remove(struct platform_device *ofdev)
{
struct qe_udc *udc = dev_get_drvdata(&ofdev->dev);
struct qe_udc *udc = platform_get_drvdata(ofdev);
struct qe_ep *ep;
unsigned int size;
DECLARE_COMPLETION(done);

View File

@ -1347,7 +1347,7 @@ static const struct usb_gadget_ops fusb300_gadget_ops = {
static int __exit fusb300_remove(struct platform_device *pdev)
{
struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev);
struct fusb300 *fusb300 = platform_get_drvdata(pdev);
usb_del_gadget_udc(&fusb300->gadget);
iounmap(fusb300->reg);
@ -1416,7 +1416,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
spin_lock_init(&fusb300->lock);
dev_set_drvdata(&pdev->dev, fusb300);
platform_set_drvdata(pdev, fusb300);
fusb300->gadget.ops = &fusb300_gadget_ops;

View File

@ -28,15 +28,18 @@
# define USB_ETH_RNDIS y
# endif
#define USBF_ECM_INCLUDED
# include "f_ecm.c"
#define USB_FSUBSET_INCLUDED
# include "f_subset.c"
# ifdef USB_ETH_RNDIS
# define USB_FRNDIS_INCLUDED
# include "f_rndis.c"
# include "rndis.c"
# include "rndis.h"
# endif
# include "u_ether.c"
# include "u_ether.h"
static u8 gfs_hostaddr[ETH_ALEN];
static u8 gfs_host_mac[ETH_ALEN];
static struct eth_dev *the_dev;
# ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
@ -45,7 +48,7 @@ static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
#else
# define the_dev NULL
# define gether_cleanup(dev) do { } while (0)
# define gfs_hostaddr NULL
# define gfs_host_mac NULL
struct eth_dev;
#endif
@ -73,6 +76,8 @@ struct gfs_ffs_obj {
USB_GADGET_COMPOSITE_OPTIONS();
USB_ETHERNET_MODULE_PARAMETERS();
static struct usb_device_descriptor gfs_dev_desc = {
.bLength = sizeof gfs_dev_desc,
.bDescriptorType = USB_DT_DEVICE,
@ -350,7 +355,8 @@ static int gfs_bind(struct usb_composite_dev *cdev)
if (missing_funcs)
return -ENODEV;
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, gfs_host_mac,
qmult);
#endif
if (IS_ERR(the_dev)) {
ret = PTR_ERR(the_dev);
@ -446,7 +452,7 @@ static int gfs_do_config(struct usb_configuration *c)
}
if (gc->eth) {
ret = gc->eth(c, gfs_hostaddr, the_dev);
ret = gc->eth(c, gfs_host_mac, the_dev);
if (unlikely(ret < 0))
return ret;
}

View File

@ -1533,7 +1533,7 @@ static const struct usb_gadget_ops m66592_gadget_ops = {
static int __exit m66592_remove(struct platform_device *pdev)
{
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
struct m66592 *m66592 = platform_get_drvdata(pdev);
usb_del_gadget_udc(&m66592->gadget);
@ -1602,7 +1602,7 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
spin_lock_init(&m66592->lock);
dev_set_drvdata(&pdev->dev, m66592);
platform_set_drvdata(pdev, m66592);
m66592->gadget.ops = &m66592_gadget_ops;
m66592->gadget.max_speed = USB_SPEED_HIGH;

View File

@ -43,16 +43,19 @@ MODULE_LICENSE("GPL");
*/
#include "f_mass_storage.c"
#define USBF_ECM_INCLUDED
#include "f_ecm.c"
#include "f_subset.c"
#ifdef USB_ETH_RNDIS
# define USB_FRNDIS_INCLUDED
# include "f_rndis.c"
# include "rndis.c"
# include "rndis.h"
#endif
#include "u_ether.c"
#include "u_ether.h"
USB_GADGET_COMPOSITE_OPTIONS();
USB_ETHERNET_MODULE_PARAMETERS();
/***************************** Device Descriptor ****************************/
#define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */
@ -133,7 +136,7 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN];
static u8 host_mac[ETH_ALEN];
static struct usb_function_instance *fi_acm;
static struct eth_dev *the_dev;
@ -152,7 +155,7 @@ static __init int rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
ret = rndis_bind_config(c, hostaddr, the_dev);
ret = rndis_bind_config(c, host_mac, the_dev);
if (ret < 0)
return ret;
@ -216,7 +219,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
ret = ecm_bind_config(c, hostaddr, the_dev);
ret = ecm_bind_config(c, host_mac, the_dev);
if (ret < 0)
return ret;
@ -280,7 +283,8 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
}
/* set up network link layer */
the_dev = gether_setup(cdev->gadget, hostaddr);
the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac,
qmult);
if (IS_ERR(the_dev))
return PTR_ERR(the_dev);

View File

@ -1786,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev)
clk_put(u3d->clk);
platform_set_drvdata(dev, NULL);
kfree(u3d);
return 0;
@ -1997,7 +1995,6 @@ err_map_cap_regs:
err_get_cap_regs:
err_get_clk:
clk_put(u3d->clk);
platform_set_drvdata(dev, NULL);
kfree(u3d);
err_alloc_private:
err_pdata:
@ -2053,7 +2050,7 @@ static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
static void mv_u3d_shutdown(struct platform_device *dev)
{
struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
struct mv_u3d *u3d = platform_get_drvdata(dev);
u32 tmp;
tmp = ioread32(&u3d->op_regs->usbcmd);

View File

@ -24,23 +24,12 @@
#include <linux/usb/composite.h>
#include "u_ether.h"
#include "u_ncm.h"
#define DRIVER_DESC "NCM Gadget"
/*-------------------------------------------------------------------------*/
/*
* 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_ncm.c"
#include "u_ether.c"
/*-------------------------------------------------------------------------*/
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures.
*/
@ -54,6 +43,8 @@
/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();
USB_ETHERNET_MODULE_PARAMETERS();
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
@ -111,13 +102,15 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL,
};
struct eth_dev *the_dev;
static u8 hostaddr[ETH_ALEN];
static struct usb_function_instance *f_ncm_inst;
static struct usb_function *f_ncm;
/*-------------------------------------------------------------------------*/
static int __init ncm_do_config(struct usb_configuration *c)
{
int status;
/* FIXME alloc iConfiguration string, set it in c->strings */
if (gadget_is_otg(c->cdev->gadget)) {
@ -125,7 +118,19 @@ static int __init ncm_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
return ncm_bind_config(c, hostaddr, the_dev);
f_ncm = usb_get_function(f_ncm_inst);
if (IS_ERR(f_ncm)) {
status = PTR_ERR(f_ncm);
return status;
}
status = usb_add_function(c, f_ncm);
if (status < 0) {
usb_put_function(f_ncm);
return status;
}
return 0;
}
static struct usb_configuration ncm_config_driver = {
@ -141,12 +146,20 @@ static struct usb_configuration ncm_config_driver = {
static int __init gncm_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct f_ncm_opts *ncm_opts;
int status;
/* set up network link layer */
the_dev = gether_setup(cdev->gadget, hostaddr);
if (IS_ERR(the_dev))
return PTR_ERR(the_dev);
f_ncm_inst = usb_get_function_instance("ncm");
if (IS_ERR(f_ncm_inst))
return PTR_ERR(f_ncm_inst);
ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst);
gether_set_qmult(ncm_opts->net, qmult);
if (!gether_set_host_addr(ncm_opts->net, host_addr))
pr_info("using host ethernet address: %s", host_addr);
if (!gether_set_dev_addr(ncm_opts->net, dev_addr))
pr_info("using self ethernet address: %s", dev_addr);
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@ -169,13 +182,16 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
return 0;
fail:
gether_cleanup(the_dev);
usb_put_function_instance(f_ncm_inst);
return status;
}
static int __exit gncm_unbind(struct usb_composite_dev *cdev)
{
gether_cleanup(the_dev);
if (!IS_ERR_OR_NULL(f_ncm))
usb_put_function(f_ncm);
if (!IS_ERR_OR_NULL(f_ncm_inst))
usb_put_function_instance(f_ncm_inst);
return 0;
}

View File

@ -16,11 +16,13 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include "u_serial.h"
#include "u_ether.h"
#include "u_phonet.h"
#include "u_ecm.h"
#include "gadget_chips.h"
/* Defines */
@ -28,24 +30,10 @@
#define NOKIA_VERSION_NUM 0x0211
#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
/*-------------------------------------------------------------------------*/
/*
* 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.
*/
#define USBF_OBEX_INCLUDED
#include "f_ecm.c"
#include "f_obex.c"
#include "f_phonet.c"
#include "u_ether.c"
/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();
USB_ETHERNET_MODULE_PARAMETERS();
#define NOKIA_VENDOR_ID 0x0421 /* Nokia */
#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
@ -98,16 +86,15 @@ MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------------*/
static struct usb_function *f_acm_cfg1;
static struct usb_function *f_acm_cfg2;
static u8 hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
static struct usb_function *f_ecm_cfg1;
static struct usb_function *f_ecm_cfg2;
static struct usb_function *f_obex1_cfg1;
static struct usb_function *f_obex2_cfg1;
static struct usb_function *f_obex1_cfg2;
static struct usb_function *f_obex2_cfg2;
static struct usb_function *f_phonet_cfg1;
static struct usb_function *f_phonet_cfg2;
enum {
TTY_PORT_OBEX0,
TTY_PORT_OBEX1,
TTY_PORTS_MAX,
};
static unsigned char tty_lines[TTY_PORTS_MAX];
static struct usb_configuration nokia_config_500ma_driver = {
.label = "Bus Powered",
@ -126,47 +113,114 @@ static struct usb_configuration nokia_config_100ma_driver = {
};
static struct usb_function_instance *fi_acm;
static struct usb_function_instance *fi_ecm;
static struct usb_function_instance *fi_obex1;
static struct usb_function_instance *fi_obex2;
static struct usb_function_instance *fi_phonet;
static int __init nokia_bind_config(struct usb_configuration *c)
{
struct usb_function *f_acm;
struct usb_function *f_phonet = NULL;
struct usb_function *f_obex1 = NULL;
struct usb_function *f_ecm;
struct usb_function *f_obex2 = NULL;
int status = 0;
int obex1_stat = 0;
int obex2_stat = 0;
int phonet_stat = 0;
status = phonet_bind_config(c);
if (status)
printk(KERN_DEBUG "could not bind phonet config\n");
if (!IS_ERR(fi_phonet)) {
f_phonet = usb_get_function(fi_phonet);
if (IS_ERR(f_phonet))
pr_debug("could not get phonet function\n");
}
status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX0]);
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
if (!IS_ERR(fi_obex1)) {
f_obex1 = usb_get_function(fi_obex1);
if (IS_ERR(f_obex1))
pr_debug("could not get obex function 0\n");
}
status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX1]);
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
if (!IS_ERR(fi_obex2)) {
f_obex2 = usb_get_function(fi_obex2);
if (IS_ERR(f_obex2))
pr_debug("could not get obex function 1\n");
}
f_acm = usb_get_function(fi_acm);
if (IS_ERR(f_acm))
return PTR_ERR(f_acm);
if (IS_ERR(f_acm)) {
status = PTR_ERR(f_acm);
goto err_get_acm;
}
f_ecm = usb_get_function(fi_ecm);
if (IS_ERR(f_ecm)) {
status = PTR_ERR(f_ecm);
goto err_get_ecm;
}
if (!IS_ERR_OR_NULL(f_phonet)) {
phonet_stat = usb_add_function(c, f_phonet);
if (phonet_stat)
pr_debug("could not add phonet function\n");
}
if (!IS_ERR_OR_NULL(f_obex1)) {
obex1_stat = usb_add_function(c, f_obex1);
if (obex1_stat)
pr_debug("could not add obex function 0\n");
}
if (!IS_ERR_OR_NULL(f_obex2)) {
obex2_stat = usb_add_function(c, f_obex2);
if (obex2_stat)
pr_debug("could not add obex function 1\n");
}
status = usb_add_function(c, f_acm);
if (status)
goto err_conf;
status = ecm_bind_config(c, hostaddr, the_dev);
status = usb_add_function(c, f_ecm);
if (status) {
pr_debug("could not bind ecm config %d\n", status);
goto err_ecm;
}
if (c == &nokia_config_500ma_driver)
if (c == &nokia_config_500ma_driver) {
f_acm_cfg1 = f_acm;
else
f_ecm_cfg1 = f_ecm;
f_phonet_cfg1 = f_phonet;
f_obex1_cfg1 = f_obex1;
f_obex2_cfg1 = f_obex2;
} else {
f_acm_cfg2 = f_acm;
f_ecm_cfg2 = f_ecm;
f_phonet_cfg2 = f_phonet;
f_obex1_cfg2 = f_obex1;
f_obex2_cfg2 = f_obex2;
}
return status;
err_ecm:
usb_remove_function(c, f_acm);
err_conf:
if (!obex2_stat)
usb_remove_function(c, f_obex2);
if (!obex1_stat)
usb_remove_function(c, f_obex1);
if (!phonet_stat)
usb_remove_function(c, f_phonet);
usb_put_function(f_ecm);
err_get_ecm:
usb_put_function(f_acm);
err_get_acm:
if (!IS_ERR_OR_NULL(f_obex2))
usb_put_function(f_obex2);
if (!IS_ERR_OR_NULL(f_obex1))
usb_put_function(f_obex1);
if (!IS_ERR_OR_NULL(f_phonet))
usb_put_function(f_phonet);
return status;
}
@ -174,23 +228,6 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
int status;
int cur_line;
status = gphonet_setup(cdev->gadget);
if (status < 0)
goto err_phonet;
for (cur_line = 0; cur_line < TTY_PORTS_MAX; cur_line++) {
status = gserial_alloc_line(&tty_lines[cur_line]);
if (status)
goto err_ether;
}
the_dev = gether_setup(cdev->gadget, hostaddr);
if (IS_ERR(the_dev)) {
status = PTR_ERR(the_dev);
goto err_ether;
}
status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
@ -201,18 +238,40 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
nokia_config_500ma_driver.iConfiguration = status;
nokia_config_100ma_driver.iConfiguration = status;
if (!gadget_supports_altsettings(gadget))
if (!gadget_supports_altsettings(gadget)) {
status = -ENODEV;
goto err_usb;
}
fi_phonet = usb_get_function_instance("phonet");
if (IS_ERR(fi_phonet))
pr_debug("could not find phonet function\n");
fi_obex1 = usb_get_function_instance("obex");
if (IS_ERR(fi_obex1))
pr_debug("could not find obex function 1\n");
fi_obex2 = usb_get_function_instance("obex");
if (IS_ERR(fi_obex2))
pr_debug("could not find obex function 2\n");
fi_acm = usb_get_function_instance("acm");
if (IS_ERR(fi_acm))
goto err_usb;
if (IS_ERR(fi_acm)) {
status = PTR_ERR(fi_acm);
goto err_obex2_inst;
}
fi_ecm = usb_get_function_instance("ecm");
if (IS_ERR(fi_ecm)) {
status = PTR_ERR(fi_ecm);
goto err_acm_inst;
}
/* finally register the configuration */
status = usb_add_config(cdev, &nokia_config_500ma_driver,
nokia_bind_config);
if (status < 0)
goto err_acm_inst;
goto err_ecm_inst;
status = usb_add_config(cdev, &nokia_config_100ma_driver,
nokia_bind_config);
@ -226,33 +285,55 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
err_put_cfg1:
usb_put_function(f_acm_cfg1);
if (!IS_ERR_OR_NULL(f_obex1_cfg1))
usb_put_function(f_obex1_cfg1);
if (!IS_ERR_OR_NULL(f_obex2_cfg1))
usb_put_function(f_obex2_cfg1);
if (!IS_ERR_OR_NULL(f_phonet_cfg1))
usb_put_function(f_phonet_cfg1);
usb_put_function(f_ecm_cfg1);
err_ecm_inst:
usb_put_function_instance(fi_ecm);
err_acm_inst:
usb_put_function_instance(fi_acm);
err_obex2_inst:
if (!IS_ERR(fi_obex2))
usb_put_function_instance(fi_obex2);
if (!IS_ERR(fi_obex1))
usb_put_function_instance(fi_obex1);
if (!IS_ERR(fi_phonet))
usb_put_function_instance(fi_phonet);
err_usb:
gether_cleanup(the_dev);
err_ether:
cur_line--;
while (cur_line >= 0)
gserial_free_line(tty_lines[cur_line--]);
gphonet_cleanup();
err_phonet:
return status;
}
static int __exit nokia_unbind(struct usb_composite_dev *cdev)
{
int i;
if (!IS_ERR_OR_NULL(f_obex1_cfg2))
usb_put_function(f_obex1_cfg2);
if (!IS_ERR_OR_NULL(f_obex2_cfg2))
usb_put_function(f_obex2_cfg2);
if (!IS_ERR_OR_NULL(f_obex1_cfg1))
usb_put_function(f_obex1_cfg1);
if (!IS_ERR_OR_NULL(f_obex2_cfg1))
usb_put_function(f_obex2_cfg1);
if (!IS_ERR_OR_NULL(f_phonet_cfg1))
usb_put_function(f_phonet_cfg1);
if (!IS_ERR_OR_NULL(f_phonet_cfg2))
usb_put_function(f_phonet_cfg2);
usb_put_function(f_acm_cfg1);
usb_put_function(f_acm_cfg2);
usb_put_function(f_ecm_cfg1);
usb_put_function(f_ecm_cfg2);
usb_put_function_instance(fi_ecm);
if (!IS_ERR(fi_obex2))
usb_put_function_instance(fi_obex2);
if (!IS_ERR(fi_obex1))
usb_put_function_instance(fi_obex1);
if (!IS_ERR(fi_phonet))
usb_put_function_instance(fi_phonet);
usb_put_function_instance(fi_acm);
gphonet_cleanup();
for (i = 0; i < TTY_PORTS_MAX; i++)
gserial_free_line(tty_lines[i]);
gether_cleanup(the_dev);
return 0;
}

View File

@ -2505,7 +2505,6 @@ static int pxa_udc_remove(struct platform_device *_dev)
usb_put_phy(udc->transceiver);
udc->transceiver = NULL;
platform_set_drvdata(_dev, NULL);
the_controller = NULL;
clk_put(udc->clk);
iounmap(udc->regs);

View File

@ -1469,11 +1469,11 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
u16 savepipe;
u16 mask0;
spin_lock(&r8a66597->lock);
if (r8a66597_is_sudmac(r8a66597))
r8a66597_sudmac_irq(r8a66597);
spin_lock(&r8a66597->lock);
intsts0 = r8a66597_read(r8a66597, INTSTS0);
intenb0 = r8a66597_read(r8a66597, INTENB0);
@ -1822,7 +1822,7 @@ static const struct usb_gadget_ops r8a66597_gadget_ops = {
static int __exit r8a66597_remove(struct platform_device *pdev)
{
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
struct r8a66597 *r8a66597 = platform_get_drvdata(pdev);
usb_del_gadget_udc(&r8a66597->gadget);
del_timer_sync(&r8a66597->timer);
@ -1909,7 +1909,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
}
spin_lock_init(&r8a66597->lock);
dev_set_drvdata(&pdev->dev, r8a66597);
platform_set_drvdata(pdev, r8a66597);
r8a66597->pdata = pdev->dev.platform_data;
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;

View File

@ -761,6 +761,7 @@ int rndis_signal_connect(int configNr)
return rndis_indicate_status_msg(configNr,
RNDIS_STATUS_MEDIA_CONNECT);
}
EXPORT_SYMBOL(rndis_signal_connect);
int rndis_signal_disconnect(int configNr)
{
@ -769,6 +770,7 @@ int rndis_signal_disconnect(int configNr)
return rndis_indicate_status_msg(configNr,
RNDIS_STATUS_MEDIA_DISCONNECT);
}
EXPORT_SYMBOL(rndis_signal_disconnect);
void rndis_uninit(int configNr)
{
@ -783,11 +785,13 @@ void rndis_uninit(int configNr)
while ((buf = rndis_get_next_response(configNr, &length)))
rndis_free_response(configNr, buf);
}
EXPORT_SYMBOL(rndis_uninit);
void rndis_set_host_mac(int configNr, const u8 *addr)
{
rndis_per_dev_params[configNr].host_mac = addr;
}
EXPORT_SYMBOL(rndis_set_host_mac);
/*
* Message Parser
@ -870,6 +874,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
return -ENOTSUPP;
}
EXPORT_SYMBOL(rndis_msg_parser);
int rndis_register(void (*resp_avail)(void *v), void *v)
{
@ -891,6 +896,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v)
return -ENODEV;
}
EXPORT_SYMBOL(rndis_register);
void rndis_deregister(int configNr)
{
@ -899,6 +905,7 @@ void rndis_deregister(int configNr)
if (configNr >= RNDIS_MAX_CONFIGS) return;
rndis_per_dev_params[configNr].used = 0;
}
EXPORT_SYMBOL(rndis_deregister);
int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
{
@ -912,6 +919,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
return 0;
}
EXPORT_SYMBOL(rndis_set_param_dev);
int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
{
@ -924,6 +932,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
return 0;
}
EXPORT_SYMBOL(rndis_set_param_vendor);
int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
{
@ -935,6 +944,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
return 0;
}
EXPORT_SYMBOL(rndis_set_param_medium);
void rndis_add_hdr(struct sk_buff *skb)
{
@ -949,6 +959,7 @@ void rndis_add_hdr(struct sk_buff *skb)
header->DataOffset = cpu_to_le32(36);
header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
}
EXPORT_SYMBOL(rndis_add_hdr);
void rndis_free_response(int configNr, u8 *buf)
{
@ -965,6 +976,7 @@ void rndis_free_response(int configNr, u8 *buf)
}
}
}
EXPORT_SYMBOL(rndis_free_response);
u8 *rndis_get_next_response(int configNr, u32 *length)
{
@ -986,6 +998,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length)
return NULL;
}
EXPORT_SYMBOL(rndis_get_next_response);
static rndis_resp_t *rndis_add_response(int configNr, u32 length)
{
@ -1029,6 +1042,7 @@ int rndis_rm_hdr(struct gether *port,
skb_queue_tail(list, skb);
return 0;
}
EXPORT_SYMBOL(rndis_rm_hdr);
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
@ -1160,6 +1174,7 @@ int rndis_init(void)
return 0;
}
module_init(rndis_init);
void rndis_exit(void)
{
@ -1173,3 +1188,6 @@ void rndis_exit(void)
}
#endif
}
module_exit(rndis_exit);
MODULE_LICENSE("GPL");

View File

@ -16,6 +16,7 @@
#define _LINUX_RNDIS_H
#include <linux/rndis.h>
#include "u_ether.h"
#include "ndis.h"
#define RNDIS_MAXIMUM_FRAME_SIZE 1518
@ -216,7 +217,4 @@ int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);
extern void rndis_set_host_mac (int configNr, const u8 *addr);
int rndis_init(void);
void rndis_exit (void);
#endif /* _LINUX_RNDIS_H */

View File

@ -0,0 +1,36 @@
/*
* u_ecm.h
*
* Utility definitions for the ecm function
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef U_ECM_H
#define U_ECM_H
#include <linux/usb/composite.h>
struct f_ecm_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This is to protect the data from concurrent access by read/write
* and create symlink/remove symlink.
*/
struct mutex lock;
int refcnt;
};
#endif /* U_ECM_H */

View File

@ -0,0 +1,36 @@
/*
* u_eem.h
*
* Utility definitions for the eem function
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef U_EEM_H
#define U_EEM_H
#include <linux/usb/composite.h>
struct f_eem_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This is to protect the data from concurrent access by read/write
* and create symlink/remove symlink.
*/
struct mutex lock;
int refcnt;
};
#endif /* U_EEM_H */

View File

@ -63,6 +63,8 @@ struct eth_dev {
struct sk_buff_head rx_frames;
unsigned qmult;
unsigned header_len;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
@ -76,6 +78,7 @@ struct eth_dev {
bool zlp;
u8 host_mac[ETH_ALEN];
u8 dev_mac[ETH_ALEN];
};
/*-------------------------------------------------------------------------*/
@ -84,12 +87,8 @@ struct eth_dev {
#define DEFAULT_QLEN 2 /* double buffering by default */
static unsigned qmult = 5;
module_param(qmult, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
/* for dual-speed hardware, use deeper queues at high/super speed */
static inline int qlen(struct usb_gadget *gadget)
static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
{
if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
gadget->speed == USB_SPEED_SUPER))
@ -588,7 +587,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
if (gadget_is_dualspeed(dev->gadget))
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
dev->gadget->speed == USB_SPEED_SUPER)
? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0)
: 0;
retval = usb_ep_queue(in, req, GFP_ATOMIC);
@ -697,16 +696,6 @@ static int eth_stop(struct net_device *net)
/*-------------------------------------------------------------------------*/
/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
static char *dev_addr;
module_param(dev_addr, charp, S_IRUGO);
MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
/* this address is invisible to ifconfig */
static char *host_addr;
module_param(host_addr, charp, S_IRUGO);
MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
static int get_ether_addr(const char *str, u8 *dev_addr)
{
if (str) {
@ -728,6 +717,17 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
{
if (len < 18)
return -EINVAL;
snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
dev_addr[0], dev_addr[1], dev_addr[2],
dev_addr[3], dev_addr[4], dev_addr[5]);
return 18;
}
static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_stop,
@ -755,8 +755,9 @@ static struct device_type gadget_type = {
*
* Returns negative errno, or zero on success
*/
struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname)
struct eth_dev *gether_setup_name(struct usb_gadget *g,
const char *dev_addr, const char *host_addr,
u8 ethaddr[ETH_ALEN], unsigned qmult, const char *netname)
{
struct eth_dev *dev;
struct net_device *net;
@ -777,6 +778,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
/* network device setup */
dev->net = net;
dev->qmult = qmult;
snprintf(net->name, sizeof(net->name), "%s%%d", netname);
if (get_ether_addr(dev_addr, net->dev_addr))
@ -806,7 +808,8 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
/* two kinds of host-initiated state changes:
/*
* two kinds of host-initiated state changes:
* - iff DATA transfer is active, carrier is "on"
* - tx queueing enabled if open *and* carrier is "on"
*/
@ -815,6 +818,186 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
return dev;
}
EXPORT_SYMBOL(gether_setup_name);
struct net_device *gether_setup_name_default(const char *netname)
{
struct net_device *net;
struct eth_dev *dev;
net = alloc_etherdev(sizeof(*dev));
if (!net)
return ERR_PTR(-ENOMEM);
dev = netdev_priv(net);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
INIT_LIST_HEAD(&dev->tx_reqs);
INIT_LIST_HEAD(&dev->rx_reqs);
skb_queue_head_init(&dev->rx_frames);
/* network device setup */
dev->net = net;
dev->qmult = QMULT_DEFAULT;
snprintf(net->name, sizeof(net->name), "%s%%d", netname);
eth_random_addr(dev->dev_mac);
pr_warn("using random %s ethernet address\n", "self");
eth_random_addr(dev->host_mac);
pr_warn("using random %s ethernet address\n", "host");
net->netdev_ops = &eth_netdev_ops;
SET_ETHTOOL_OPS(net, &ops);
SET_NETDEV_DEVTYPE(net, &gadget_type);
return net;
}
EXPORT_SYMBOL(gether_setup_name_default);
int gether_register_netdev(struct net_device *net)
{
struct eth_dev *dev;
struct usb_gadget *g;
struct sockaddr sa;
int status;
if (!net->dev.parent)
return -EINVAL;
dev = netdev_priv(net);
g = dev->gadget;
status = register_netdev(net);
if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
return status;
} else {
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
/* two kinds of host-initiated state changes:
* - iff DATA transfer is active, carrier is "on"
* - tx queueing enabled if open *and* carrier is "on"
*/
netif_carrier_off(net);
}
sa.sa_family = net->type;
memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN);
rtnl_lock();
status = dev_set_mac_address(net, &sa);
rtnl_unlock();
if (status)
pr_warn("cannot set self ethernet address: %d\n", status);
else
INFO(dev, "MAC %pM\n", dev->dev_mac);
return status;
}
EXPORT_SYMBOL(gether_register_netdev);
void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
{
struct eth_dev *dev;
dev = netdev_priv(net);
dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
}
EXPORT_SYMBOL(gether_set_gadget);
int gether_set_dev_addr(struct net_device *net, const char *dev_addr)
{
struct eth_dev *dev;
u8 new_addr[ETH_ALEN];
dev = netdev_priv(net);
if (get_ether_addr(dev_addr, new_addr))
return -EINVAL;
memcpy(dev->dev_mac, new_addr, ETH_ALEN);
return 0;
}
EXPORT_SYMBOL(gether_set_dev_addr);
int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len)
{
struct eth_dev *dev;
dev = netdev_priv(net);
return get_ether_addr_str(dev->dev_mac, dev_addr, len);
}
EXPORT_SYMBOL(gether_get_dev_addr);
int gether_set_host_addr(struct net_device *net, const char *host_addr)
{
struct eth_dev *dev;
u8 new_addr[ETH_ALEN];
dev = netdev_priv(net);
if (get_ether_addr(host_addr, new_addr))
return -EINVAL;
memcpy(dev->host_mac, new_addr, ETH_ALEN);
return 0;
}
EXPORT_SYMBOL(gether_set_host_addr);
int gether_get_host_addr(struct net_device *net, char *host_addr, int len)
{
struct eth_dev *dev;
dev = netdev_priv(net);
return get_ether_addr_str(dev->host_mac, host_addr, len);
}
EXPORT_SYMBOL(gether_get_host_addr);
int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)
{
struct eth_dev *dev;
if (len < 13)
return -EINVAL;
dev = netdev_priv(net);
snprintf(host_addr, len, "%pm", dev->host_mac);
return strlen(host_addr);
}
EXPORT_SYMBOL(gether_get_host_addr_cdc);
void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN])
{
struct eth_dev *dev;
dev = netdev_priv(net);
memcpy(host_mac, dev->host_mac, ETH_ALEN);
}
EXPORT_SYMBOL(gether_get_host_addr_u8);
void gether_set_qmult(struct net_device *net, unsigned qmult)
{
struct eth_dev *dev;
dev = netdev_priv(net);
dev->qmult = qmult;
}
EXPORT_SYMBOL(gether_set_qmult);
unsigned gether_get_qmult(struct net_device *net)
{
struct eth_dev *dev;
dev = netdev_priv(net);
return dev->qmult;
}
EXPORT_SYMBOL(gether_get_qmult);
int gether_get_ifname(struct net_device *net, char *name, int len)
{
rtnl_lock();
strlcpy(name, netdev_name(net), len);
rtnl_unlock();
return strlen(name);
}
EXPORT_SYMBOL(gether_get_ifname);
/**
* gether_cleanup - remove Ethernet-over-USB device
@ -831,6 +1014,7 @@ void gether_cleanup(struct eth_dev *dev)
flush_work(&dev->work);
free_netdev(dev->net);
}
EXPORT_SYMBOL(gether_cleanup);
/**
* gether_connect - notify network layer that USB link is active
@ -873,11 +1057,12 @@ struct net_device *gether_connect(struct gether *link)
}
if (result == 0)
result = alloc_requests(dev, link, qlen(dev->gadget));
result = alloc_requests(dev, link, qlen(dev->gadget,
dev->qmult));
if (result == 0) {
dev->zlp = link->is_zlp_ok;
DBG(dev, "qlen %d\n", qlen(dev->gadget));
DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult));
dev->header_len = link->header_len;
dev->unwrap = link->unwrap;
@ -910,6 +1095,7 @@ fail0:
return ERR_PTR(result);
return dev->net;
}
EXPORT_SYMBOL(gether_connect);
/**
* gether_disconnect - notify network layer that USB link is inactive
@ -980,3 +1166,7 @@ void gether_disconnect(struct gether *link)
dev->port_usb = NULL;
spin_unlock(&dev->lock);
}
EXPORT_SYMBOL(gether_disconnect);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");

View File

@ -21,6 +21,26 @@
#include "gadget_chips.h"
#define QMULT_DEFAULT 5
/*
* dev_addr: initial value
* changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx"
* host_addr: this address is invisible to ifconfig
*/
#define USB_ETHERNET_MODULE_PARAMETERS() \
static unsigned qmult = QMULT_DEFAULT; \
module_param(qmult, uint, S_IRUGO|S_IWUSR); \
MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");\
\
static char *dev_addr; \
module_param(dev_addr, charp, S_IRUGO); \
MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); \
\
static char *host_addr; \
module_param(host_addr, charp, S_IRUGO); \
MODULE_PARM_DESC(host_addr, "Host Ethernet Address")
struct eth_dev;
/*
@ -71,8 +91,9 @@ struct gether {
|USB_CDC_PACKET_TYPE_DIRECTED)
/* variant of gether_setup that allows customizing network device name */
struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname);
struct eth_dev *gether_setup_name(struct usb_gadget *g,
const char *dev_addr, const char *host_addr,
u8 ethaddr[ETH_ALEN], unsigned qmult, const char *netname);
/* netdev setup/teardown as directed by the gadget driver */
/* gether_setup - initialize one ethernet-over-usb link
@ -88,11 +109,145 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
* Returns negative errno, or zero on success
*/
static inline struct eth_dev *gether_setup(struct usb_gadget *g,
u8 ethaddr[ETH_ALEN])
const char *dev_addr, const char *host_addr,
u8 ethaddr[ETH_ALEN], unsigned qmult)
{
return gether_setup_name(g, ethaddr, "usb");
return gether_setup_name(g, dev_addr, host_addr, ethaddr, qmult, "usb");
}
/*
* variant of gether_setup_default that allows customizing
* network device name
*/
struct net_device *gether_setup_name_default(const char *netname);
/*
* gether_register_netdev - register the net device
* @net: net device to register
*
* Registers the net device associated with this ethernet-over-usb link
*
*/
int gether_register_netdev(struct net_device *net);
/* gether_setup_default - initialize one ethernet-over-usb link
* Context: may sleep
*
* This sets up the single network link that may be exported by a
* gadget driver using this framework. The link layer addresses
* are set to random values.
*
* Returns negative errno, or zero on success
*/
static inline struct net_device *gether_setup_default(void)
{
return gether_setup_name_default("usb");
}
/**
* gether_set_gadget - initialize one ethernet-over-usb link with a gadget
* @net: device representing this link
* @g: the gadget to initialize with
*
* This associates one ethernet-over-usb link with a gadget.
*/
void gether_set_gadget(struct net_device *net, struct usb_gadget *g);
/**
* gether_set_dev_addr - initialize an ethernet-over-usb link with eth address
* @net: device representing this link
* @dev_addr: eth address of this device
*
* This sets the device-side Ethernet address of this ethernet-over-usb link
* if dev_addr is correct.
* Returns negative errno if the new address is incorrect.
*/
int gether_set_dev_addr(struct net_device *net, const char *dev_addr);
/**
* gether_get_dev_addr - get an ethernet-over-usb link eth address
* @net: device representing this link
* @dev_addr: place to store device's eth address
* @len: length of the @dev_addr buffer
*
* This gets the device-side Ethernet address of this ethernet-over-usb link.
* Returns zero on success, else negative errno.
*/
int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len);
/**
* gether_set_host_addr - initialize an ethernet-over-usb link with host address
* @net: device representing this link
* @host_addr: eth address of the host
*
* This sets the host-side Ethernet address of this ethernet-over-usb link
* if host_addr is correct.
* Returns negative errno if the new address is incorrect.
*/
int gether_set_host_addr(struct net_device *net, const char *host_addr);
/**
* gether_get_host_addr - get an ethernet-over-usb link host address
* @net: device representing this link
* @host_addr: place to store eth address of the host
* @len: length of the @host_addr buffer
*
* This gets the host-side Ethernet address of this ethernet-over-usb link.
* Returns zero on success, else negative errno.
*/
int gether_get_host_addr(struct net_device *net, char *host_addr, int len);
/**
* gether_get_host_addr_cdc - get an ethernet-over-usb link host address
* @net: device representing this link
* @host_addr: place to store eth address of the host
* @len: length of the @host_addr buffer
*
* This gets the CDC formatted host-side Ethernet address of this
* ethernet-over-usb link.
* Returns zero on success, else negative errno.
*/
int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len);
/**
* gether_get_host_addr_u8 - get an ethernet-over-usb link host address
* @net: device representing this link
* @host_mac: place to store the eth address of the host
*
* This gets the binary formatted host-side Ethernet address of this
* ethernet-over-usb link.
*/
void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]);
/**
* gether_set_qmult - initialize an ethernet-over-usb link with a multiplier
* @net: device representing this link
* @qmult: queue multiplier
*
* This sets the queue length multiplier of this ethernet-over-usb link.
* For higher speeds use longer queues.
*/
void gether_set_qmult(struct net_device *net, unsigned qmult);
/**
* gether_get_qmult - get an ethernet-over-usb link multiplier
* @net: device representing this link
*
* This gets the queue length multiplier of this ethernet-over-usb link.
*/
unsigned gether_get_qmult(struct net_device *net);
/**
* gether_get_ifname - get an ethernet-over-usb link interface name
* @net: device representing this link
* @name: place to store the interface name
* @len: length of the @name buffer
*
* This gets the interface name of this ethernet-over-usb link.
* Returns zero on success, else negative errno.
*/
int gether_get_ifname(struct net_device *net, char *name, int len);
void gether_cleanup(struct eth_dev *dev);
/* connect/disconnect is handled by individual functions */
@ -117,9 +272,6 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev);
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev);
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev);
int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
#ifdef USB_ETH_RNDIS

View File

@ -0,0 +1,164 @@
/*
* u_ether_configfs.h
*
* Utility definitions for configfs support in USB Ethernet functions
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __U_ETHER_CONFIGFS_H
#define __U_ETHER_CONFIGFS_H
#define USB_ETHERNET_CONFIGFS_ITEM(_f_) \
CONFIGFS_ATTR_STRUCT(f_##_f_##_opts); \
CONFIGFS_ATTR_OPS(f_##_f_##_opts); \
\
static void _f_##_attr_release(struct config_item *item) \
{ \
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
\
usb_put_function_instance(&opts->func_inst); \
} \
\
static struct configfs_item_operations _f_##_item_ops = { \
.release = _f_##_attr_release, \
.show_attribute = f_##_f_##_opts_attr_show, \
.store_attribute = f_##_f_##_opts_attr_store, \
}
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(_f_) \
static ssize_t _f_##_opts_dev_addr_show(struct f_##_f_##_opts *opts, \
char *page) \
{ \
int result; \
\
mutex_lock(&opts->lock); \
result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \
mutex_unlock(&opts->lock); \
\
return result; \
} \
\
static ssize_t _f_##_opts_dev_addr_store(struct f_##_f_##_opts *opts, \
const char *page, size_t len)\
{ \
int ret; \
\
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
mutex_unlock(&opts->lock); \
return -EBUSY; \
} \
\
ret = gether_set_dev_addr(opts->net, page); \
mutex_unlock(&opts->lock); \
if (!ret) \
ret = len; \
return ret; \
} \
\
static struct f_##_f_##_opts_attribute f_##_f_##_opts_dev_addr = \
__CONFIGFS_ATTR(dev_addr, S_IRUGO | S_IWUSR, \
_f_##_opts_dev_addr_show, \
_f_##_opts_dev_addr_store)
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(_f_) \
static ssize_t _f_##_opts_host_addr_show(struct f_##_f_##_opts *opts, \
char *page) \
{ \
int result; \
\
mutex_lock(&opts->lock); \
result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \
mutex_unlock(&opts->lock); \
\
return result; \
} \
\
static ssize_t _f_##_opts_host_addr_store(struct f_##_f_##_opts *opts, \
const char *page, size_t len)\
{ \
int ret; \
\
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
mutex_unlock(&opts->lock); \
return -EBUSY; \
} \
\
ret = gether_set_host_addr(opts->net, page); \
mutex_unlock(&opts->lock); \
if (!ret) \
ret = len; \
return ret; \
} \
\
static struct f_##_f_##_opts_attribute f_##_f_##_opts_host_addr = \
__CONFIGFS_ATTR(host_addr, S_IRUGO | S_IWUSR, \
_f_##_opts_host_addr_show, \
_f_##_opts_host_addr_store)
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(_f_) \
static ssize_t _f_##_opts_qmult_show(struct f_##_f_##_opts *opts, \
char *page) \
{ \
unsigned qmult; \
\
mutex_lock(&opts->lock); \
qmult = gether_get_qmult(opts->net); \
mutex_unlock(&opts->lock); \
return sprintf(page, "%d", qmult); \
} \
\
static ssize_t _f_##_opts_qmult_store(struct f_##_f_##_opts *opts, \
const char *page, size_t len)\
{ \
u8 val; \
int ret; \
\
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
ret = -EBUSY; \
goto out; \
} \
\
ret = kstrtou8(page, 0, &val); \
if (ret) \
goto out; \
\
gether_set_qmult(opts->net, val); \
ret = len; \
out: \
mutex_unlock(&opts->lock); \
return ret; \
} \
\
static struct f_##_f_##_opts_attribute f_##_f_##_opts_qmult = \
__CONFIGFS_ATTR(qmult, S_IRUGO | S_IWUSR, \
_f_##_opts_qmult_show, \
_f_##_opts_qmult_store)
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(_f_) \
static ssize_t _f_##_opts_ifname_show(struct f_##_f_##_opts *opts, \
char *page) \
{ \
int ret; \
\
mutex_lock(&opts->lock); \
ret = gether_get_ifname(opts->net, page, PAGE_SIZE); \
mutex_unlock(&opts->lock); \
\
return ret; \
} \
\
static struct f_##_f_##_opts_attribute f_##_f_##_opts_ifname = \
__CONFIGFS_ATTR_RO(ifname, _f_##_opts_ifname_show)
#endif /* __U_ETHER_CONFIGFS_H */

View File

@ -0,0 +1,36 @@
/*
* u_gether.h
*
* Utility definitions for the subset function
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef U_GETHER_H
#define U_GETHER_H
#include <linux/usb/composite.h>
struct f_gether_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This is to protect the data from concurrent access by read/write
* and create symlink/remove symlink.
*/
struct mutex lock;
int refcnt;
};
#endif /* U_GETHER_H */

View File

@ -0,0 +1,36 @@
/*
* u_ncm.h
*
* Utility definitions for the ncm function
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef U_NCM_H
#define U_NCM_H
#include <linux/usb/composite.h>
struct f_ncm_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This is to protect the data from concurrent access by read/write
* and create symlink/remove symlink.
*/
struct mutex lock;
int refcnt;
};
#endif /* U_NCM_H */

View File

@ -14,8 +14,16 @@
#include <linux/usb/composite.h>
#include <linux/usb/cdc.h>
int gphonet_setup(struct usb_gadget *gadget);
int phonet_bind_config(struct usb_configuration *c);
void gphonet_cleanup(void);
struct f_phonet_opts {
struct usb_function_instance func_inst;
bool bound;
struct net_device *net;
};
struct net_device *gphonet_setup_default(void);
void gphonet_set_gadget(struct net_device *net, struct usb_gadget *g);
int gphonet_register_netdev(struct net_device *net);
int phonet_bind_config(struct usb_configuration *c, struct net_device *dev);
void gphonet_cleanup(struct net_device *dev);
#endif /* __U_PHONET_H */

View File

@ -0,0 +1,41 @@
/*
* u_rndis.h
*
* Utility definitions for the subset function
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef U_RNDIS_H
#define U_RNDIS_H
#include <linux/usb/composite.h>
struct f_rndis_opts {
struct usb_function_instance func_inst;
u32 vendor_id;
const char *manufacturer;
struct net_device *net;
bool bound;
bool borrowed_net;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This is to protect the data from concurrent access by read/write
* and create symlink/remove symlink.
*/
struct mutex lock;
int refcnt;
};
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
#endif /* U_RNDIS_H */

View File

@ -103,10 +103,26 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&queue->irqlock, flags);
}
static void uvc_wait_prepare(struct vb2_queue *vq)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
mutex_unlock(&queue->mutex);
}
static void uvc_wait_finish(struct vb2_queue *vq)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
mutex_lock(&queue->mutex);
}
static struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.wait_prepare = uvc_wait_prepare,
.wait_finish = uvc_wait_finish,
};
static int uvc_queue_init(struct uvc_video_queue *queue,

View File

@ -17,7 +17,6 @@ config USB_C67X00_HCD
config USB_XHCI_HCD
tristate "xHCI HCD (USB 3.0) support"
depends on USB_ARCH_HAS_XHCI
---help---
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
"SuperSpeed" host controller hardware.
@ -43,7 +42,6 @@ endif # USB_XHCI_HCD
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
depends on USB_ARCH_HAS_EHCI
---help---
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
"high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
@ -200,7 +198,7 @@ config USB_EHCI_MSM
has an external PHY.
config USB_EHCI_TEGRA
boolean "NVIDIA Tegra HCD support"
tristate "NVIDIA Tegra HCD support"
depends on ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT
select USB_PHY
@ -345,9 +343,19 @@ config USB_ISP1362_HCD
To compile this driver as a module, choose M here: the
module will be called isp1362-hcd.
config USB_FUSBH200_HCD
tristate "FUSBH200 HCD support"
depends on USB
default N
---help---
Faraday FUSBH200 is designed to meet USB2.0 EHCI specification
with minor modification.
To compile this driver as a module, choose M here: the
module will be called fusbh200-hcd.
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB_ARCH_HAS_OHCI
tristate "OHCI HCD (USB 1.1) support"
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
depends on USB_ISP1301 || !ARCH_LPC32XX
---help---
@ -415,8 +423,8 @@ config USB_OHCI_HCD_PPC_OF
default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
config USB_OHCI_HCD_PCI
bool "OHCI support for PCI-bus USB controllers"
depends on PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
tristate "OHCI support for PCI-bus USB controllers"
depends on PCI
default y
select USB_OHCI_LITTLE_ENDIAN
---help---
@ -470,7 +478,7 @@ config USB_CNS3XXX_OHCI
It is needed for low-speed USB 1.0 device support.
config USB_OHCI_HCD_PLATFORM
bool "Generic OHCI driver for a platform device"
tristate "Generic OHCI driver for a platform device"
default n
---help---
Adds an OHCI host driver for a generic platform device, which

View File

@ -33,11 +33,16 @@ obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o
obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o
obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o
obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD_PCI) += ohci-pci.o
obj-$(CONFIG_USB_OHCI_HCD_PLATFORM) += ohci-platform.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o
@ -52,3 +57,4 @@ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o

View File

@ -37,15 +37,15 @@ static int clocked;
static void atmel_start_clock(void)
{
clk_enable(iclk);
clk_enable(fclk);
clk_prepare_enable(iclk);
clk_prepare_enable(fclk);
clocked = 1;
}
static void atmel_stop_clock(void)
{
clk_disable(fclk);
clk_disable(iclk);
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
clocked = 0;
}

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