mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 09:31:50 +00:00
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:
commit
a84270189e
81
Documentation/ABI/testing/configfs-usb-gadget
Normal file
81
Documentation/ABI/testing/configfs-usb-gadget
Normal 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
|
||||
|
8
Documentation/ABI/testing/configfs-usb-gadget-acm
Normal file
8
Documentation/ABI/testing/configfs-usb-gadget-acm
Normal 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".
|
16
Documentation/ABI/testing/configfs-usb-gadget-ecm
Normal file
16
Documentation/ABI/testing/configfs-usb-gadget-ecm
Normal 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
|
||||
|
||||
|
14
Documentation/ABI/testing/configfs-usb-gadget-eem
Normal file
14
Documentation/ABI/testing/configfs-usb-gadget-eem
Normal 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
|
15
Documentation/ABI/testing/configfs-usb-gadget-ncm
Normal file
15
Documentation/ABI/testing/configfs-usb-gadget-ncm
Normal 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
|
||||
|
9
Documentation/ABI/testing/configfs-usb-gadget-obex
Normal file
9
Documentation/ABI/testing/configfs-usb-gadget-obex
Normal 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".
|
||||
|
8
Documentation/ABI/testing/configfs-usb-gadget-phonet
Normal file
8
Documentation/ABI/testing/configfs-usb-gadget-phonet
Normal 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.
|
14
Documentation/ABI/testing/configfs-usb-gadget-rndis
Normal file
14
Documentation/ABI/testing/configfs-usb-gadget-rndis
Normal 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
|
9
Documentation/ABI/testing/configfs-usb-gadget-serial
Normal file
9
Documentation/ABI/testing/configfs-usb-gadget-serial
Normal 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".
|
||||
|
14
Documentation/ABI/testing/configfs-usb-gadget-subset
Normal file
14
Documentation/ABI/testing/configfs-usb-gadget-subset
Normal 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
|
@ -236,3 +236,30 @@ Description:
|
||||
This attribute is to expose these information to user space.
|
||||
The file will read "hotplug", "wired" and "not used" if the
|
||||
information is available, and "unknown" otherwise.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
|
||||
Date: May 2013
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
USB 2.0 devices may support hardware link power management (LPM)
|
||||
L1 sleep state. The usb2_lpm_l1_timeout attribute allows
|
||||
tuning the timeout for L1 inactivity timer (LPM timer), e.g.
|
||||
needed inactivity time before host requests the device to go to L1 sleep.
|
||||
Useful for power management tuning.
|
||||
Supported values are 0 - 65535 microseconds.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/usb2_lpm_besl
|
||||
Date: May 2013
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
USB 2.0 devices that support hardware link power management (LPM)
|
||||
L1 sleep state now use a best effort service latency value (BESL) to
|
||||
indicate the best effort to resumption of service to the device after the
|
||||
initiation of the resume event.
|
||||
If the device does not have a preferred besl value then the host can select
|
||||
one instead. This usb2_lpm_besl attribute allows to tune the host selected besl
|
||||
value in order to tune power saving and service latency.
|
||||
|
||||
Supported values are 0 - 15.
|
||||
More information on how besl values map to microseconds can be found in
|
||||
USB 2.0 ECN Errata for Link Power Management, section 4.10)
|
||||
|
@ -36,3 +36,22 @@ Description:
|
||||
|
||||
Refer to [ECMA-368] section 10.3.1.1 for the value to
|
||||
use.
|
||||
|
||||
What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_dnts
|
||||
Date: June 2013
|
||||
KernelVersion: 3.11
|
||||
Contact: Thomas Pugliese <thomas.pugliese@gmail.com>
|
||||
Description:
|
||||
The device notification time slot (DNTS) count and inverval in
|
||||
milliseconds that the WUSB host should use. This controls how
|
||||
often the devices will have the opportunity to send
|
||||
notifications to the host.
|
||||
|
||||
What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_retry_count
|
||||
Date: June 2013
|
||||
KernelVersion: 3.11
|
||||
Contact: Thomas Pugliese <thomas.pugliese@gmail.com>
|
||||
Description:
|
||||
The number of retries that the WUSB host should attempt
|
||||
before reporting an error for a bus transaction. The range of
|
||||
valid values is [0..15], where 0 indicates infinite retries.
|
||||
|
@ -5,6 +5,12 @@ Required properties:
|
||||
- reg: Should contain registers location and length
|
||||
- interrupts: Should contain controller interrupt
|
||||
|
||||
Recommended properies:
|
||||
- phy_type: the type of the phy connected to the core. Should be one
|
||||
of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
|
||||
property the PORTSC register won't be touched
|
||||
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
|
||||
|
||||
Optional properties:
|
||||
- fsl,usbphy: phandler of usb phy that connects to the only one port
|
||||
- fsl,usbmisc: phandler of non-core register device, with one argument
|
||||
|
@ -6,27 +6,10 @@ Practice : Universal Serial Bus" with the following modifications
|
||||
and additions :
|
||||
|
||||
Required properties :
|
||||
- compatible : Should be "nvidia,tegra20-ehci" for USB controllers
|
||||
used in host mode.
|
||||
- phy_type : Should be one of "ulpi" or "utmi".
|
||||
- nvidia,vbus-gpio : If present, specifies a gpio that needs to be
|
||||
activated for the bus to be powered.
|
||||
- nvidia,phy : phandle of the PHY instance, the controller is connected to.
|
||||
|
||||
Required properties for phy_type == ulpi:
|
||||
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
|
||||
- compatible : Should be "nvidia,tegra20-ehci".
|
||||
- nvidia,phy : phandle of the PHY that the controller is connected to.
|
||||
- clocks : Contains a single entry which defines the USB controller's clock.
|
||||
|
||||
Optional properties:
|
||||
- dr_mode : dual role mode. Indicates the working mode for
|
||||
nvidia,tegra20-ehci compatible controllers. Can be "host", "peripheral",
|
||||
or "otg". Default to "host" if not defined for backward compatibility.
|
||||
host means this is a host controller
|
||||
peripheral means it is device controller
|
||||
otg means it can operate as either ("on the go")
|
||||
- nvidia,has-legacy-mode : boolean indicates whether this controller can
|
||||
operate in legacy mode (as APX 2500 / 2600). In legacy mode some
|
||||
registers are accessed through the APB_MISC base address instead of
|
||||
the USB controller. Since this is a legacy issue it probably does not
|
||||
warrant a compatible string of its own.
|
||||
- nvidia,needs-double-reset : boolean is to be set for some of the Tegra2
|
||||
USB ports, which need reset twice due to hardware issues.
|
||||
- nvidia,needs-double-reset : boolean is to be set for some of the Tegra20
|
||||
USB ports, which need reset twice due to hardware issues.
|
||||
|
@ -4,14 +4,49 @@ The device node for Tegra SOC USB PHY:
|
||||
|
||||
Required properties :
|
||||
- compatible : Should be "nvidia,tegra20-usb-phy".
|
||||
- reg : Address and length of the register set for the USB PHY interface.
|
||||
- phy_type : Should be one of "ulpi" or "utmi".
|
||||
- reg : Defines the following set of registers, in the order listed:
|
||||
- The PHY's own register set.
|
||||
Always present.
|
||||
- The register set of the PHY containing the UTMI pad control registers.
|
||||
Present if-and-only-if phy_type == utmi.
|
||||
- phy_type : Should be one of "utmi", "ulpi" or "hsic".
|
||||
- clocks : Defines the clocks listed in the clock-names property.
|
||||
- clock-names : The following clock names must be present:
|
||||
- reg: The clock needed to access the PHY's own registers. This is the
|
||||
associated EHCI controller's clock. Always present.
|
||||
- pll_u: PLL_U. Always present.
|
||||
- timer: The timeout clock (clk_m). Present if phy_type == utmi.
|
||||
- utmi-pads: The clock needed to access the UTMI pad control registers.
|
||||
Present if phy_type == utmi.
|
||||
- ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2).
|
||||
Present if phy_type == ulpi, and ULPI link mode is in use.
|
||||
|
||||
Required properties for phy_type == ulpi:
|
||||
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
|
||||
|
||||
Required PHY timing params for utmi phy:
|
||||
- nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
|
||||
start of sync launches RxActive
|
||||
- nvidia,elastic-limit : Variable FIFO Depth of elastic input store
|
||||
- nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
|
||||
before declare IDLE.
|
||||
- nvidia,term-range-adj : Range adjusment on terminations
|
||||
- nvidia,xcvr-setup : HS driver output control
|
||||
- nvidia,xcvr-lsfslew : LS falling slew rate control.
|
||||
- nvidia,xcvr-lsrslew : LS rising slew rate control.
|
||||
|
||||
Optional properties:
|
||||
- nvidia,has-legacy-mode : boolean indicates whether this controller can
|
||||
operate in legacy mode (as APX 2500 / 2600). In legacy mode some
|
||||
registers are accessed through the APB_MISC base address instead of
|
||||
the USB controller.
|
||||
the USB controller.
|
||||
- nvidia,is-wired : boolean. Indicates whether we can do certain kind of power
|
||||
optimizations for the devices that are always connected. e.g. modem.
|
||||
- dr_mode : dual role mode. Indicates the working mode for the PHY. Can be
|
||||
"host", "peripheral", or "otg". Defaults to "host" if not defined.
|
||||
host means this is a host controller
|
||||
peripheral means it is device controller
|
||||
otg means it can operate as either ("on the go")
|
||||
|
||||
Required properties for dr_mode == otg:
|
||||
- vbus-supply: regulator for VBUS
|
||||
|
@ -4,6 +4,10 @@ Required properties:
|
||||
- compatible: Should be "smsc,usb3503".
|
||||
- reg: Specifies the i2c slave address, it should be 0x08.
|
||||
- connect-gpios: Should specify GPIO for connect.
|
||||
- disabled-ports: Should specify the ports unused.
|
||||
'1' or '2' or '3' are availe for this property to describe the port
|
||||
number. 1~3 property values are possible to be desribed.
|
||||
Do not describe this property if all ports have to be enabled.
|
||||
- intn-gpios: Should specify GPIO for interrupt.
|
||||
- reset-gpios: Should specify GPIO for reset.
|
||||
- initial-mode: Should specify initial mode.
|
||||
@ -14,6 +18,7 @@ Examples:
|
||||
compatible = "smsc,usb3503";
|
||||
reg = <0x08>;
|
||||
connect-gpios = <&gpx3 0 1>;
|
||||
disabled-ports = <2 3>;
|
||||
intn-gpios = <&gpx3 4 1>;
|
||||
reset-gpios = <&gpx3 5 1>;
|
||||
initial-mode = <1>;
|
||||
|
384
Documentation/usb/gadget_configfs.txt
Normal file
384
Documentation/usb/gadget_configfs.txt
Normal 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.
|
@ -449,7 +449,11 @@
|
||||
|
||||
usb@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb-phy@c5004000 {
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
sdhci@c8000600 {
|
||||
|
@ -428,17 +428,26 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb-phy@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5004400 {
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdhci@c8000200 {
|
||||
|
@ -38,13 +38,20 @@
|
||||
|
||||
usb@c5000000 {
|
||||
status = "okay";
|
||||
dr_mode = "otg";
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
@ -427,17 +427,26 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
|
||||
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
|
||||
};
|
||||
|
||||
usb-phy@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5004400 {
|
||||
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdhci@c8000000 {
|
||||
|
@ -569,17 +569,28 @@
|
||||
dr_mode = "otg";
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
vbus-supply = <&vbus_reg>;
|
||||
dr_mode = "otg";
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb-phy@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5004400 {
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdhci@c8000000 {
|
||||
@ -807,6 +818,15 @@
|
||||
gpio = <&pmic 1 0>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
vbus_reg: regulator@3 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <3>;
|
||||
regulator-name = "vdd_vbus_wup1";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&gpio 24 0>; /* PD0 */
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
|
@ -470,6 +470,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdhci@c8000600 {
|
||||
cd-gpios = <&gpio 58 1>; /* gpio PH2 */
|
||||
wp-gpios = <&gpio 59 0>; /* gpio PH3 */
|
||||
|
@ -314,17 +314,27 @@
|
||||
nvidia,vbus-gpio = <&gpio 170 0>; /* gpio PV2 */
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
vbus-supply = <&vbus_reg>;
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
|
||||
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
|
||||
};
|
||||
|
||||
usb-phy@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5004400 {
|
||||
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdhci@c8000000 {
|
||||
@ -390,6 +400,15 @@
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vbus_reg: regulator@2 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <2>;
|
||||
regulator-name = "usb1_vbus";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&gpio 170 0>; /* PV2 */
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
|
@ -505,17 +505,26 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb-phy@c5004000 {
|
||||
status = "okay";
|
||||
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb-phy@c5004400 {
|
||||
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdhci@c8000000 {
|
||||
|
@ -511,11 +511,21 @@
|
||||
nvidia,vbus-gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
vbus-supply = <&vbus1_reg>;
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
status = "okay";
|
||||
nvidia,vbus-gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
|
||||
};
|
||||
|
||||
usb-phy@c5008000 {
|
||||
status = "okay";
|
||||
vbus-supply = <&vbus3_reg>;
|
||||
};
|
||||
|
||||
sdhci@c8000400 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
@ -568,6 +578,24 @@
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vbus1_reg: regulator@2 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <2>;
|
||||
regulator-name = "vbus1";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
|
||||
};
|
||||
|
||||
vbus3_reg: regulator@3 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <3>;
|
||||
regulator-name = "vbus3";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
|
@ -455,13 +455,24 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
phy1: usb-phy@c5000400 {
|
||||
phy1: usb-phy@c5000000 {
|
||||
compatible = "nvidia,tegra20-usb-phy";
|
||||
reg = <0xc5000400 0x3c00>;
|
||||
reg = <0xc5000000 0x4000 0xc5000000 0x4000>;
|
||||
phy_type = "utmi";
|
||||
clocks = <&tegra_car 22>,
|
||||
<&tegra_car 127>,
|
||||
<&tegra_car 106>,
|
||||
<&tegra_car 22>;
|
||||
clock-names = "reg", "pll_u", "timer", "utmi-pads";
|
||||
nvidia,has-legacy-mode;
|
||||
clocks = <&tegra_car 22>, <&tegra_car 127>;
|
||||
clock-names = "phy", "pll_u";
|
||||
hssync_start_delay = <9>;
|
||||
idle_wait_delay = <17>;
|
||||
elastic_limit = <16>;
|
||||
term_range_adj = <6>;
|
||||
xcvr_setup = <9>;
|
||||
xcvr_lsfslew = <1>;
|
||||
xcvr_lsrslew = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
@ -474,12 +485,15 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
phy2: usb-phy@c5004400 {
|
||||
phy2: usb-phy@c5004000 {
|
||||
compatible = "nvidia,tegra20-usb-phy";
|
||||
reg = <0xc5004400 0x3c00>;
|
||||
reg = <0xc5004000 0x4000>;
|
||||
phy_type = "ulpi";
|
||||
clocks = <&tegra_car 93>, <&tegra_car 127>;
|
||||
clock-names = "phy", "pll_u";
|
||||
clocks = <&tegra_car 58>,
|
||||
<&tegra_car 127>,
|
||||
<&tegra_car 93>;
|
||||
clock-names = "reg", "pll_u", "ulpi-link";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
usb@c5008000 {
|
||||
@ -492,12 +506,23 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
phy3: usb-phy@c5008400 {
|
||||
phy3: usb-phy@c5008000 {
|
||||
compatible = "nvidia,tegra20-usb-phy";
|
||||
reg = <0xc5008400 0x3c00>;
|
||||
reg = <0xc5008000 0x4000 0xc5000000 0x4000>;
|
||||
phy_type = "utmi";
|
||||
clocks = <&tegra_car 22>, <&tegra_car 127>;
|
||||
clock-names = "phy", "pll_u";
|
||||
clocks = <&tegra_car 59>,
|
||||
<&tegra_car 127>,
|
||||
<&tegra_car 106>,
|
||||
<&tegra_car 22>;
|
||||
clock-names = "reg", "pll_u", "timer", "utmi-pads";
|
||||
hssync_start_delay = <9>;
|
||||
idle_wait_delay = <17>;
|
||||
elastic_limit = <16>;
|
||||
term_range_adj = <6>;
|
||||
xcvr_setup = <9>;
|
||||
xcvr_lsfslew = <2>;
|
||||
xcvr_lsrslew = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdhci@c8000000 {
|
||||
|
@ -873,7 +873,7 @@ static int qt_open(struct tty_struct *tty,
|
||||
result = qt_get_device(serial, &port0->DeviceData);
|
||||
|
||||
/* Port specific setups */
|
||||
result = qt_open_channel(serial, port->number, &ChannelData);
|
||||
result = qt_open_channel(serial, port->port_number, &ChannelData);
|
||||
if (result < 0) {
|
||||
dev_dbg(&port->dev, "qt_open_channel failed\n");
|
||||
return result;
|
||||
@ -888,7 +888,7 @@ static int qt_open(struct tty_struct *tty,
|
||||
(SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD);
|
||||
|
||||
/* Set Baud rate to default and turn off (default)flow control here */
|
||||
result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR);
|
||||
result = qt_setuart(serial, port->port_number, DEFAULT_DIVISOR, DEFAULT_LCR);
|
||||
if (result < 0) {
|
||||
dev_dbg(&port->dev, "qt_setuart failed\n");
|
||||
return result;
|
||||
@ -906,8 +906,7 @@ static int qt_open(struct tty_struct *tty,
|
||||
qt_submit_urb_from_open(serial, port);
|
||||
}
|
||||
|
||||
dev_dbg(&port->dev, "port number is %d\n", port->number);
|
||||
dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor);
|
||||
dev_dbg(&port->dev, "minor number is %d\n", port->minor);
|
||||
dev_dbg(&port->dev,
|
||||
"Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
|
||||
dev_dbg(&port->dev,
|
||||
@ -1003,7 +1002,7 @@ static void qt_close(struct usb_serial_port *port)
|
||||
status = 0;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
index = tty->index - serial->minor;
|
||||
index = port->port_number;
|
||||
|
||||
qt_port = qt_get_port_private(port);
|
||||
port0 = qt_get_port_private(serial->port[0]);
|
||||
@ -1022,14 +1021,11 @@ static void qt_close(struct usb_serial_port *port)
|
||||
/* Close uart channel */
|
||||
status = qt_close_channel(serial, index);
|
||||
if (status < 0)
|
||||
dev_dbg(&port->dev,
|
||||
"%s - port %d qt_close_channel failed.\n",
|
||||
__func__, port->number);
|
||||
dev_dbg(&port->dev, "%s - qt_close_channel failed.\n", __func__);
|
||||
|
||||
port0->open_ports--;
|
||||
|
||||
dev_dbg(&port->dev, "qt_num_open_ports in close%d:in port%d\n",
|
||||
port0->open_ports, port->number);
|
||||
dev_dbg(&port->dev, "qt_num_open_ports in close%d\n", port0->open_ports);
|
||||
|
||||
if (port0->open_ports == 0) {
|
||||
if (serial->port[0]->interrupt_in_urb) {
|
||||
@ -1133,12 +1129,11 @@ static int qt_ioctl(struct tty_struct *tty,
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct quatech_port *qt_port = qt_get_port_private(port);
|
||||
struct usb_serial *serial = get_usb_serial(port, __func__);
|
||||
unsigned int index;
|
||||
|
||||
dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
|
||||
|
||||
index = tty->index - serial->minor;
|
||||
index = port->port_number;
|
||||
|
||||
if (cmd == TIOCMIWAIT) {
|
||||
while (qt_port != NULL) {
|
||||
@ -1169,8 +1164,7 @@ static int qt_ioctl(struct tty_struct *tty,
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(&port->dev, "%s -No ioctl for that one. port = %d\n",
|
||||
__func__, port->number);
|
||||
dev_dbg(&port->dev, "%s -No ioctl for that one.\n", __func__);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
@ -1185,7 +1179,7 @@ static void qt_set_termios(struct tty_struct *tty,
|
||||
int baud, divisor, remainder;
|
||||
int status;
|
||||
|
||||
index = tty->index - port->serial->minor;
|
||||
index = port->port_number;
|
||||
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
@ -1245,8 +1239,7 @@ static void qt_set_termios(struct tty_struct *tty,
|
||||
|
||||
/* Now determine flow control */
|
||||
if (cflag & CRTSCTS) {
|
||||
dev_dbg(&port->dev, "%s - Enabling HW flow control port %d\n",
|
||||
__func__, port->number);
|
||||
dev_dbg(&port->dev, "%s - Enabling HW flow control\n", __func__);
|
||||
|
||||
/* Enable RTS/CTS flow control */
|
||||
status = BoxSetHW_FlowCtrl(port->serial, index, 1);
|
||||
@ -1258,8 +1251,7 @@ static void qt_set_termios(struct tty_struct *tty,
|
||||
} else {
|
||||
/* Disable RTS/CTS flow control */
|
||||
dev_dbg(&port->dev,
|
||||
"%s - disabling HW flow control port %d\n",
|
||||
__func__, port->number);
|
||||
"%s - disabling HW flow control\n", __func__);
|
||||
|
||||
status = BoxSetHW_FlowCtrl(port->serial, index, 0);
|
||||
if (status < 0) {
|
||||
@ -1303,7 +1295,7 @@ static void qt_break(struct tty_struct *tty, int break_state)
|
||||
u16 index, onoff;
|
||||
unsigned int result;
|
||||
|
||||
index = tty->index - serial->minor;
|
||||
index = port->port_number;
|
||||
|
||||
qt_port = qt_get_port_private(port);
|
||||
|
||||
@ -1332,7 +1324,7 @@ static inline int qt_real_tiocmget(struct tty_struct *tty,
|
||||
int status;
|
||||
unsigned int index;
|
||||
|
||||
index = tty->index - serial->minor;
|
||||
index = port->port_number;
|
||||
status =
|
||||
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
|
||||
if (status >= 0) {
|
||||
@ -1371,7 +1363,7 @@ static inline int qt_real_tiocmset(struct tty_struct *tty,
|
||||
int status;
|
||||
unsigned int index;
|
||||
|
||||
index = tty->index - serial->minor;
|
||||
index = port->port_number;
|
||||
status =
|
||||
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
|
||||
if (status < 0)
|
||||
|
@ -2,59 +2,15 @@
|
||||
# USB device configuration
|
||||
#
|
||||
|
||||
# many non-PCI SOC chips embed OHCI
|
||||
# These are unused now, remove them once they are no longer selected
|
||||
config USB_ARCH_HAS_OHCI
|
||||
boolean
|
||||
# ARM:
|
||||
default y if SA1111
|
||||
default y if ARCH_OMAP
|
||||
default y if ARCH_S3C24XX
|
||||
default y if PXA27x
|
||||
default y if PXA3xx
|
||||
default y if ARCH_EP93XX
|
||||
default y if ARCH_AT91
|
||||
default y if MFD_TC6393XB
|
||||
default y if ARCH_W90X900
|
||||
default y if ARCH_DAVINCI_DA8XX
|
||||
default y if ARCH_CNS3XXX
|
||||
default y if PLAT_SPEAR
|
||||
default y if ARCH_EXYNOS
|
||||
# PPC:
|
||||
default y if STB03xxx
|
||||
default y if PPC_MPC52xx
|
||||
# MIPS:
|
||||
default y if MIPS_ALCHEMY
|
||||
default y if MACH_JZ4740
|
||||
# more:
|
||||
default PCI
|
||||
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
|
||||
|
@ -25,6 +25,7 @@ obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1760_HCD) += host/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
|
||||
obj-$(CONFIG_USB_FUSBH200_HCD) += host/
|
||||
|
||||
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
|
||||
|
||||
|
@ -12,15 +12,15 @@ if USB_CHIPIDEA
|
||||
|
||||
config USB_CHIPIDEA_UDC
|
||||
bool "ChipIdea device controller"
|
||||
depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA
|
||||
depends on USB_GADGET=y || USB_CHIPIDEA=m
|
||||
help
|
||||
Say Y here to enable device controller functionality of the
|
||||
ChipIdea driver.
|
||||
|
||||
config USB_CHIPIDEA_HOST
|
||||
bool "ChipIdea host controller"
|
||||
depends on USB=y || USB=USB_CHIPIDEA
|
||||
depends on USB_EHCI_HCD=y
|
||||
depends on USB=y
|
||||
depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
help
|
||||
Say Y here to enable host controller functionality of the
|
||||
|
@ -9,13 +9,13 @@ ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
|
||||
|
||||
# Glue/Bridge layers go here
|
||||
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
|
||||
|
||||
# PCI doesn't provide stubs, need to check
|
||||
ifneq ($(CONFIG_PCI),)
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_pci.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_OF_DEVICE),)
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_imx.o usbmisc_imx.o
|
||||
endif
|
||||
|
@ -48,10 +48,24 @@
|
||||
#define PORTSC_SUSP BIT(7)
|
||||
#define PORTSC_HSP BIT(9)
|
||||
#define PORTSC_PTC (0x0FUL << 16)
|
||||
/* PTS and PTW for non lpm version only */
|
||||
#define PORTSC_PTS(d) \
|
||||
((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
|
||||
#define PORTSC_PTW BIT(28)
|
||||
#define PORTSC_STS BIT(29)
|
||||
|
||||
/* DEVLC */
|
||||
#define DEVLC_PSPD (0x03UL << 25)
|
||||
#define DEVLC_PSPD_HS (0x02UL << 25)
|
||||
#define DEVLC_PSPD_HS (0x02UL << 25)
|
||||
#define DEVLC_PTW BIT(27)
|
||||
#define DEVLC_STS BIT(28)
|
||||
#define DEVLC_PTS(d) (((d) & 0x7) << 29)
|
||||
|
||||
/* Encoding for DEVLC_PTS and PORTSC_PTS */
|
||||
#define PTS_UTMI 0
|
||||
#define PTS_ULPI 2
|
||||
#define PTS_SERIAL 3
|
||||
#define PTS_HSIC 4
|
||||
|
||||
/* OTGSC */
|
||||
#define OTGSC_IDPU BIT(5)
|
||||
|
@ -22,14 +22,14 @@
|
||||
* DEFINE
|
||||
*****************************************************************************/
|
||||
#define TD_PAGE_COUNT 5
|
||||
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
|
||||
#define CI_HDRC_PAGE_SIZE 4096ul /* page size for TD's */
|
||||
#define ENDPT_MAX 32
|
||||
|
||||
/******************************************************************************
|
||||
* STRUCTURES
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* struct ci13xxx_ep - endpoint representation
|
||||
* struct ci_hw_ep - endpoint representation
|
||||
* @ep: endpoint structure for gadget drivers
|
||||
* @dir: endpoint direction (TX/RX)
|
||||
* @num: endpoint number
|
||||
@ -41,7 +41,7 @@
|
||||
* @lock: pointer to controller's spinlock
|
||||
* @td_pool: pointer to controller's TD pool
|
||||
*/
|
||||
struct ci13xxx_ep {
|
||||
struct ci_hw_ep {
|
||||
struct usb_ep ep;
|
||||
u8 dir;
|
||||
u8 num;
|
||||
@ -49,15 +49,16 @@ struct ci13xxx_ep {
|
||||
char name[16];
|
||||
struct {
|
||||
struct list_head queue;
|
||||
struct ci13xxx_qh *ptr;
|
||||
struct ci_hw_qh *ptr;
|
||||
dma_addr_t dma;
|
||||
} qh;
|
||||
int wedge;
|
||||
|
||||
/* global resources */
|
||||
struct ci13xxx *ci;
|
||||
struct ci_hdrc *ci;
|
||||
spinlock_t *lock;
|
||||
struct dma_pool *td_pool;
|
||||
struct td_node *pending_td;
|
||||
};
|
||||
|
||||
enum ci_role {
|
||||
@ -74,9 +75,9 @@ enum ci_role {
|
||||
* name: role name string (host/gadget)
|
||||
*/
|
||||
struct ci_role_driver {
|
||||
int (*start)(struct ci13xxx *);
|
||||
void (*stop)(struct ci13xxx *);
|
||||
irqreturn_t (*irq)(struct ci13xxx *);
|
||||
int (*start)(struct ci_hdrc *);
|
||||
void (*stop)(struct ci_hdrc *);
|
||||
irqreturn_t (*irq)(struct ci_hdrc *);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
@ -101,7 +102,7 @@ struct hw_bank {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ci13xxx - chipidea device representation
|
||||
* struct ci_hdrc - chipidea device representation
|
||||
* @dev: pointer to parent device
|
||||
* @lock: access synchronization
|
||||
* @hw_bank: hardware register mapping
|
||||
@ -116,7 +117,7 @@ struct hw_bank {
|
||||
* @gadget: device side representation for peripheral controller
|
||||
* @driver: gadget driver
|
||||
* @hw_ep_max: total number of endpoints supported by hardware
|
||||
* @ci13xxx_ep: array of endpoints
|
||||
* @ci_hw_ep: array of endpoints
|
||||
* @ep0_dir: ep0 direction
|
||||
* @ep0out: pointer to ep0 OUT endpoint
|
||||
* @ep0in: pointer to ep0 IN endpoint
|
||||
@ -132,7 +133,7 @@ struct hw_bank {
|
||||
* @hcd: pointer to usb_hcd for ehci host driver
|
||||
* @debugfs: root dentry for this controller in debugfs
|
||||
*/
|
||||
struct ci13xxx {
|
||||
struct ci_hdrc {
|
||||
struct device *dev;
|
||||
spinlock_t lock;
|
||||
struct hw_bank hw_bank;
|
||||
@ -149,9 +150,9 @@ struct ci13xxx {
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
unsigned hw_ep_max;
|
||||
struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX];
|
||||
struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
|
||||
u32 ep0_dir;
|
||||
struct ci13xxx_ep *ep0out, *ep0in;
|
||||
struct ci_hw_ep *ep0out, *ep0in;
|
||||
|
||||
struct usb_request *status;
|
||||
bool setaddr;
|
||||
@ -160,7 +161,7 @@ struct ci13xxx {
|
||||
u8 suspended;
|
||||
u8 test_mode;
|
||||
|
||||
struct ci13xxx_platform_data *platdata;
|
||||
struct ci_hdrc_platform_data *platdata;
|
||||
int vbus_active;
|
||||
/* FIXME: some day, we'll not use global phy */
|
||||
bool global_phy;
|
||||
@ -169,13 +170,13 @@ struct ci13xxx {
|
||||
struct dentry *debugfs;
|
||||
};
|
||||
|
||||
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
|
||||
static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
|
||||
{
|
||||
BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
|
||||
return ci->roles[ci->role];
|
||||
}
|
||||
|
||||
static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
|
||||
static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -191,7 +192,7 @@ static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void ci_role_stop(struct ci13xxx *ci)
|
||||
static inline void ci_role_stop(struct ci_hdrc *ci)
|
||||
{
|
||||
enum ci_role role = ci->role;
|
||||
|
||||
@ -210,7 +211,7 @@ static inline void ci_role_stop(struct ci13xxx *ci)
|
||||
#define REG_BITS (32)
|
||||
|
||||
/* register indices */
|
||||
enum ci13xxx_regs {
|
||||
enum ci_hw_regs {
|
||||
CAP_CAPLENGTH,
|
||||
CAP_HCCPARAMS,
|
||||
CAP_DCCPARAMS,
|
||||
@ -242,7 +243,7 @@ enum ci13xxx_regs {
|
||||
*
|
||||
* This function returns register contents
|
||||
*/
|
||||
static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
|
||||
static inline u32 hw_read(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask)
|
||||
{
|
||||
return ioread32(ci->hw_bank.regmap[reg]) & mask;
|
||||
}
|
||||
@ -253,7 +254,7 @@ static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
|
||||
* @mask: bitfield mask
|
||||
* @data: new value
|
||||
*/
|
||||
static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
static inline void hw_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
|
||||
u32 mask, u32 data)
|
||||
{
|
||||
if (~mask)
|
||||
@ -270,7 +271,7 @@ static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
*
|
||||
* This function returns register contents
|
||||
*/
|
||||
static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
static inline u32 hw_test_and_clear(struct ci_hdrc *ci, enum ci_hw_regs reg,
|
||||
u32 mask)
|
||||
{
|
||||
u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask;
|
||||
@ -287,7 +288,7 @@ static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
*
|
||||
* This function returns register contents
|
||||
*/
|
||||
static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
|
||||
u32 mask, u32 data)
|
||||
{
|
||||
u32 val = hw_read(ci, reg, ~0);
|
||||
@ -296,10 +297,10 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
return (val & mask) >> __ffs(mask);
|
||||
}
|
||||
|
||||
int hw_device_reset(struct ci13xxx *ci, u32 mode);
|
||||
int hw_device_reset(struct ci_hdrc *ci, u32 mode);
|
||||
|
||||
int hw_port_test_set(struct ci13xxx *ci, u8 mode);
|
||||
int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
|
||||
|
||||
u8 hw_port_test_get(struct ci13xxx *ci);
|
||||
u8 hw_port_test_get(struct ci_hdrc *ci);
|
||||
|
||||
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
|
||||
|
@ -20,16 +20,14 @@
|
||||
#include <linux/usb/chipidea.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include "ci.h"
|
||||
#include "ci13xxx_imx.h"
|
||||
#include "ci_hdrc_imx.h"
|
||||
|
||||
#define pdev_to_phy(pdev) \
|
||||
((struct usb_phy *)platform_get_drvdata(pdev))
|
||||
|
||||
struct ci13xxx_imx_data {
|
||||
struct device_node *phy_np;
|
||||
struct ci_hdrc_imx_data {
|
||||
struct usb_phy *phy;
|
||||
struct platform_device *ci_pdev;
|
||||
struct clk *clk;
|
||||
@ -88,22 +86,17 @@ EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
|
||||
|
||||
/* End of common functions shared by usbmisc drivers*/
|
||||
|
||||
static struct ci13xxx_platform_data ci13xxx_imx_platdata = {
|
||||
.name = "ci13xxx_imx",
|
||||
.flags = CI13XXX_REQUIRE_TRANSCEIVER |
|
||||
CI13XXX_PULLUP_ON_VBUS |
|
||||
CI13XXX_DISABLE_STREAMING,
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
};
|
||||
|
||||
static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx_imx_data *data;
|
||||
struct platform_device *plat_ci, *phy_pdev;
|
||||
struct device_node *phy_np;
|
||||
struct ci_hdrc_imx_data *data;
|
||||
struct ci_hdrc_platform_data pdata = {
|
||||
.name = "ci_hdrc_imx",
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
.flags = CI_HDRC_REQUIRE_TRANSCEIVER |
|
||||
CI_HDRC_PULLUP_ON_VBUS |
|
||||
CI_HDRC_DISABLE_STREAMING,
|
||||
};
|
||||
struct resource *res;
|
||||
struct regulator *reg_vbus;
|
||||
struct pinctrl *pinctrl;
|
||||
int ret;
|
||||
|
||||
if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
|
||||
@ -112,7 +105,7 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
|
||||
dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -122,11 +115,6 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl))
|
||||
dev_warn(&pdev->dev, "pinctrl get/select failed, err=%ld\n",
|
||||
PTR_ERR(pinctrl));
|
||||
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
@ -141,37 +129,33 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0);
|
||||
if (phy_np) {
|
||||
data->phy_np = phy_np;
|
||||
phy_pdev = of_find_device_by_node(phy_np);
|
||||
if (phy_pdev) {
|
||||
struct usb_phy *phy;
|
||||
phy = pdev_to_phy(phy_pdev);
|
||||
if (phy &&
|
||||
try_module_get(phy_pdev->dev.driver->owner)) {
|
||||
usb_phy_init(phy);
|
||||
data->phy = phy;
|
||||
}
|
||||
data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
|
||||
if (!IS_ERR(data->phy)) {
|
||||
ret = usb_phy_init(data->phy);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to init phy: %d\n", ret);
|
||||
goto err_clk;
|
||||
}
|
||||
} else if (PTR_ERR(data->phy) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* we only support host now, so enable vbus here */
|
||||
reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
|
||||
if (!IS_ERR(reg_vbus)) {
|
||||
ret = regulator_enable(reg_vbus);
|
||||
data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
|
||||
if (!IS_ERR(data->reg_vbus)) {
|
||||
ret = regulator_enable(data->reg_vbus);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to enable vbus regulator, err=%d\n",
|
||||
ret);
|
||||
goto put_np;
|
||||
goto err_clk;
|
||||
}
|
||||
data->reg_vbus = reg_vbus;
|
||||
} else {
|
||||
reg_vbus = NULL;
|
||||
data->reg_vbus = NULL;
|
||||
}
|
||||
|
||||
ci13xxx_imx_platdata.phy = data->phy;
|
||||
pdata.phy = data->phy;
|
||||
|
||||
if (!pdev->dev.dma_mask)
|
||||
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
|
||||
@ -187,11 +171,11 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
plat_ci = ci13xxx_add_device(&pdev->dev,
|
||||
data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
|
||||
pdev->resource, pdev->num_resources,
|
||||
&ci13xxx_imx_platdata);
|
||||
if (IS_ERR(plat_ci)) {
|
||||
ret = PTR_ERR(plat_ci);
|
||||
&pdata);
|
||||
if (IS_ERR(data->ci_pdev)) {
|
||||
ret = PTR_ERR(data->ci_pdev);
|
||||
dev_err(&pdev->dev,
|
||||
"Can't register ci_hdrc platform device, err=%d\n",
|
||||
ret);
|
||||
@ -203,11 +187,10 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"usbmisc post failed, ret=%d\n", ret);
|
||||
goto put_np;
|
||||
goto disable_device;
|
||||
}
|
||||
}
|
||||
|
||||
data->ci_pdev = plat_ci;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_no_callbacks(&pdev->dev);
|
||||
@ -215,22 +198,22 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
disable_device:
|
||||
ci_hdrc_remove_device(data->ci_pdev);
|
||||
err:
|
||||
if (reg_vbus)
|
||||
regulator_disable(reg_vbus);
|
||||
put_np:
|
||||
if (phy_np)
|
||||
of_node_put(phy_np);
|
||||
if (data->reg_vbus)
|
||||
regulator_disable(data->reg_vbus);
|
||||
err_clk:
|
||||
clk_disable_unprepare(data->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ci13xxx_imx_remove(struct platform_device *pdev)
|
||||
static int ci_hdrc_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx_imx_data *data = platform_get_drvdata(pdev);
|
||||
struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
ci13xxx_remove_device(data->ci_pdev);
|
||||
ci_hdrc_remove_device(data->ci_pdev);
|
||||
|
||||
if (data->reg_vbus)
|
||||
regulator_disable(data->reg_vbus);
|
||||
@ -240,35 +223,31 @@ static int ci13xxx_imx_remove(struct platform_device *pdev)
|
||||
module_put(data->phy->dev->driver->owner);
|
||||
}
|
||||
|
||||
of_node_put(data->phy_np);
|
||||
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ci13xxx_imx_dt_ids[] = {
|
||||
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx27-usb", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids);
|
||||
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
|
||||
|
||||
static struct platform_driver ci13xxx_imx_driver = {
|
||||
.probe = ci13xxx_imx_probe,
|
||||
.remove = ci13xxx_imx_remove,
|
||||
static struct platform_driver ci_hdrc_imx_driver = {
|
||||
.probe = ci_hdrc_imx_probe,
|
||||
.remove = ci_hdrc_imx_remove,
|
||||
.driver = {
|
||||
.name = "imx_usb",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ci13xxx_imx_dt_ids,
|
||||
.of_match_table = ci_hdrc_imx_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ci13xxx_imx_driver);
|
||||
module_platform_driver(ci_hdrc_imx_driver);
|
||||
|
||||
MODULE_ALIAS("platform:imx-usb");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("CI13xxx i.MX USB binding");
|
||||
MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
|
||||
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
|
||||
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
|
@ -17,19 +17,19 @@
|
||||
|
||||
#define MSM_USB_BASE (ci->hw_bank.abs)
|
||||
|
||||
static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
|
||||
static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
|
||||
{
|
||||
struct device *dev = ci->gadget.dev.parent;
|
||||
int val;
|
||||
|
||||
switch (event) {
|
||||
case CI13XXX_CONTROLLER_RESET_EVENT:
|
||||
dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
|
||||
case CI_HDRC_CONTROLLER_RESET_EVENT:
|
||||
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
|
||||
writel(0, USB_AHBBURST);
|
||||
writel(0, USB_AHBMODE);
|
||||
break;
|
||||
case CI13XXX_CONTROLLER_STOPPED_EVENT:
|
||||
dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
|
||||
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
|
||||
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
|
||||
/*
|
||||
* Put the transceiver in non-driving mode. Otherwise host
|
||||
* may not detect soft-disconnection.
|
||||
@ -40,32 +40,32 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
|
||||
usb_phy_io_write(ci->transceiver, val, ULPI_FUNC_CTRL);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "unknown ci13xxx event\n");
|
||||
dev_dbg(dev, "unknown ci_hdrc event\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
|
||||
.name = "ci13xxx_msm",
|
||||
.flags = CI13XXX_REGS_SHARED |
|
||||
CI13XXX_REQUIRE_TRANSCEIVER |
|
||||
CI13XXX_PULLUP_ON_VBUS |
|
||||
CI13XXX_DISABLE_STREAMING,
|
||||
static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
|
||||
.name = "ci_hdrc_msm",
|
||||
.flags = CI_HDRC_REGS_SHARED |
|
||||
CI_HDRC_REQUIRE_TRANSCEIVER |
|
||||
CI_HDRC_PULLUP_ON_VBUS |
|
||||
CI_HDRC_DISABLE_STREAMING,
|
||||
|
||||
.notify_event = ci13xxx_msm_notify_event,
|
||||
.notify_event = ci_hdrc_msm_notify_event,
|
||||
};
|
||||
|
||||
static int ci13xxx_msm_probe(struct platform_device *pdev)
|
||||
static int ci_hdrc_msm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci;
|
||||
|
||||
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
|
||||
dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n");
|
||||
|
||||
plat_ci = ci13xxx_add_device(&pdev->dev,
|
||||
plat_ci = ci_hdrc_add_device(&pdev->dev,
|
||||
pdev->resource, pdev->num_resources,
|
||||
&ci13xxx_msm_platdata);
|
||||
&ci_hdrc_msm_platdata);
|
||||
if (IS_ERR(plat_ci)) {
|
||||
dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
|
||||
dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
|
||||
return PTR_ERR(plat_ci);
|
||||
}
|
||||
|
||||
@ -77,23 +77,24 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci13xxx_msm_remove(struct platform_device *pdev)
|
||||
static int ci_hdrc_msm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
ci13xxx_remove_device(plat_ci);
|
||||
ci_hdrc_remove_device(plat_ci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ci13xxx_msm_driver = {
|
||||
.probe = ci13xxx_msm_probe,
|
||||
.remove = ci13xxx_msm_remove,
|
||||
static struct platform_driver ci_hdrc_msm_driver = {
|
||||
.probe = ci_hdrc_msm_probe,
|
||||
.remove = ci_hdrc_msm_remove,
|
||||
.driver = { .name = "msm_hsusb", },
|
||||
};
|
||||
|
||||
module_platform_driver(ci13xxx_msm_driver);
|
||||
module_platform_driver(ci_hdrc_msm_driver);
|
||||
|
||||
MODULE_ALIAS("platform:msm_hsusb");
|
||||
MODULE_ALIAS("platform:ci13xxx_msm");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -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");
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -14,15 +14,15 @@
|
||||
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
|
||||
|
||||
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
|
||||
int dbg_create_files(struct ci13xxx *ci);
|
||||
void dbg_remove_files(struct ci13xxx *ci);
|
||||
int dbg_create_files(struct ci_hdrc *ci);
|
||||
void dbg_remove_files(struct ci_hdrc *ci);
|
||||
#else
|
||||
static inline int dbg_create_files(struct ci13xxx *ci)
|
||||
static inline int dbg_create_files(struct ci_hdrc *ci)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dbg_remove_files(struct ci13xxx *ci)
|
||||
static inline void dbg_remove_files(struct ci_hdrc *ci)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -33,12 +33,12 @@
|
||||
|
||||
static struct hc_driver __read_mostly ci_ehci_hc_driver;
|
||||
|
||||
static irqreturn_t host_irq(struct ci13xxx *ci)
|
||||
static irqreturn_t host_irq(struct ci_hdrc *ci)
|
||||
{
|
||||
return usb_hcd_irq(ci->irq, ci->hcd);
|
||||
}
|
||||
|
||||
static int host_start(struct ci13xxx *ci)
|
||||
static int host_start(struct ci_hdrc *ci)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
@ -70,13 +70,13 @@ static int host_start(struct ci13xxx *ci)
|
||||
else
|
||||
ci->hcd = hcd;
|
||||
|
||||
if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
|
||||
if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void host_stop(struct ci13xxx *ci)
|
||||
static void host_stop(struct ci_hdrc *ci)
|
||||
{
|
||||
struct usb_hcd *hcd = ci->hcd;
|
||||
|
||||
@ -84,7 +84,7 @@ static void host_stop(struct ci13xxx *ci)
|
||||
usb_put_hcd(hcd);
|
||||
}
|
||||
|
||||
int ci_hdrc_host_init(struct ci13xxx *ci)
|
||||
int ci_hdrc_host_init(struct ci_hdrc *ci)
|
||||
{
|
||||
struct ci_role_driver *rdrv;
|
||||
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
#ifdef CONFIG_USB_CHIPIDEA_HOST
|
||||
|
||||
int ci_hdrc_host_init(struct ci13xxx *ci);
|
||||
int ci_hdrc_host_init(struct ci_hdrc *ci);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ci_hdrc_host_init(struct ci13xxx *ci)
|
||||
static inline int ci_hdrc_host_init(struct ci_hdrc *ci)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,7 @@
|
||||
#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
|
||||
|
||||
/* DMA layout of transfer descriptors */
|
||||
struct ci13xxx_td {
|
||||
struct ci_hw_td {
|
||||
/* 0 */
|
||||
u32 next;
|
||||
#define TD_TERMINATE BIT(0)
|
||||
@ -43,24 +43,31 @@ struct ci13xxx_td {
|
||||
} __attribute__ ((packed, aligned(4)));
|
||||
|
||||
/* DMA layout of queue heads */
|
||||
struct ci13xxx_qh {
|
||||
struct ci_hw_qh {
|
||||
/* 0 */
|
||||
u32 cap;
|
||||
#define QH_IOS BIT(15)
|
||||
#define QH_MAX_PKT (0x07FFUL << 16)
|
||||
#define QH_ZLT BIT(29)
|
||||
#define QH_MULT (0x0003UL << 30)
|
||||
#define QH_ISO_MULT(x) ((x >> 11) & 0x03)
|
||||
/* 1 */
|
||||
u32 curr;
|
||||
/* 2 - 8 */
|
||||
struct ci13xxx_td td;
|
||||
struct ci_hw_td td;
|
||||
/* 9 */
|
||||
u32 RESERVED;
|
||||
struct usb_ctrlrequest setup;
|
||||
} __attribute__ ((packed, aligned(4)));
|
||||
|
||||
struct td_node {
|
||||
struct list_head td;
|
||||
dma_addr_t dma;
|
||||
struct ci_hw_td *ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ci13xxx_req - usb request representation
|
||||
* struct ci_hw_req - usb request representation
|
||||
* @req: request structure for gadget drivers
|
||||
* @queue: link to QH list
|
||||
* @ptr: transfer descriptor for this request
|
||||
@ -68,22 +75,19 @@ struct ci13xxx_qh {
|
||||
* @zptr: transfer descriptor for the zero packet
|
||||
* @zdma: dma address of the zero packet's transfer descriptor
|
||||
*/
|
||||
struct ci13xxx_req {
|
||||
struct ci_hw_req {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
struct ci13xxx_td *ptr;
|
||||
dma_addr_t dma;
|
||||
struct ci13xxx_td *zptr;
|
||||
dma_addr_t zdma;
|
||||
struct list_head tds;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_CHIPIDEA_UDC
|
||||
|
||||
int ci_hdrc_gadget_init(struct ci13xxx *ci);
|
||||
int ci_hdrc_gadget_init(struct ci_hdrc *ci);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
|
||||
static inline int ci_hdrc_gadget_init(struct ci_hdrc *ci)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "ci13xxx_imx.h"
|
||||
#include "ci_hdrc_imx.h"
|
||||
|
||||
#define USB_DEV_MAX 4
|
||||
|
||||
@ -175,6 +175,7 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
|
||||
|
||||
static int usbmisc_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -243,17 +244,7 @@ static struct platform_driver usbmisc_imx_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
int usbmisc_imx_drv_init(void)
|
||||
{
|
||||
return platform_driver_register(&usbmisc_imx_driver);
|
||||
}
|
||||
subsys_initcall(usbmisc_imx_drv_init);
|
||||
|
||||
void usbmisc_imx_drv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&usbmisc_imx_driver);
|
||||
}
|
||||
module_exit(usbmisc_imx_drv_exit);
|
||||
module_platform_driver(usbmisc_imx_driver);
|
||||
|
||||
MODULE_ALIAS("platform:usbmisc-imx");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -216,38 +216,6 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int acm_write_start(struct acm *acm, int wbn)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct acm_wb *wb = &acm->wb[wbn];
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
if (!acm->dev) {
|
||||
wb->use = 0;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
|
||||
acm->susp_count);
|
||||
usb_autopm_get_interface_async(acm->control);
|
||||
if (acm->susp_count) {
|
||||
if (!acm->delayed_wb)
|
||||
acm->delayed_wb = wb;
|
||||
else
|
||||
usb_autopm_put_interface_async(acm->control);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return 0; /* A white lie */
|
||||
}
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
rc = acm_start_wb(acm, wb);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
/*
|
||||
* attributes exported through sysfs
|
||||
*/
|
||||
@ -653,13 +621,31 @@ static int acm_tty_write(struct tty_struct *tty,
|
||||
}
|
||||
wb = &acm->wb[wbn];
|
||||
|
||||
if (!acm->dev) {
|
||||
wb->use = 0;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
count = (count > acm->writesize) ? acm->writesize : count;
|
||||
dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
|
||||
memcpy(wb->buf, buf, count);
|
||||
wb->len = count;
|
||||
|
||||
usb_autopm_get_interface_async(acm->control);
|
||||
if (acm->susp_count) {
|
||||
if (!acm->delayed_wb)
|
||||
acm->delayed_wb = wb;
|
||||
else
|
||||
usb_autopm_put_interface_async(acm->control);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return count; /* A white lie */
|
||||
}
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
stat = acm_start_wb(acm, wb);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
||||
stat = acm_write_start(acm, wbn);
|
||||
if (stat < 0)
|
||||
return stat;
|
||||
return count;
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include <linux/usb/tmc.h>
|
||||
|
||||
|
||||
#define RIGOL 1
|
||||
#define USBTMC_HEADER_SIZE 12
|
||||
#define USBTMC_MINOR_BASE 176
|
||||
|
||||
/*
|
||||
@ -84,6 +86,8 @@ struct usbtmc_device_data {
|
||||
u8 bTag_last_write; /* needed for abort */
|
||||
u8 bTag_last_read; /* needed for abort */
|
||||
|
||||
u8 rigol_quirk;
|
||||
|
||||
/* attributes from the USB TMC spec for this device */
|
||||
u8 TermChar;
|
||||
bool TermCharEnabled;
|
||||
@ -97,6 +101,16 @@ struct usbtmc_device_data {
|
||||
};
|
||||
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
|
||||
|
||||
struct usbtmc_ID_rigol_quirk {
|
||||
__u16 idVendor;
|
||||
__u16 idProduct;
|
||||
};
|
||||
|
||||
static const struct usbtmc_ID_rigol_quirk usbtmc_id_quirk[] = {
|
||||
{ 0x1ab1, 0x0588 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
static struct usb_driver usbtmc_driver;
|
||||
|
||||
@ -361,6 +375,59 @@ 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;
|
||||
|
@ -49,14 +49,14 @@
|
||||
#include <linux/security.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#define USB_MAXBUS 64
|
||||
#define USB_DEVICE_MAX USB_MAXBUS * 128
|
||||
#define USB_DEVICE_MAX (USB_MAXBUS * 128)
|
||||
#define USB_SG_SIZE 16384 /* split-size for large txs */
|
||||
|
||||
/* Mutual exclusion for removal, open, and release */
|
||||
@ -1804,7 +1804,8 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
|
||||
|
||||
/* alloc buffer */
|
||||
if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
|
||||
if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
|
||||
if (copy_from_user(buf, ctl->data, size)) {
|
||||
|
@ -94,7 +94,7 @@ static int init_usb_class(void)
|
||||
kref_init(&usb_class->kref);
|
||||
usb_class->class = class_create(THIS_MODULE, "usbmisc");
|
||||
if (IS_ERR(usb_class->class)) {
|
||||
result = IS_ERR(usb_class->class);
|
||||
result = PTR_ERR(usb_class->class);
|
||||
printk(KERN_ERR "class_create failed for usb devices\n");
|
||||
kfree(usb_class);
|
||||
usb_class = NULL;
|
||||
|
@ -149,6 +149,27 @@ static const u8 usb3_rh_dev_descriptor[18] = {
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* usb 2.5 (wireless USB 1.0) root hub device descriptor */
|
||||
static const u8 usb25_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
0x50, 0x02, /* __le16 bcdUSB; v2.5 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 bDeviceSubClass; */
|
||||
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
|
||||
0xFF, /* __u8 bMaxPacketSize0; always 0xFF (WUSB Spec 7.4.1). */
|
||||
|
||||
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
|
||||
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
|
||||
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
|
||||
|
||||
0x03, /* __u8 iManufacturer; */
|
||||
0x02, /* __u8 iProduct; */
|
||||
0x01, /* __u8 iSerialNumber; */
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* usb 2.0 root hub device descriptor */
|
||||
static const u8 usb2_rh_dev_descriptor [18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
@ -527,6 +548,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
case HCD_USB3:
|
||||
bufp = usb3_rh_dev_descriptor;
|
||||
break;
|
||||
case HCD_USB25:
|
||||
bufp = usb25_rh_dev_descriptor;
|
||||
break;
|
||||
case HCD_USB2:
|
||||
bufp = usb2_rh_dev_descriptor;
|
||||
break;
|
||||
@ -546,6 +570,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
bufp = ss_rh_config_descriptor;
|
||||
len = sizeof ss_rh_config_descriptor;
|
||||
break;
|
||||
case HCD_USB25:
|
||||
case HCD_USB2:
|
||||
bufp = hs_rh_config_descriptor;
|
||||
len = sizeof hs_rh_config_descriptor;
|
||||
@ -2511,6 +2536,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
case HCD_USB2:
|
||||
rhdev->speed = USB_SPEED_HIGH;
|
||||
break;
|
||||
case HCD_USB25:
|
||||
rhdev->speed = USB_SPEED_WIRELESS;
|
||||
break;
|
||||
case HCD_USB3:
|
||||
rhdev->speed = USB_SPEED_SUPER;
|
||||
break;
|
||||
|
@ -718,18 +718,18 @@ static void hub_tt_work(struct work_struct *work)
|
||||
|
||||
/**
|
||||
* usb_hub_set_port_power - control hub port's power state
|
||||
* @hdev: target hub
|
||||
* @hdev: USB device belonging to the usb hub
|
||||
* @hub: target hub
|
||||
* @port1: port index
|
||||
* @set: expected status
|
||||
*
|
||||
* call this function to control port's power via setting or
|
||||
* clearing the port's PORT_POWER feature.
|
||||
*/
|
||||
int usb_hub_set_port_power(struct usb_device *hdev, int port1,
|
||||
bool set)
|
||||
int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
|
||||
int port1, bool set)
|
||||
{
|
||||
int ret;
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
|
||||
if (set)
|
||||
@ -1769,15 +1769,17 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
|
||||
static int find_port_owner(struct usb_device *hdev, unsigned port1,
|
||||
struct dev_state ***ppowner)
|
||||
{
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
|
||||
if (hdev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
if (port1 == 0 || port1 > hdev->maxchild)
|
||||
return -EINVAL;
|
||||
|
||||
/* This assumes that devices not managed by the hub driver
|
||||
/* Devices not managed by the hub driver
|
||||
* will always have maxchild equal to 0.
|
||||
*/
|
||||
*ppowner = &(usb_hub_to_struct_hub(hdev)->ports[port1 - 1]->port_owner);
|
||||
*ppowner = &(hub->ports[port1 - 1]->port_owner);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5323,7 +5325,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
|
||||
{
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
|
||||
hub->ports[port1 - 1]->connect_type = type;
|
||||
if (hub)
|
||||
hub->ports[port1 - 1]->connect_type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5339,6 +5342,9 @@ usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
|
||||
{
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
|
||||
if (!hub)
|
||||
return USB_PORT_CONNECT_TYPE_UNKNOWN;
|
||||
|
||||
return hub->ports[port1 - 1]->connect_type;
|
||||
}
|
||||
|
||||
@ -5397,6 +5403,9 @@ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
|
||||
{
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
|
||||
if (!hub)
|
||||
return NULL;
|
||||
|
||||
return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
|
||||
}
|
||||
#endif
|
||||
|
@ -100,7 +100,7 @@ extern int usb_hub_create_port_device(struct usb_hub *hub,
|
||||
int port1);
|
||||
extern void usb_hub_remove_port_device(struct usb_hub *hub,
|
||||
int port1);
|
||||
extern int usb_hub_set_port_power(struct usb_device *hdev,
|
||||
extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
|
||||
int port1, bool set);
|
||||
extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
|
||||
extern int hub_port_debounce(struct usb_hub *hub, int port1,
|
||||
|
@ -252,7 +252,7 @@ static void sg_clean(struct usb_sg_request *io)
|
||||
{
|
||||
if (io->urbs) {
|
||||
while (io->entries--)
|
||||
usb_free_urb(io->urbs [io->entries]);
|
||||
usb_free_urb(io->urbs[io->entries]);
|
||||
kfree(io->urbs);
|
||||
io->urbs = NULL;
|
||||
}
|
||||
@ -300,10 +300,10 @@ static void sg_complete(struct urb *urb)
|
||||
*/
|
||||
spin_unlock(&io->lock);
|
||||
for (i = 0, found = 0; i < io->entries; i++) {
|
||||
if (!io->urbs [i] || !io->urbs [i]->dev)
|
||||
if (!io->urbs[i] || !io->urbs[i]->dev)
|
||||
continue;
|
||||
if (found) {
|
||||
retval = usb_unlink_urb(io->urbs [i]);
|
||||
retval = usb_unlink_urb(io->urbs[i]);
|
||||
if (retval != -EINPROGRESS &&
|
||||
retval != -ENODEV &&
|
||||
retval != -EBUSY &&
|
||||
@ -311,7 +311,7 @@ static void sg_complete(struct urb *urb)
|
||||
dev_err(&io->dev->dev,
|
||||
"%s, unlink --> %d\n",
|
||||
__func__, retval);
|
||||
} else if (urb == io->urbs [i])
|
||||
} else if (urb == io->urbs[i])
|
||||
found = 1;
|
||||
}
|
||||
spin_lock(&io->lock);
|
||||
@ -379,7 +379,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
}
|
||||
|
||||
/* initialize all the urbs we'll use */
|
||||
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
|
||||
io->urbs = kmalloc(io->entries * sizeof(*io->urbs), mem_flags);
|
||||
if (!io->urbs)
|
||||
goto nomem;
|
||||
|
||||
@ -511,7 +511,7 @@ void usb_sg_wait(struct usb_sg_request *io)
|
||||
int retval;
|
||||
|
||||
io->urbs[i]->dev = io->dev;
|
||||
retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC);
|
||||
retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
|
||||
|
||||
/* after we submit, let completions or cancelations fire;
|
||||
* we handshake using io->status.
|
||||
@ -586,9 +586,9 @@ void usb_sg_cancel(struct usb_sg_request *io)
|
||||
for (i = 0; i < io->entries; i++) {
|
||||
int retval;
|
||||
|
||||
if (!io->urbs [i]->dev)
|
||||
if (!io->urbs[i]->dev)
|
||||
continue;
|
||||
retval = usb_unlink_urb(io->urbs [i]);
|
||||
retval = usb_unlink_urb(io->urbs[i]);
|
||||
if (retval != -EINPROGRESS
|
||||
&& retval != -ENODEV
|
||||
&& retval != -EBUSY
|
||||
|
@ -86,7 +86,7 @@ static int usb_port_runtime_resume(struct device *dev)
|
||||
usb_autopm_get_interface(intf);
|
||||
set_bit(port1, hub->busy_bits);
|
||||
|
||||
retval = usb_hub_set_port_power(hdev, port1, true);
|
||||
retval = usb_hub_set_port_power(hdev, hub, port1, true);
|
||||
if (port_dev->child && !retval) {
|
||||
/*
|
||||
* Wait for usb hub port to be reconnected in order to make
|
||||
@ -128,7 +128,7 @@ static int usb_port_runtime_suspend(struct device *dev)
|
||||
|
||||
usb_autopm_get_interface(intf);
|
||||
set_bit(port1, hub->busy_bits);
|
||||
retval = usb_hub_set_port_power(hdev, port1, false);
|
||||
retval = usb_hub_set_port_power(hdev, hub, port1, false);
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
|
||||
clear_bit(port1, hub->busy_bits);
|
||||
|
@ -497,8 +497,62 @@ set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
|
||||
static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
|
||||
set_usb2_hardware_lpm);
|
||||
|
||||
static ssize_t
|
||||
show_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->l1_params.timeout);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
set_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
u16 timeout;
|
||||
|
||||
if (kstrtou16(buf, 0, &timeout))
|
||||
return -EINVAL;
|
||||
|
||||
udev->l1_params.timeout = timeout;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(usb2_lpm_l1_timeout, S_IRUGO | S_IWUSR,
|
||||
show_usb2_lpm_l1_timeout, set_usb2_lpm_l1_timeout);
|
||||
|
||||
static ssize_t
|
||||
show_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->l1_params.besl);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
set_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
u8 besl;
|
||||
|
||||
if (kstrtou8(buf, 0, &besl) || besl > 15)
|
||||
return -EINVAL;
|
||||
|
||||
udev->l1_params.besl = besl;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(usb2_lpm_besl, S_IRUGO | S_IWUSR,
|
||||
show_usb2_lpm_besl, set_usb2_lpm_besl);
|
||||
|
||||
static struct attribute *usb2_hardware_lpm_attr[] = {
|
||||
&dev_attr_usb2_hardware_lpm.attr,
|
||||
&dev_attr_usb2_lpm_l1_timeout.attr,
|
||||
&dev_attr_usb2_lpm_besl.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group usb2_hardware_lpm_attr_group = {
|
||||
|
@ -209,6 +209,39 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_find_interface);
|
||||
|
||||
struct each_dev_arg {
|
||||
void *data;
|
||||
int (*fn)(struct usb_device *, void *);
|
||||
};
|
||||
|
||||
static int __each_dev(struct device *dev, void *data)
|
||||
{
|
||||
struct each_dev_arg *arg = (struct each_dev_arg *)data;
|
||||
|
||||
/* There are struct usb_interface on the same bus, filter them out */
|
||||
if (!is_usb_device(dev))
|
||||
return 0;
|
||||
|
||||
return arg->fn(container_of(dev, struct usb_device, dev), arg->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_for_each_dev - iterate over all USB devices in the system
|
||||
* @data: data pointer that will be handed to the callback function
|
||||
* @fn: callback function to be called for each USB device
|
||||
*
|
||||
* Iterate over all USB devices and call @fn for each, passing it @data. If it
|
||||
* returns anything other than 0, we break the iteration prematurely and return
|
||||
* that value.
|
||||
*/
|
||||
int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *))
|
||||
{
|
||||
struct each_dev_arg arg = {data, fn};
|
||||
|
||||
return bus_for_each_dev(&usb_bus_type, NULL, &arg, __each_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_for_each_dev);
|
||||
|
||||
/**
|
||||
* usb_release_dev - free a usb device structure when all users of it are finished.
|
||||
* @dev: device that's been disconnected
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -33,6 +33,7 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
||||
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
|
||||
mv_udc-y := mv_udc_core.o
|
||||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
|
||||
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
|
||||
|
||||
# USB Functions
|
||||
@ -45,6 +46,21 @@ usb_f_serial-y := f_serial.o
|
||||
obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
|
||||
usb_f_obex-y := f_obex.o
|
||||
obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
|
||||
obj-$(CONFIG_USB_U_ETHER) += u_ether.o
|
||||
u_rndis-y := rndis.o
|
||||
obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o
|
||||
usb_f_ncm-y := f_ncm.o
|
||||
obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o
|
||||
usb_f_ecm-y := f_ecm.o
|
||||
obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o
|
||||
usb_f_phonet-y := f_phonet.o
|
||||
obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o
|
||||
usb_f_eem-y := f_eem.o
|
||||
obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o
|
||||
usb_f_ecm_subset-y := f_subset.o
|
||||
obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o
|
||||
usb_f_rndis-y := f_rndis.o
|
||||
obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "u_ether.h"
|
||||
#include "u_serial.h"
|
||||
#include "u_ecm.h"
|
||||
|
||||
|
||||
#define DRIVER_DESC "CDC Composite Gadget"
|
||||
@ -32,18 +33,9 @@
|
||||
#define CDC_VENDOR_NUM 0x0525 /* NetChip */
|
||||
#define CDC_PRODUCT_NUM 0xa4aa /* CDC Composite: ECM + ACM */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
USB_GADGET_COMPOSITE_OPTIONS();
|
||||
|
||||
/*
|
||||
* Kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
#include "f_ecm.c"
|
||||
#include "u_ether.c"
|
||||
USB_ETHERNET_MODULE_PARAMETERS();
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -102,12 +94,13 @@ static struct usb_gadget_strings *dev_strings[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
static struct eth_dev *the_dev;
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static struct usb_function *f_acm;
|
||||
static struct usb_function_instance *fi_serial;
|
||||
|
||||
static struct usb_function *f_ecm;
|
||||
static struct usb_function_instance *fi_ecm;
|
||||
|
||||
/*
|
||||
* We _always_ have both CDC ECM and CDC ACM functions.
|
||||
*/
|
||||
@ -120,13 +113,27 @@ static int __init cdc_do_config(struct usb_configuration *c)
|
||||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
status = ecm_bind_config(c, hostaddr, the_dev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
fi_ecm = usb_get_function_instance("ecm");
|
||||
if (IS_ERR(fi_ecm)) {
|
||||
status = PTR_ERR(fi_ecm);
|
||||
goto err_func_ecm;
|
||||
}
|
||||
|
||||
f_ecm = usb_get_function(fi_ecm);
|
||||
if (IS_ERR(f_ecm)) {
|
||||
status = PTR_ERR(f_ecm);
|
||||
goto err_get_ecm;
|
||||
}
|
||||
|
||||
status = usb_add_function(c, f_ecm);
|
||||
if (status)
|
||||
goto err_add_ecm;
|
||||
|
||||
fi_serial = usb_get_function_instance("acm");
|
||||
if (IS_ERR(fi_serial))
|
||||
return PTR_ERR(fi_serial);
|
||||
if (IS_ERR(fi_serial)) {
|
||||
status = PTR_ERR(fi_serial);
|
||||
goto err_get_acm;
|
||||
}
|
||||
|
||||
f_acm = usb_get_function(fi_serial);
|
||||
if (IS_ERR(f_acm)) {
|
||||
@ -136,12 +143,21 @@ static int __init cdc_do_config(struct usb_configuration *c)
|
||||
|
||||
status = usb_add_function(c, f_acm);
|
||||
if (status)
|
||||
goto err_conf;
|
||||
goto err_add_acm;
|
||||
|
||||
return 0;
|
||||
err_conf:
|
||||
|
||||
err_add_acm:
|
||||
usb_put_function(f_acm);
|
||||
err_func_acm:
|
||||
usb_put_function_instance(fi_serial);
|
||||
err_get_acm:
|
||||
usb_remove_function(c, f_ecm);
|
||||
err_add_ecm:
|
||||
usb_put_function(f_ecm);
|
||||
err_get_ecm:
|
||||
usb_put_function_instance(fi_ecm);
|
||||
err_func_ecm:
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -157,6 +173,7 @@ static struct usb_configuration cdc_config_driver = {
|
||||
static int __init cdc_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct f_ecm_opts *ecm_opts;
|
||||
int status;
|
||||
|
||||
if (!can_support_ecm(cdev->gadget)) {
|
||||
@ -165,10 +182,23 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set up network link layer */
|
||||
the_dev = gether_setup(cdev->gadget, hostaddr);
|
||||
if (IS_ERR(the_dev))
|
||||
return PTR_ERR(the_dev);
|
||||
fi_ecm = usb_get_function_instance("ecm");
|
||||
if (IS_ERR(fi_ecm))
|
||||
return PTR_ERR(fi_ecm);
|
||||
|
||||
ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
|
||||
|
||||
gether_set_qmult(ecm_opts->net, qmult);
|
||||
if (!gether_set_host_addr(ecm_opts->net, host_addr))
|
||||
pr_info("using host ethernet address: %s", host_addr);
|
||||
if (!gether_set_dev_addr(ecm_opts->net, dev_addr))
|
||||
pr_info("using self ethernet address: %s", dev_addr);
|
||||
|
||||
fi_serial = usb_get_function_instance("acm");
|
||||
if (IS_ERR(fi_serial)) {
|
||||
status = PTR_ERR(fi_serial);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
@ -192,7 +222,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
||||
return 0;
|
||||
|
||||
fail1:
|
||||
gether_cleanup(the_dev);
|
||||
usb_put_function_instance(fi_serial);
|
||||
fail:
|
||||
usb_put_function_instance(fi_ecm);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -200,7 +232,10 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
usb_put_function(f_acm);
|
||||
usb_put_function_instance(fi_serial);
|
||||
gether_cleanup(the_dev);
|
||||
if (!IS_ERR_OR_NULL(f_ecm))
|
||||
usb_put_function(f_ecm);
|
||||
if (!IS_ERR_OR_NULL(fi_ecm))
|
||||
usb_put_function_instance(fi_ecm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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, ð_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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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[] = {
|
||||
|
1219
drivers/usb/gadget/fotg210-udc.c
Normal file
1219
drivers/usb/gadget/fotg210-udc.c
Normal file
File diff suppressed because it is too large
Load Diff
253
drivers/usb/gadget/fotg210.h
Normal file
253
drivers/usb/gadget/fotg210.h
Normal 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)
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
36
drivers/usb/gadget/u_ecm.h
Normal file
36
drivers/usb/gadget/u_ecm.h
Normal 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 */
|
36
drivers/usb/gadget/u_eem.h
Normal file
36
drivers/usb/gadget/u_eem.h
Normal 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 */
|
@ -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 = ð_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");
|
||||
|
@ -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
|
||||
|
||||
|
164
drivers/usb/gadget/u_ether_configfs.h
Normal file
164
drivers/usb/gadget/u_ether_configfs.h
Normal 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 */
|
36
drivers/usb/gadget/u_gether.h
Normal file
36
drivers/usb/gadget/u_gether.h
Normal 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 */
|
36
drivers/usb/gadget/u_ncm.h
Normal file
36
drivers/usb/gadget/u_ncm.h
Normal 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 */
|
@ -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 */
|
||||
|
41
drivers/usb/gadget/u_rndis.h
Normal file
41
drivers/usb/gadget/u_rndis.h
Normal 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 */
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user